megactl/src/adapter.c

846 lines
28 KiB
C

/*
* High-level interface to adapter information.
*
* Copyright (c) 2007 by Jefferson Ogata
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; see the file COPYING. If not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "megaioctl.h"
#include "logpage.h"
#include "ntrim.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <scg/scsireg.h>
static void batteryStatus (struct adapter_config *a, uint8_t status)
{
a->battery.module_missing = (status & BATTERY_MODULE_MISSING) != 0;
a->battery.pack_missing = (status & BATTERY_PACK_MISSING) != 0;
a->battery.low_voltage = (status & BATTERY_LOW_VOLTAGE) != 0;
a->battery.high_temperature = (status & BATTERY_TEMP_HIGH) != 0;
a->battery.cycles_exceeded = (status & BATTERY_CYCLES_EXCEEDED) != 0;
switch (status & BATTERY_CHARGE_MASK)
{
case BATTERY_CHARGE_FAIL: a->battery.charger_state = ChargerStateFailed; break;
case BATTERY_CHARGE_DONE: a->battery.charger_state = ChargerStateComplete; break;
case BATTERY_CHARGE_INPROG: a->battery.charger_state = ChargerStateInProgress; break;
default: a->battery.charger_state = ChargerStateUnknown; break;
}
a->battery.voltage = -1;
a->battery.temperature = -1;
a->battery.healthy = !(a->battery.module_missing || a->battery.pack_missing || a->battery.low_voltage || a->battery.high_temperature || a->battery.cycles_exceeded || (a->battery.charger_state != ChargerStateComplete));
}
static void batteryStatus5 (struct adapter_config *a)
{
struct mega_battery_state_sas *b = &a->q.v5.battery.state;
a->battery.module_missing = !(a->q.v5.adapinfo.hw_present.bbu);
a->battery.pack_missing = b->type == MEGA_BATTERY_TYPE_NONE;
a->battery.low_voltage = b->remaining_capacity_alarm || b->remaining_time_alarm || b->fully_discharged;
a->battery.high_temperature = b->over_temperature != 0;
a->battery.over_charged = b->over_charged != 0;
switch (b->charger_status)
{
case 0: a->battery.charger_state = ChargerStateFailed; break;
case 1: a->battery.charger_state = ChargerStateComplete; break;
case 2: a->battery.charger_state = ChargerStateInProgress; break;
default: a->battery.charger_state = ChargerStateUnknown; break;
}
a->battery.voltage = b->voltage;
a->battery.temperature = b->temperature;
a->battery.healthy = !(a->battery.module_missing || a->battery.pack_missing || a->battery.low_voltage || a->battery.high_temperature || a->battery.cycles_exceeded || (a->battery.charger_state != ChargerStateComplete) || (!b->health));
}
static struct log_page_list *getPage (struct physical_drive_info *d, uint8_t page)
{
struct log_page_list *p;
if ((p = (struct log_page_list *) malloc (sizeof (*p))) == NULL)
return NULL;
memset (p, 0, sizeof (*p));
if (megaScsiLogSense (&d->adapter->target, d->target, &p->buf, sizeof (p->buf), 1, page, 0) < 0)
{
free (p);
return NULL;
}
if (parseLogPage (&p->buf, sizeof (p->buf), &p->log) < 0)
{
free (p);
return NULL;
}
return p;
}
struct log_page_list *getDriveLogPage (struct physical_drive_info *d, uint8_t page)
{
struct supportedLogsPage *supported = NULL;
struct log_page_list *p;
for (p = d->log; p; p = p->next)
{
if (p->log.h.page_code == page)
return p;
if (p->log.h.page_code == 0)
supported = &p->log.u.supported;
}
if (supported == NULL)
{
if ((p = getPage (d, 0)) == NULL)
return NULL;
p->next = d->log;
d->log = p;
if (page == 0)
return p;
supported = &p->log.u.supported;
}
/* Is the requested page supported? */
if (supported->page[page] == 0)
return NULL;
if ((p = getPage (d, page)) == NULL)
return NULL;
p->next = d->log;
d->log = p;
return p;
}
int cmpPhysical (const void *a, const void *b)
{
struct physical_drive_info *x = *((struct physical_drive_info **) a);
struct physical_drive_info *y = *((struct physical_drive_info **) b);
if (x->adapter->target.adapno != y->adapter->target.adapno)
return (int) (x->adapter->target.adapno) - (int) (y->adapter->target.adapno);
if (x->channel != y->channel)
return (int) (x->channel) - (int) (y->channel);
if (x->id != y->id)
return (int) (x->id) - (int) (y->id);
return 0;
}
struct physical_drive_info *getPhysicalDriveInfo (struct adapter_config *a, uint16_t target, int fetch)
{
int k;
struct physical_drive_info *d;
/* Look for it. */
for (k = 0, d = a->physical; k < a->num_physicals; ++k, ++d)
{
if (d->adapter == NULL)
break;
if (d->target == target)
return d->present ? d : NULL;
}
/* Not there and no place for it. That's just wrong. */
if (k >= a->num_physicals)
{
fprintf (stderr, "me so crazy, me think adapter crazy too. sorry, mister.\n");
return NULL;
}
/* If we don't want to query it, we're done. */
if (!fetch)
return NULL;
d->adapter = a;
d->target = target;
if (a->is_sas)
{
struct mega_physical_disk_info_sas *info = &d->q.v5.info;
if (megaSasGetDiskInfo (&a->target, target, info) < 0)
{
d->error_string = megaErrorString ();
d->present = 0;
return NULL;
}
d->channel = info->enclosure;
d->id = info->slot;
snprintf (d->name, sizeof (d->name), "%se%us%u", a->name, d->channel, d->id);
d->inquiry = info->inquiry.inq;
strncpy (d->vendor, d->inquiry.vendor_info, sizeof (d->vendor) - 1);
d->vendor[sizeof (d->vendor) - 1] = '\0';
ntrim (d->vendor);
strncpy (d->model, d->inquiry.prod_ident, sizeof (d->model) - 1);
d->model[sizeof (d->model) - 1] = '\0';
ntrim (d->model);
strncpy (d->revision, d->inquiry.prod_revision, sizeof (d->revision) - 1);
d->revision[sizeof (d->revision) - 1] = '\0';
ntrim (d->revision);
if ((d->inquiry.qualifier == INQ_DEV_PRESENT) && (d->inquiry.type == INQ_DASD))
{
d->present = 1;
}
else
{
d->present = 0;
return NULL;
}
strncpy (d->serial, (char *) info->inquiry.buf + sizeof (info->inquiry.inq), sizeof (d->serial));
d->serial[sizeof (d->serial) - 1] = '\0';
ntrim (d->serial);
if (info->configured)
{
if (info->online)
d->state = PdStateOnline;
else if (info->rebuild)
d->state = PdStateRebuild;
else if (info->failure)
d->state = PdStateFailed;
else
d->state = PdStateUnknown;
}
else
{
if (info->hotspare)
d->state = PdStateHotspare;
else if (info->failure)
d->state = PdStateUnconfiguredBad;
else
d->state = PdStateUnconfiguredGood;
}
d->blocks = info->raw_size;
d->media_errors = info->media_errors;
d->other_errors = info->other_errors;
d->predictive_failures = info->predictive_failures;
}
else
{
int status;
struct scsi_inquiry inq;
uint8_t evpd[128];
struct mega_physical_drive_error_info errors;
d->channel = (target >> 4) & 0xf;
d->id = target & 0xf;
snprintf (d->name, sizeof (d->name), "%sc%ut%u", a->name, d->channel, d->id);
if (megaScsiDriveInquiry (&a->target, target, &inq, sizeof (inq), 0, 0) == 0)
{
d->inquiry = inq;
strncpy (d->vendor, d->inquiry.vendor_info, sizeof (d->vendor) - 1);
d->vendor[sizeof (d->vendor) - 1] = '\0';
ntrim (d->vendor);
strncpy (d->model, d->inquiry.prod_ident, sizeof (d->model) - 1);
d->model[sizeof (d->model) - 1] = '\0';
ntrim (d->model);
strncpy (d->revision, d->inquiry.prod_revision, sizeof (d->revision) - 1);
d->revision[sizeof (d->revision) - 1] = '\0';
ntrim (d->revision);
if ((d->inquiry.qualifier == INQ_DEV_PRESENT) && (d->inquiry.type == INQ_DASD))
{
d->present = 1;
}
else
{
d->present = 0;
return NULL;
}
}
else
{
d->error_string = megaErrorString ();
d->present = 0;
return NULL;
}
if (megaScsiDriveInquiry (&a->target, target, evpd, sizeof evpd, 0x80, 1) == 0)
{
uint8_t len = evpd[3];
if ((evpd[1] == 0x80) && (len + 4 <= sizeof evpd))
{
if (len > sizeof (d->serial) - 1)
len = sizeof (d->serial) - 1;
strncpy (d->serial, (char *) evpd + 4, len);
d->serial[len] = '\0';
ntrim (d->serial);
}
}
if ((status = megaGetDriveErrorCount (&a->target, target, &errors)) == 0)
{
d->media_errors = errors.media;
d->other_errors = errors.other;
}
else
d->error_string = megaErrorString ();
}
/* Add it to the device list and sort it. */
for (k = 0; k < a->num_physicals; ++k)
if (a->physical_list[k] == NULL)
break;
if (k >= a->num_physicals)
{
fprintf (stderr, "not ok at the ok corral. freak out, mama!\n");
return NULL;
}
a->physical_list[k++] = d;
qsort (a->physical_list, k, sizeof (*a->physical_list), cmpPhysical);
return d;
}
/* Adapter handling for PERC2. */
static char *getAdapterConfig2 (struct adapter_config *a)
{
int k;
logdrv_8ld_span8_t *ml;
int spanIndex;
mraid_adapinfo1_t *pinfo = &a->q.v2.inquiry.adapter_info;
mraid_inquiry1_t *inquiry = &a->q.v2.inquiry;
disk_array_8ld_span8_t *config = &a->q.v2.config;
a->target.type = MEGA_ADAPTER_V2;
if (megaGetAdapterInquiry (&a->target, inquiry) < 0)
return "cannot query adapter";
if (megaGetAdapterConfig8 (&a->target, config) < 0)
return "cannot read adapter config";
if (megaGetPredictiveMap (&a->target, &a->q.v2.map) < 0)
return "cannot read adapter predictive map";
a->rebuild_rate = pinfo->rebuild_rate;
a->dram_size = pinfo->dram_size;
snprintf (a->name, sizeof (a->name), "a%u", a->target.adapno);
strcpy (a->product, "PERC2/");
switch (pinfo->nchannels)
{
case 1: strcat (a->product, "SC"); break;
case 2: strcat (a->product, "DC"); break;
case 4: strcat (a->product, "QC"); break;
default: return "invalid number of channels";
}
strncpy (a->bios, (char *) pinfo->bios_version, sizeof (a->bios));
a->bios[sizeof (a->bios) - 1] = '\0';
ntrim (a->bios);
strncpy (a->firmware, (char *) pinfo->fw_version, sizeof (a->firmware));
a->firmware[sizeof (a->firmware) - 1] = '\0';
ntrim (a->firmware);
batteryStatus (a, pinfo->battery_status);
if (config->numldrv > sizeof (config->ldrv) / sizeof (config->ldrv[0]))
return "invalid number of logical drives";
a->num_channels = pinfo->nchannels;
if ((a->channel = (uint8_t *) malloc (a->num_channels * sizeof (*a->channel))) == NULL)
return "out of memory (channels)";
for (k = 0; k < a->num_channels; ++k)
a->channel[k] = k;
a->num_physicals = FC_MAX_PHYSICAL_DEVICES;
if ((a->physical = (struct physical_drive_info *) malloc (a->num_physicals * sizeof (*a->physical))) == NULL)
return "out of memory (physical drives)";
memset (a->physical, 0, a->num_physicals * sizeof (*a->physical));
if ((a->physical_list = (struct physical_drive_info **) malloc (a->num_physicals * sizeof (*a->physical_list))) == NULL)
return "out of memory (physical drives)";
memset (a->physical_list, 0, a->num_physicals * sizeof (*a->physical_list));
a->num_logicals = config->numldrv;
if ((a->logical = (struct logical_drive_info *) malloc (a->num_logicals * sizeof (*a->logical))) == NULL)
return "out of memory (logical drives)";
memset (a->logical, 0, a->num_logicals * sizeof (*a->logical));
/* Count how many spans there are. */
for (k = 0, ml = config->ldrv, a->num_spans = 0; k < config->numldrv; ++k, ++ml)
a->num_spans += ml->lparam.span_depth;
if ((a->span = (struct span_info *) malloc (a->num_spans * sizeof (*a->span))) == NULL)
return "out of memory (spans)";
memset (a->span, 0, a->num_spans * sizeof (*a->span));
/* Copy drive states. */
for (k = 0; k < sizeof (inquiry->pdrv_info.pdrv_state) / sizeof (inquiry->pdrv_info.pdrv_state[0]); ++k)
switch (inquiry->pdrv_info.pdrv_state[k] & 0xf)
{
case PDRV_UNCNF: a->physical[k].state = PdStateUnconfiguredGood; continue;
case PDRV_ONLINE: a->physical[k].state = PdStateOnline; continue;
case PDRV_FAILED: a->physical[k].state = PdStateFailed; continue;
case PDRV_RBLD: a->physical[k].state = PdStateRebuild; continue;
case PDRV_HOTSPARE: a->physical[k].state = PdStateHotspare; continue;
default: a->physical[k].state = PdStateUnknown; continue;
}
/* Copy drive sizes. */
for (k = 0; k < sizeof (config->pdrv) / sizeof (config->pdrv[0]); ++k)
a->physical[k].blocks = config->pdrv[k].size;
/* Copy drive predictive failures flag */
for (k = 0; k < 8 * sizeof (a->q.v2.map.map) / sizeof (a->q.v2.map.map[0]); ++k)
a->physical[k].predictive_failures = ((a->q.v2.map.map[k >> 3] & (1 << (k & 0x7))) != 0);
/* Examine all the logical drives. */
for (k = 0, ml = config->ldrv, spanIndex = 0; k < config->numldrv; ++k, ++ml)
{
struct span_info *span;
adap_span_8ld_t *mr;
int j;
struct logical_drive_info *l = &a->logical[k];
l->adapter = a;
snprintf (l->name, sizeof (l->name), "a%ud%u", a->target.adapno, k);
l->target = k;
switch (ml->lparam.status)
{
case RDRV_OFFLINE: l->state = LdStateOffline; break;
case RDRV_DEGRADED: l->state = LdStateDegraded; break;
case RDRV_OPTIMAL: l->state = LdStateOptimal; break;
case RDRV_DELETED: l->state = LdStateDeleted; break;
default: l->state = LdStateUnknown; break;
}
l->raid_level = ml->lparam.level;
l->span_size = ml->lparam.row_size;
l->num_spans = ml->lparam.span_depth;
if ((l->span = (struct span_reference *) malloc (l->num_spans * sizeof (*l->span))) == NULL)
return "out of memory (span references)";
for (j = 0, mr = ml->span; j < ml->lparam.span_depth; ++j, ++mr)
{
int i;
span = &a->span[spanIndex++];
span->adapter = a;
span->num_logical_drives = 1;
if ((span->logical_drive = (struct logical_drive_info **) malloc (span->num_logical_drives * sizeof (*span->logical_drive))) == NULL)
return "out of memory (span -> ldrv pointers)";
span->logical_drive[0] = l;
span->blocks_per_disk = mr->num_blks;
span->num_disks = ml->lparam.row_size;
if ((span->disk = (struct physical_drive_info **) malloc (span->num_disks * sizeof (*span->disk))) == NULL)
return "out of memory (span -> disk pointers)";
/* Logical drives use the whole span. */
l->span[j].offset = 0;
l->span[j].blocks_per_disk = span->blocks_per_disk;
l->span[j].span = span;
for (i = 0; i < span->num_disks; ++i)
{
span->disk[i] = &a->physical[mr->device[i].target];
span->disk[i]->span = span;
}
}
}
return NULL;
}
/* Adapter handling for PERC3 and PERC4 adapters. */
static char *getAdapterConfig3 (struct adapter_config *a)
{
int k;
logdrv_40ld_t *ml;
int spanIndex;
mraid_pinfo_t *pinfo = &a->q.v3.adapinfo;
mraid_inquiry3_t *enquiry3 = &a->q.v3.enquiry3;
disk_array_40ld_t *config = &a->q.v3.config;
a->target.type = MEGA_ADAPTER_V34;
if (megaGetAdapterEnquiry3 (&a->target, &a->q.v3.enquiry3) < 0)
return "cannot query adapter";
if (megaGetAdapterConfig40 (&a->target, config) < 0)
return "cannot read adapter config";
if (megaGetPredictiveMap (&a->target, &a->q.v3.map) < 0)
return "cannot read adapter predictive map";
a->rebuild_rate = enquiry3->rebuild_rate;
a->dram_size = pinfo->dram_size;
snprintf (a->name, sizeof (a->name), "a%u", a->target.adapno);
switch (pinfo->nchannels)
{
case 1: break;
case 2: break;
case 4: break;
default: return "invalid number of channels";
}
strncpy (a->product, (char *) pinfo->product_name, sizeof (pinfo->product_name));
a->product[sizeof (a->product) - 1] = '\0';
ntrim (a->product);
strncpy (a->bios, (char *) pinfo->bios_version, sizeof (a->bios));
a->bios[sizeof (a->bios) - 1] = '\0';
ntrim (a->bios);
strncpy (a->firmware, (char *) pinfo->fw_version, sizeof (a->firmware));
a->firmware[sizeof (a->firmware) - 1] = '\0';
ntrim (a->firmware);
batteryStatus (a, enquiry3->battery_status);
if (config->numldrv > sizeof (config->ldrv) / sizeof (config->ldrv[0]))
return "invalid number of logical drives";
a->num_channels = pinfo->nchannels;
if ((a->channel = (uint8_t *) malloc (a->num_channels * sizeof (*a->channel))) == NULL)
return "out of memory (channels)";
for (k = 0; k < a->num_channels; ++k)
a->channel[k] = k;
a->num_physicals = FC_MAX_PHYSICAL_DEVICES;
if ((a->physical = (struct physical_drive_info *) malloc (a->num_physicals * sizeof (*a->physical))) == NULL)
return "out of memory (physical drives)";
memset (a->physical, 0, a->num_physicals * sizeof (*a->physical));
if ((a->physical_list = (struct physical_drive_info **) malloc (a->num_physicals * sizeof (*a->physical_list))) == NULL)
return "out of memory (physical drives)";
memset (a->physical_list, 0, a->num_physicals * sizeof (*a->physical_list));
a->num_logicals = config->numldrv;
if ((a->logical = (struct logical_drive_info *) malloc (a->num_logicals * sizeof (*a->logical))) == NULL)
return "out of memory (logical drives)";
memset (a->logical, 0, a->num_logicals * sizeof (*a->logical));
/* Count how many spans there are. */
for (k = 0, ml = config->ldrv, a->num_spans = 0; k < config->numldrv; ++k, ++ml)
a->num_spans += ml->lparam.span_depth;
if ((a->span = (struct span_info *) malloc (a->num_spans * sizeof (*a->span))) == NULL)
return "out of memory (spans)";
memset (a->span, 0, a->num_spans * sizeof (*a->span));
/* Copy drive states. */
for (k = 0; k < sizeof (enquiry3->pdrv_state) / sizeof (enquiry3->pdrv_state[0]); ++k)
switch (enquiry3->pdrv_state[k] & 0xf)
{
case PDRV_UNCNF: a->physical[k].state = PdStateUnconfiguredGood; continue;
case PDRV_ONLINE: a->physical[k].state = PdStateOnline; continue;
case PDRV_FAILED: a->physical[k].state = PdStateFailed; continue;
case PDRV_RBLD: a->physical[k].state = PdStateRebuild; continue;
case PDRV_HOTSPARE: a->physical[k].state = PdStateHotspare; continue;
default: a->physical[k].state = PdStateUnknown; continue;
}
/* Copy drive sizes. */
for (k = 0; k < sizeof (config->pdrv) / sizeof (config->pdrv[0]); ++k)
a->physical[k].blocks = config->pdrv[k].size;
/* Copy drive predictive failures flag */
for (k = 0; k < 8 * sizeof (a->q.v3.map.map) / sizeof (a->q.v3.map.map[0]); ++k)
a->physical[k].predictive_failures = ((a->q.v3.map.map[k >> 3] & (1 << (k & 0x7))) != 0);
/* Examine all the logical drives. */
for (k = 0, ml = config->ldrv, spanIndex = 0; k < config->numldrv; ++k, ++ml)
{
struct span_info *span;
adap_span_40ld_t *mr;
int j;
struct logical_drive_info *l = &a->logical[k];
l->adapter = a;
snprintf (l->name, sizeof (l->name), "a%ud%u", a->target.adapno, k);
l->target = k;
switch (ml->lparam.status)
{
case RDRV_OFFLINE: l->state = LdStateOffline; break;
case RDRV_DEGRADED: l->state = LdStateDegraded; break;
case RDRV_OPTIMAL: l->state = LdStateOptimal; break;
case RDRV_DELETED: l->state = LdStateDeleted; break;
default: l->state = LdStateUnknown; break;
}
l->raid_level = ml->lparam.level;
l->span_size = ml->lparam.row_size;
l->num_spans = ml->lparam.span_depth;
if ((l->span = (struct span_reference *) malloc (l->num_spans * sizeof (*l->span))) == NULL)
return "out of memory (span references)";
for (j = 0, mr = ml->span; j < ml->lparam.span_depth; ++j, ++mr)
{
int i;
span = &a->span[spanIndex++];
span->adapter = a;
span->num_logical_drives = 1;
if ((span->logical_drive = (struct logical_drive_info **) malloc (span->num_logical_drives * sizeof (*span->logical_drive))) == NULL)
return "out of memory (span -> ldrv pointers)";
span->logical_drive[0] = l;
span->blocks_per_disk = mr->num_blks;
span->num_disks = ml->lparam.row_size;
if ((span->disk = (struct physical_drive_info **) malloc (span->num_disks * sizeof (*span->disk))) == NULL)
return "out of memory (span -> disk pointers)";
/* Logical drives use the whole span. */
l->span[j].offset = 0;
l->span[j].blocks_per_disk = span->blocks_per_disk;
l->span[j].span = span;
for (i = 0; i < span->num_disks; ++i)
{
span->disk[i] = &a->physical[mr->device[i].target];
span->disk[i]->span = span;
}
}
}
#if 0
/* Go ahead and hit all the other devices that have a non-zero scsi transfer rate. */
for (k = 0; k < sizeof (a->q.v3.enquiry3.targ_xfer) / sizeof (a->q.v3.enquiry3.targ_xfer[0]); ++k)
if (a->q.v3.enquiry3.targ_xfer[k])
(void) getPhysicalDriveInfo (a, (uint8_t) k, 1);
#endif
return NULL;
}
int cmpChannel (const void *a, const void *b)
{
int x = (int) *((uint8_t *) a);
int y = (int) *((uint8_t *) b);
return x - y;
}
/* Adapter handling for PERC5 adapters. */
static char *getAdapterConfig5 (struct adapter_config *a)
{
int k;
struct mega_array_span_def_sas *ms;
struct mega_array_disk_def_sas *ml;
struct megasas_ctrl_info *pinfo = &a->q.v5.adapinfo;
struct mega_device_list_sas *device;
struct mega_array_config_sas *config = &a->q.v5.config;
a->target.type = MEGA_ADAPTER_V5;
if (megaSasGetDeviceList (&a->target, &(a->q.v5.device)) < 0)
return "cannot retrieve device list";
device = a->q.v5.device;
if (megaSasGetArrayConfig (&a->target, &(a->q.v5.config)) < 0)
return "cannot retrieve array configuration";
if (megaSasGetBatteryInfo (&a->target, &(a->q.v5.battery)) < 0)
return "cannot retrieve battery info";
a->rebuild_rate = pinfo->properties.rebuild_rate;
a->dram_size = pinfo->memory_size;
snprintf (a->name, sizeof (a->name), "a%u", a->target.adapno);
strncpy (a->product, (char *) pinfo->product_name, sizeof (pinfo->product_name));
a->product[sizeof (a->product) - 1] = '\0';
ntrim (a->product);
for (k = 0; k < pinfo->image_component_count; ++k)
{
if (!strcmp (pinfo->image_component[k].name, "BIOS"))
{
strncpy (a->bios, pinfo->image_component[k].version, sizeof (a->bios));
a->bios[sizeof (a->bios) - 1] = '\0';
ntrim (a->bios);
}
else if (!strcmp (pinfo->image_component[k].name, "APP "))
{
strncpy (a->firmware, pinfo->image_component[k].version, sizeof (a->firmware));
a->firmware[sizeof (a->firmware) - 1] = '\0';
ntrim (a->firmware);
}
}
batteryStatus5 (a);
/* Build enclosure map. */
for (k = 0, a->num_channels = 0, a->channel = NULL; k < device->num_devices; ++k)
{
int j;
for (j = 0; j < a->num_channels; ++j)
if (device->device[k].enclosure == a->channel[j])
break;
if (j < a->num_channels)
continue;
/* Didn't find this enclosure; extend the map */
++a->num_channels;
if ((a->channel = (uint8_t *) realloc (a->channel, a->num_channels * sizeof (*a->channel))) == NULL)
return "out of memory (channels)";
a->channel[a->num_channels - 1] = device->device[k].enclosure;
}
qsort (a->channel, a->num_channels, sizeof (*a->channel), cmpChannel);
a->num_physicals = pinfo->pd_present_count;
if ((a->physical = (struct physical_drive_info *) malloc (a->num_physicals * sizeof (*a->physical))) == NULL)
return "out of memory (physical drives)";
memset (a->physical, 0, a->num_physicals * sizeof (*a->physical));
if ((a->physical_list = (struct physical_drive_info **) malloc (a->num_physicals * sizeof (*a->physical_list))) == NULL)
return "out of memory (physical drives)";
memset (a->physical_list, 0, a->num_physicals * sizeof (*a->physical_list));
a->num_logicals = config->header->num_disk_defs;
if ((a->logical = (struct logical_drive_info *) malloc (a->num_logicals * sizeof (*a->logical))) == NULL)
return "out of memory (logical drives)";
memset (a->logical, 0, a->num_logicals * sizeof (*a->logical));
a->num_spans = config->header->num_span_defs;
if ((a->span = (struct span_info *) malloc (a->num_spans * sizeof (*a->span))) == NULL)
return "out of memory (spans)";
memset (a->span, 0, a->num_spans * sizeof (*a->span));
/* Get drive info. (This is fast on a PERC5.) */
for (k = 0; k < device->num_devices; ++k)
if ((device->device[k].type == INQ_DASD) && (getPhysicalDriveInfo (a, device->device[k].device_id, 1) == NULL))
return "cannot get physical device info";
/* Examine all the spans. */
for (k = 0, ms = config->span; k < config->header->num_span_defs; ++k, ++ms)
{
struct span_info *span = &a->span[k];
int i;
span->adapter = a;
span->num_logical_drives = 0;
span->logical_drive = NULL;
span->blocks_per_disk = ms->sectors_per_disk;
span->num_disks = ms->span_size;
if ((span->disk = (struct physical_drive_info **) malloc (span->num_disks * sizeof (*span->disk))) == NULL)
return "out of memory (span -> disk pointers)";
for (i = 0; i < span->num_disks; ++i)
{
span->disk[i] = getPhysicalDriveInfo (a, ms->disk[i].device_id, 1);
span->disk[i]->span = span;
}
}
/* Examine all the logical drives. */
for (k = 0, ml = config->disk; k < config->header->num_disk_defs; ++k, ++ml)
{
struct span_info *span;
struct mega_array_disk_entry_sas *mr;
int j;
struct logical_drive_info *l = &a->logical[k];
l->adapter = a;
snprintf (l->name, sizeof (l->name), "a%ud%u", a->target.adapno, k);
l->target = k;
switch (ml->state)
{
case MEGA_SAS_LD_OFFLINE: l->state = LdStateOffline; break;
case MEGA_SAS_LD_PARTIALLY_DEGRADED: l->state = LdStatePartiallyDegraded; break;
case MEGA_SAS_LD_DEGRADED: l->state = LdStateDegraded; break;
case MEGA_SAS_LD_OPTIMAL: l->state = LdStateOptimal; break;
default: l->state = LdStateUnknown; break;
}
l->raid_level = ml->raid_level;
l->span_size = ml->disks_per_span;
l->num_spans = ml->num_spans;
if ((l->span = (struct span_reference *) malloc (l->num_spans * sizeof (*l->span))) == NULL)
return "out of memory (span references)";
for (j = 0, mr = ml->span; j < ml->num_spans; ++j, ++mr)
{
span = &a->span[mr->span_index];
++(span->num_logical_drives);
if ((span->logical_drive = (struct logical_drive_info **) realloc (span->logical_drive, span->num_logical_drives * sizeof (*span->logical_drive))) == NULL)
return "out of memory (span -> ldrv pointers)";
span->logical_drive[span->num_logical_drives - 1] = l;
l->span[j].offset = mr->offset;
l->span[j].blocks_per_disk = mr->sectors_per_disk;
l->span[j].span = span;
}
}
return NULL;
}
struct adapter_config *getAdapterConfig (int fd, uint8_t adapno, int sas)
{
static struct adapter_config *cf = NULL;
struct adapter_config *a;
char *status;
for (a = cf; a; a = a->next)
if ((a->target.adapno == adapno) && (a->is_sas == sas))
return a;
if ((a = (struct adapter_config *) malloc (sizeof (*a))) == NULL)
return NULL;
memset (a, 0, sizeof (*a));
a->target.fd = fd;
a->target.adapno = adapno;
a->is_sas = sas;
if (sas)
{
if (megaSasGetAdapterProductInfo (fd, adapno, &a->q.v5.adapinfo) < 0)
return NULL;
status = getAdapterConfig5 (a);
}
else
{
mraid_pinfo_t pinfo;
if (megaGetAdapterProductInfo (fd, adapno, &pinfo) < 0)
return NULL;
if (pinfo.data_size == 0)
status = getAdapterConfig2 (a);
else
{
a->q.v3.adapinfo = pinfo;
status = getAdapterConfig3 (a);
}
}
if (status)
{
free (a);
fprintf (stderr, "adapter %d: %s\n", adapno, status);
return NULL;
}
a->next = cf;
cf = a;
return a;
}