/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <stdio.h>
#include <stddef.h>
#include <syslog.h>
#include <strings.h>
#include <unistd.h>
#include <libintl.h>
#include <stdlib.h>
#include <ctype.h>
#include <picl.h>
#include <picltree.h>
#include <picld_pluginutil.h>
#include <fcntl.h>
#include <dirent.h>
#include <pthread.h>
#include <libdevinfo.h>
#include <limits.h>
#include <sys/systeminfo.h>
#include <i2c_gpio.h>
#include "libdevice.h"
#include "picldefs.h"
#include <sys/raidioctl.h>
/*
* Plugin registration entry points
*/
static void piclfrudr_register(void);
static void piclfrudr_init(void);
static void piclfrudr_fini(void);
static void rmc_state_event(void);
static void seattle_setleds(void);
static void boston_set_frontleds(const char *, int);
static void boston_set_rearleds(const char *, int);
#pragma init(piclfrudr_register)
"SUNW_MPXU_frudr",
};
/*
* Log message texts
*/
/*
* PICL property values
*/
/*
* Local defines
*/
#define SEATTLE1U_HDDBP_PATH \
#define SEATTLE2U_HDDBP_PATH \
#define BOSTON_HDDBP_PATH \
"/disk-backplane-8/%s"
/*
* PSU defines
*/
#define PSU_DEV \
/*
*/
#define SEATTLE_PSU_DEV \
#define BOSTON_PSU_DEV \
/*
* Seattle fan-tray paths
*/
#define SEATTLE_FCB0_1U \
"/FCB0/fan-connector-board/%s"
#define SEATTLE_FCB1_1U \
"/FCB1/fan-connector-board/%s"
#define SEATTLE_PDB_1U \
#define SEATTLE_FCB0_2U \
"/FCB0/fan-connector-board/%s"
#define SEATTLE_FCB1_2U \
"/FCB1/fan-connector-board/%s"
#define SEATTLE_PDB_2U \
"/HDDFB/fan-connector-board/%s"
/*
* disk defines
*/
/* For V440 RAID policy */
/*
*/
#define SEATTLE_DISK_DEVCTL \
#define BOSTON_DISK_DEVCTL_1068X \
#define BOSTON_DISK_DEVCTL_1068E \
/*
* led defines
*/
/*
*/
/*
*/
typedef struct id_props {
} id_props_t;
typedef struct idp_lkup {
} idp_lkup_t;
/*
* table for mapping RMC handles to volatile property handles
*/
/*
* path names to system-controller device and fault led gpio
*/
/*
* disk data
*/
"HDD4", "HDD5", "HDD6", "HDD7" };
/*
* Boston platform-specific flag which tells us if we are using
* a LSI 1068X disk controller (0) or a LSI 1068E (1).
*/
static int boston_1068e_flag = 0;
/*
* static strings
*/
/*
* OperationalStatus property values
*/
/*
* forward reference
*/
static void opst_init(void);
static void disk_leds_init(void);
static void disk_leds_fini(void);
static void *disk_leds_thread(void *args);
static char *create_bezel_leds_pathname(const char *dirpath,
const char *devname);
char *tbl_name);
static int create_i2c_node(char *ap_id);
static void delete_i2c_node(char *ap_id);
static int ps_name_to_addr(char *name);
static char *ps_name_to_unitaddr(char *name);
static char *ps_apid_to_nodename(char *apid);
/*
* Because this plugin is shared across different platforms, we need to
* distinguish for certain functionality
*/
#define PLAT_ENXS 0
static int sys_platform;
static void
{
else
}
/*
* This function is executed as part of .init when the plugin is
* dlopen()ed
*/
static void
piclfrudr_register(void)
{
(void) picld_plugin_register(&my_reg_info);
}
/*
* This function is the init entry point of the plugin.
* It initializes the /frutree tree
*/
static void
piclfrudr_init(void)
{
get_platform();
if (sc_device_name != NULL) {
}
NULL))
opst_init();
/*
* There is a window of opportunity for the RMC to deliver an event
* indicating a newly operable state just before we are listening for
* it. In this case, envmon will have missed setting up /platform
* and won't get a signal from frudr. So send it a PICL_FRU_ADDED just
* in case.
*/
if ((sys_platform == PLAT_CHALUPA) ||
(sys_platform == PLAT_CHALUPA19)) {
} else {
}
return;
return;
}
static void
{
return;
}
if (child_name == NULL)
return;
/*
* create fru node of supplied name
*/
return;
}
}
/*
* function to add a volatile property to a specified node
*/
static void
{
int err;
if (err == PICL_SUCCESS) {
&proph) == PICL_SUCCESS) {
}
}
err);
return;
}
}
/*
* Deliver volatile property value.
* prtpicl gets very upset if we fail this command, so if the property
* cannot be retrieved, return a status of unknown.
*/
static int
{
int index;
int envmon_fd;
int err;
if (index < 0) {
/*
* We drop memory of PSU op status handles in opst_init()
* when we get an RMC faulty event. We cannot access the
* status info in this circumstance, so returning "unknown"
* is appropriate.
*/
return (PICL_SUCCESS);
}
if (envmon_fd < 0) {
/*
* To get this far we must have succeeded with an earlier
* open, so this is an unlikely failure. It would be more
* helpful to indicate the nature of the failure, but we
* don't have the space to say much. Just return "unknown".
*/
return (PICL_SUCCESS);
}
if (err < 0) {
/*
* If we can't read the stats, "unknown" is a reasonable
* status to return. This one really shouldn't happen.
*/
return (PICL_SUCCESS);
}
return (PICL_SUCCESS);
}
return (PICL_SUCCESS);
}
return (PICL_SUCCESS);
}
/*
* Function for explicitly turning on system leds
*/
static void
{
if (fd < 0)
return;
}
}
/*
* Function for explicitly turning on system leds
*/
static void
seattle_setleds(void)
{
int fd;
if (fd < 0)
return;
}
/*
* Function for explicitly turning on the front system leds
*/
static void
{
if (fd < 0) {
return;
}
/* first clear the polarity */
return;
}
/* now clear the direction */
return;
}
/* and light the leds */
}
/*
* Function for explicitly turning on the rear system leds
*/
static void
{
if (fd < 0) {
return;
}
/* first clear the polarity */
return;
}
/* now set the direction */
return;
}
/* and light the leds */
}
static void
rmc_state_event(void)
{
int res;
if (fd < 0)
return;
/*
* SC failed event - light the service led
* note that as Solaris is still running,
* the Solaris active led should be lit too.
*/
switch (sys_platform) {
case PLAT_ENXS:
case PLAT_SALSA19:
case PLAT_EN19:
/*
* the device name for the bezel leds GPIO device
* tends to vary from Unix to Unix. Search for it.
*/
if (bezel_leds == NULL) {
}
if (bezel_leds == NULL)
return;
break;
case PLAT_ENTS:
/*
* the device name for the system leds gpio can vary
* as there are several similar gpio devices. Search
* for one with the desired address.
*/
if (bezel_leds == NULL) {
}
if (bezel_leds == NULL)
return;
break;
case PLAT_CHALUPA:
case PLAT_CHALUPA19:
break;
case PLAT_BOSTON:
/* set front leds */
/* and then the rear leds */
break;
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
break;
default:
break;
}
}
}
static int
{
int index;
return (-1);
return (index);
}
return (-1);
}
static int
{
int index;
return (-1);
return (index);
}
return (-1);
}
/*
* This function is the fini entry point of the plugin.
*/
static void
piclfrudr_fini(void)
{
NULL);
}
if (sc_device_name != NULL) {
}
}
/*
* subroutine for various functions. Finds immediate child of parh with
* requested name if present. Otherwise returns NULL.
*/
static picl_nodehdl_t
{
int err;
&nodeh, sizeof (picl_nodehdl_t));
if (err != PICL_SUCCESS)
return (NULL);
for (;;) {
sizeof (nodename));
if (err != PICL_SUCCESS)
return (NULL);
return (nodeh);
}
&nodeh, sizeof (picl_nodehdl_t));
if (err != PICL_SUCCESS)
return (NULL);
}
}
/* Creates a reference property for a given PICL node */
static int
{
int err;
if (err != PICL_SUCCESS) {
return (err);
}
if (err != PICL_SUCCESS) {
return (err);
}
return (PICL_SUCCESS);
}
/* create an entry in the specified table */
static int
{
int err;
/* first column is class */
if (err != PICL_SUCCESS) {
return (err);
}
/* second column is reference property */
if (err != PICL_SUCCESS) {
return (err);
}
/* add row to table */
if (err != PICL_SUCCESS)
return (err);
}
/* create an empty table property */
static int
{
int err;
if (err != PICL_SUCCESS) {
return (err);
}
if (err != PICL_SUCCESS)
return (err);
}
/*
* The size of outfilename must be PATH_MAX
*/
static int
{
int dir;
continue;
}
return (0);
}
}
return (0);
}
return (-1);
}
/*
* This helper function for Netra-440 fan tray removal removes
* the rmclomv-rooted nodes and their properties.
*/
static void
{
int err;
do {
if (err == PICL_SUCCESS) {
(void) ptree_destroy_prop(prop);
}
} while (err == PICL_SUCCESS);
(void) ptree_destroy_node(hdl);
}
static void
{
int retval;
int fanfru = 0;
sizeof (name));
if (retval != PICL_SUCCESS) {
return;
}
if (retval != PICL_SUCCESS) {
/*
* No Devices table. However on Seattle, Boston and
* Netra-440 (Chalupa19) (which support fan fru hotplug),
* the Devices table will be found under the child node (Fn)
* of the fru (fan-tray).
* Therefore, check the first child of the fru for the
* Devices table on these platforms before returning.
*/
switch (sys_platform) {
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
case PLAT_BOSTON:
return;
fanfru = 1;
break;
case PLAT_CHALUPA19:
return;
fanfru = 1;
break;
default:
/* nothing to do */
return;
}
if (retval != PICL_SUCCESS)
return;
if (retval != PICL_SUCCESS)
return;
}
/*
* follow all reference properties in the second
* column of the table and delete any _fru_parent node
* at the referenced node.
*/
if (retval != PICL_SUCCESS) {
/* can't get value of table property */
goto afterloop;
}
/* get first col, first row */
if (retval != PICL_SUCCESS) {
/* no rows? */
goto afterloop;
}
/*
* starting at next col, get every entry in the column
*/
retval == PICL_SUCCESS;
/*
* should be a ref prop in our hands,
* get the target node handle
*/
sizeof (nodeh));
if (retval != PICL_SUCCESS) {
continue;
}
/*
* got the referenced node, has it got a
* _fru_parent property?
*/
if (retval != PICL_SUCCESS) {
/*
* on Boston, Seattle and Netra-440 we should
* actually be looking for the _location_parent
* property for fan frus
*/
if (fanfru) {
}
if (retval != PICL_SUCCESS)
continue;
}
/*
* got a _fru_parent node reference delete it
*/
(void) ptree_destroy_prop(fruph);
/* On Netra-440, extra clean-up is required for fan trays */
/* remove the rmclomv node and its properties */
}
}
/* More Netra-440 fan tray clean-up */
/* remove the fru's child's table */
(void) ptree_destroy_prop(tableh);
/* remove the child */
(void) ptree_destroy_node(childh);
}
}
static void
{
int retval;
if (retval == PICL_SUCCESS) {
/*
* found a Devices property, delete it
*/
(void) ptree_destroy_prop(tableh);
}
}
/*
* is there a child node?
*/
sizeof (rootnd));
while (retval == PICL_SUCCESS) {
/*
* any siblings?
*/
}
}
/*
* Event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events
*/
/* ARGSUSED */
static void
{
int err;
/*
* now frudata has been notified that the node is to be
* removed, we can actually remove it
*/
(void) nvlist_lookup_uint64(earg,
/*
* first find name of the fru
*/
if (err == PICL_SUCCESS) {
sizeof (nodename));
}
if (err == PICL_SUCCESS) {
/*
* if it was a power supply, delete i2c node
*/
PS_NAME_LEN) == 0) {
(void) delete_i2c_node(nodename);
}
/*
* is disk node, make thread re-evaluate led
* state
*/
DISK_NAME_LEN) == 0) {
'0'] = -1;
}
}
/*
* now we can delete the node
*/
if (err == PICL_SUCCESS) {
(void) ptree_destroy_node(fruh);
} else {
}
if ((sys_platform == PLAT_CHALUPA19) &&
/*
* On Netra-440 platforms, a fan tray
* may contain 2 fans (F0 and F1) but
* we only receive a single notification
* for removal of F0. If F1 is present,
* peerh will be valid and we need to
* process it as well.
*/
if (err == PICL_SUCCESS) {
(void) ptree_destroy_node(peerh);
} else {
}
}
}
}
}
/*
* Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
*/
static void
{
char *ev_name;
return;
return;
}
if (parenth != 0L &&
return;
}
if (fruh != 0L &&
return;
}
frudr_completion_handler) != 0) {
}
}
static void
{
int res;
switch (sys_platform) {
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
if (res != PICL_SUCCESS)
return;
/*
* seeprom nodes sit below this node,
* is there one with the supplied unit address?
*/
&child_hdl, sizeof (picl_nodehdl_t));
while (res == PICL_SUCCESS) {
&child_hdl, sizeof (picl_nodehdl_t));
if ((res == PICL_SUCCESS) &&
sizeof (unit_addr)) == PICL_SUCCESS) {
return; /* unit address exists already */
}
}
/*
* found platform location for PS seeprom node, create it
*/
return;
return;
}
static void
{
switch (sys_platform) {
case PLAT_SEATTLE1U:
} else {
}
break;
case PLAT_SEATTLE2U:
} else {
}
break;
case PLAT_BOSTON:
break;
default:
break;
}
}
/*
* handle EC_DR picl events
*/
/*ARGSUSED*/
static void
{
char *dtype;
char *ap_id;
char *hint;
int err;
int index;
char *fru_name;
return;
}
return;
}
return;
}
return;
}
return;
}
/*
* check ap_id really is a hot-plug device
*/
} else {
return;
}
return;
}
/*
* OK - so this is an EC_DR event - let's handle it.
*/
(sys_platform != PLAT_CHALUPA19))
else {
if ((sys_platform == PLAT_CHALUPA19) &&
switch (sys_platform) {
case PLAT_SEATTLE1U:
break;
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
} else {
}
}
return;
}
/*
* now either add or delete the fru node as appropriate. If no
* hint, treat as insert and update the tree if necessary.
*/
/*
* fru was there - but has gone away
*/
}
} else if (rmc_flag) {
/*
* An event on the RMC location, just pass it on
* it's not really a PICL_FRU_ADDED event, so offer
* the child handle as well (if it exists).
*/
}
} else {
/*
* fru has been inserted (or may need to update)
* if node already there, then just return
*/
return;
}
/*
* On Netra-440, the fan-tray location nodes are
* not deleted when fan-trays are physically
* removed, so we do not need to create another
* fru node.
*/
if ((sys_platform != PLAT_CHALUPA19) ||
/*
* create requested fru node
*/
PICL_CLASS_FRU, &childh);
if (err != PICL_SUCCESS) {
return;
}
}
/*
* power supplies have operational status and fruid -
* add OperationalStatus property and create i2c device node
* before posting fru_added event
*/
if (index >= 0)
(void) create_i2c_node(ap_id);
}
/*
* now post event
*/
}
}
/*
* Handle PICL_FRU_ADDED events.
* These events are posted by the frudr_evhandler of this plugin in response to
* PICLEVENT_DR_AP_STATE_CHANGE events. The sequence is as follows:
* 1) frudr_evhandler catches PICLEVENT_DR_AP_STATE_CHANGE and creates a
* child node below the relevant location.
* 2) frudr_evhandler posts a PICL_FRU_ADDED event.
* 3) envmon catches PICL_FRU_ADDED event, gropes the RMC configuration
* and creates platform tree nodes (primarily for PSUs). (If the event
* is for the RMC itself, envmon deletes existing platform nodes and
* rebuilds from scratch.)
* 4) this plugin catches PICL_FRU_ADDED event, looks for a related
* configuration file and parses it. This adds Fru data properties (etc.).
* 5) frudata catches the event and updates its FRUID data cache.
*/
/*ARGSUSED*/
static void
{
int retval;
char *fru_name;
return;
if (retval != PICL_SUCCESS)
return;
if (retval != PICL_SUCCESS)
return;
return;
/*
* We're about to parse a fru-specific .conf file to populate
* picl nodes relating to the dynamically added component. In the
* case of the RMC, there is a problem: all of its /platform tree
* nodes have just been replaced by envmon. It is now necessary to
* repopulate Devices tables in /frutree.
* picld_pluginutil_parse_config_file doesn't handle repopulating
* existing tables, so as a work round, delete all tables found
* under /frutree. This works on Enchilada Server as the tables
* are all created from parsing a .conf file, and we're about to
* redo that action.
*/
if (retval == PICL_SUCCESS) {
}
}
/*
* Re-establish the HPU(FRU) volatile properties.
* This needs to be done before the .conf file is parsed because
* it has a side effect of re-creating any missing power-supply
* fru node. The .conf file can then hang properties beneath.
*/
opst_init();
/*
* see if there's a .conf file for this fru
*/
PICL_SUCCESS)) {
}
}
}
/*
* Handle PICLEVENT_SYSEVENT_DEVICE_ADDED events.
*/
/*ARGSUSED*/
static void
void *cookie)
{
char *fru_name;
char *dtype;
char *dpath;
char *ptr;
char *ptr2;
int i;
return;
return;
return;
}
return;
}
return;
}
return;
}
/*
* fru_name is of the form
* or
* reduce it to "usb-a-2"
*/
if ((sys_platform == PLAT_SEATTLE1U) ||
(sys_platform == PLAT_SEATTLE2U) ||
(sys_platform == PLAT_BOSTON)) {
for (i = 0; i < MAX_USB_PORTS; i++) {
path) != PICL_SUCCESS)) {
}
}
}
} else {
if (*ptr == '/') {
ptr++;
ptr++;
*ptr = '-';
ptr++;
*ptr = '-';
ptr++;
ptr++;
'/');
*ptr2 = '\0';
}
}
}
}
}
}
return;
}
/*
* see if there's a .conf file for this fru
*/
PICL_SUCCESS)) {
}
}
}
}
static int
{
int retval;
char *value_ptr;
/* find the location node */
switch (sys_platform) {
case PLAT_CHALUPA:
case PLAT_CHALUPA19:
break;
case PLAT_SEATTLE1U:
break;
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
return (PICL_FAILURE);
}
/*
* if no fru node, then turn led off
*/
else
/* get its Devices table */
return (PICL_FAILURE);
return (PICL_FAILURE);
/* get first col, first row */
return (PICL_FAILURE);
/*
* starting at next col, get every entry in the column
*/
retval == PICL_SUCCESS;
/*
* get the target node handle
*/
!= PICL_SUCCESS)
continue;
/*
* check it's a led
*/
continue;
continue;
/*
* check its the right led
*/
continue;
/*
* set it
*/
&proph) != PICL_SUCCESS)
continue;
continue;
return (retval);
}
}
return (PICL_FAILURE);
}
/*
* function to find first node of specified class beneath supplied node
*/
static int
{
int err;
/*
* go through the children
*/
sizeof (picl_nodehdl_t));
while (err == PICL_SUCCESS) {
*foundnodeh = childh;
return (PICL_SUCCESS);
}
if (err == PICL_SUCCESS)
return (PICL_SUCCESS);
&childh, sizeof (picl_nodehdl_t));
}
return (PICL_NODENOTFOUND);
}
/*
* get system-controller node
*/
static int
{
int err;
/* get platform node */
if (err != PICL_SUCCESS)
return (err);
return (err);
}
/*
* create pathname string for system-controller device
*/
static char *
{
char *ptr;
/*
* prefix devfs-path name with /devices
*/
/*
* append devfs-path property
*/
return (NULL);
}
/*
* locate final component of name
*/
return (NULL);
return (NULL);
}
/*
* look for a name which starts with the string at *ptr
*/
continue; /* skip short names */
/*
* Got a match, restore full pathname and stat the
* entry. Reject if not a char device
*/
continue; /* reject if can't stat it */
continue; /* not a character device */
/*
* go with this entry
*/
}
}
return (NULL);
}
/*
* create pathname string for bezel leds device
*/
static char *
{
/*
* start with directory name
*/
/*
* append devfs-path property
*/
return (NULL);
}
/*
* look for a name which starts with the gpio string
*/
continue; /* skip short names */
/*
* Got a match, restore full pathname and stat the
* entry. Reject if not a char device
*/
sizeof (namebuf) - lendirpath);
continue; /* reject if can't stat it */
continue; /* not a character device */
/*
* go with this entry
*/
}
}
return (NULL);
}
/*
* initialise structure associated with nodes requiring OperationalStatus
*/
static void
opst_init(void)
{
int res;
int index = 0;
int fd;
int entries = 0;
int err = 0;
/*
* This must be a restart, clean up earlier allocation
*/
}
if (sc_device_name == NULL)
err = 1;
else {
if (fd < 0) {
err = 1;
}
}
if (err == 0) {
if (res < 0) {
err = 1;
}
}
if (err == 0) {
err = 1;
}
}
if (err == 0) {
/*
* The HPU node for the RMC is a special case. Its handle is
* generated by the rmclomv driver. Rather than building
* knowledge of its frutree hierarchic name into the driver, we
* put that knowledge here.
*/
if ((res == 0) &&
}
}
}
}
static void
disk_leds_init(void)
{
int err = 0, i;
if (!g_mutex_init) {
} else {
return;
}
}
/*
* Initialise to -1 so the led thread will set correctly.
* Do this before creating the disk_leds thread,
* so there's no race.
*/
for (i = 0; i < N_DISKS; i++)
disk_ready[i] = -1;
if (ledsthr_created) {
/*
* this is a restart, wake up sleeping threads
*/
if (err != 0) {
return;
}
(void) pthread_cond_broadcast(&g_cv);
(void) pthread_mutex_unlock(&g_mutex);
} else {
if ((pthread_attr_init(&ledsthr_attr) != 0) ||
PTHREAD_SCOPE_SYSTEM) != 0))
return;
disk_leds_thread, NULL)) != 0) {
return;
}
}
}
static void
disk_leds_fini(void)
{
int err, i;
/*
* turn the leds off as we'll no longer be monitoring them
*/
for (i = 0; i < N_DISKS; i++)
/*
* disk_leds_thread() never started or an error occured so
* that it's not running
*/
if (!disk_leds_thread_running)
return;
/*
* tell led thread to pause
*/
if (!ledsthr_created)
return;
if (err != 0) {
return;
}
(void) pthread_cond_broadcast(&g_cv);
/*
* and wait for them to acknowledge
*/
while (!disk_leds_thread_ack) {
}
(void) pthread_mutex_unlock(&g_mutex);
}
static void
{
int err;
switch (sys_platform) {
case PLAT_CHALUPA:
case PLAT_CHALUPA19:
break;
case PLAT_SEATTLE1U:
break;
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
return;
}
return;
}
if (err == PICL_SUCCESS) {
if (err != PICL_SUCCESS)
return;
if (err != PICL_SUCCESS) {
if (err != PICL_SUCCESS)
return;
if (err != PICL_SUCCESS)
return;
}
} else {
/*
* no mechanism for deleting row - so delete
* whole table and start again
*/
&tblproph);
if (err != PICL_SUCCESS)
return;
if (err != PICL_SUCCESS)
return;
(void) ptree_destroy_prop(tblproph);
if (err != PICL_SUCCESS)
return;
}
}
/*
* We will light the OK2REMOVE LED for disks configured
* into a raid if (and only if) the driver reports
* that the disk has failed.
*/
static int
{
int i;
if (d == target) {
switch (dstatus) {
case RAID_DISKSTATUS_MISSING:
/* If LED is on, turn it off */
if (disk_ready[d] == B_FALSE) {
PICL_PROPVAL_OFF) == PICL_SUCCESS) {
disk_ready[d] = B_TRUE;
}
}
break;
case RAID_DISKSTATUS_GOOD:
if (disk_ready[d] != B_TRUE) {
PICL_PROPVAL_OFF) == PICL_SUCCESS) {
disk_ready[d] = B_TRUE;
}
}
break;
case RAID_DISKSTATUS_FAILED:
if (disk_ready[d] != B_FALSE) {
PICL_PROPVAL_ON) == PICL_SUCCESS) {
disk_ready[d] = B_FALSE;
}
}
break;
default:
break;
}
return (1);
}
}
return (0);
}
static int
{
int fd;
int numvols;
int i, j;
switch (sys_platform) {
case PLAT_CHALUPA:
case PLAT_CHALUPA19:
break;
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
if (boston_1068e_flag) {
} else {
}
break;
default:
fd = -1;
break;
}
if (fd == -1) {
return (0);
}
return (0);
}
for (i = 0; i < numvols; i++) {
return (0);
}
return (1);
}
}
return (0);
}
/*ARGSUSED*/
static void *
{
int c;
int i;
char **disk_dev;
int fd;
int n_disks = 0,
do_raid = 0,
err = 0;
static char *mpxu_devs[] = {
"/pci@1c,600000/scsi@2/sd@0,0",
"/pci@1c,600000/scsi@2/sd@1,0",
"/pci@1c,600000/scsi@2/sd@2,0",
"/pci@1c,600000/scsi@2/sd@3,0"
};
static char *ents_devs[] = {
"/pci@1d,700000/scsi@4/sd@0,0",
"/pci@1d,700000/scsi@4/sd@1,0",
"/pci@1d,700000/scsi@4/sd@2,0",
"/pci@1d,700000/scsi@4/sd@3,0",
"/pci@1d,700000/scsi@4/sd@8,0",
"/pci@1d,700000/scsi@4/sd@9,0",
"/pci@1d,700000/scsi@4/sd@a,0",
"/pci@1d,700000/scsi@4/sd@b,0"
};
static char *v440_devs[] = {
"/pci@1f,700000/scsi@2/sd@0,0",
"/pci@1f,700000/scsi@2/sd@1,0",
"/pci@1f,700000/scsi@2/sd@2,0",
"/pci@1f,700000/scsi@2/sd@3,0"
};
static char *n210_devs[] = {
"/pci@1c,600000/LSILogic,sas@1/sd@0,0",
"/pci@1c,600000/LSILogic,sas@1/sd@1,0"
};
static char *seattle_devs[] = {
};
static char *boston_devs_1068e[] = {
"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@0,0",
"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@1,0",
"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@2,0",
"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@3,0",
"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@4,0",
"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@5,0",
"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@6,0",
"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@7,0"
};
static char *boston_devs_1068x[] = {
"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@0,0",
"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@1,0",
"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@2,0",
"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@3,0",
"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@4,0",
"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@5,0",
"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@6,0",
"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@7,0"
};
switch (sys_platform) {
case PLAT_ENTS:
break;
case PLAT_CHALUPA:
case PLAT_CHALUPA19:
do_raid = 1;
break;
case PLAT_SALSA19:
break;
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
do_raid = 1;
break;
case PLAT_BOSTON:
/*
* If we can open the devctl path for the built-in 1068E
* controller then assume we're a 1068E-equipped Boston
* and make all the paths appropriate for that hardware.
* Otherwise assume we are a 1068X-equipped Boston and
* make all of the paths appropriate for a 1068X PCI-X
* controller in PCI slot 4.
*
* The flag is also used in the check_raid() function.
*/
boston_1068e_flag = 1;
} else {
boston_1068e_flag = 0;
}
do_raid = 1;
break;
}
/*
* make up disk names
*/
for (i = 0; i < n_disks; i++) {
}
for (;;) {
for (i = 0; i < n_disks; i++) {
/*
* If it's one of the RAID disks, we have already
* applied the ok2remove policy.
*/
if (do_raid && check_raid(i)) {
continue;
}
if (statep & DEVICE_OFFLINE) {
if (disk_ready[i] != B_FALSE) {
disk_ready[i] = B_FALSE;
}
} else if (statep & DEVICE_ONLINE) {
if (disk_ready[i] != B_TRUE) {
disk_ready[i] = B_TRUE;
}
}
}
/*
* wait a bit until we check again
*/
/*
* are we to stop?
*/
(void) pthread_mutex_lock(&g_mutex);
while (g_finish_now) {
/*
* notify _fini routine that we've paused
*/
(void) pthread_cond_signal(&g_cv_ack);
/*
* and go to sleep in case we get restarted
*/
}
(void) pthread_mutex_unlock(&g_mutex);
}
return ((void *)err);
}
/*
* Given the powersupply name, convert to addr
*/
static int
{
int ps_addr = 0;
switch (sys_platform) {
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
switch (sys_platform) {
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
switch (sys_platform) {
case PLAT_BOSTON:
break;
default:
break;
}
switch (sys_platform) {
case PLAT_BOSTON:
break;
default:
break;
}
}
return (ps_addr);
}
/*
* Given powersupply name, convert to unit addr
*/
static char *
{
char *unitaddr;
switch (sys_platform) {
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
switch (sys_platform) {
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
switch (sys_platform) {
case PLAT_BOSTON:
break;
default:
break;
}
switch (sys_platform) {
case PLAT_BOSTON:
break;
default:
break;
}
}
else
return (unitaddr);
}
/*
* converts apid to real FRU name in PICL tree. The
* name of powersupply devices on chalupa19 are
* PSU instead of PS
*/
static char *
{
char *nodename;
if (sys_platform != PLAT_CHALUPA19)
return (apid);
else
return (nodename);
}
/*
* Create SEEPROM node at insertion time.
*/
static int
{
char *compatible;
/* create seeprom node */
nd_reg[0] = 0;
switch (sys_platform) {
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
return (DDI_FAILURE);
/* device definition properties */
/* create the device node */
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/*
* Delete SEEPROM node at insertion time.
*/
static void
{
switch (sys_platform) {
case PLAT_SEATTLE1U:
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
return;
}
/*
* If the seeprom driver is not loaded, calls to
* devctl_device_remove fails for seeprom devices
*/
if (devctl_device_remove(dev_hdl)) {
}
}
static void
{
PS_NAME_LEN) == 0);
DISK_NAME_LEN) == 0);
(sys_platform != PLAT_CHALUPA19));
} else if (disk_flag) {
switch (sys_platform) {
case PLAT_CHALUPA:
case PLAT_CHALUPA19:
break;
case PLAT_SEATTLE1U:
break;
case PLAT_SEATTLE2U:
break;
case PLAT_BOSTON:
break;
default:
break;
}
}
}