www.pudn.com > libscsi.rar > libscsi.c
#include "libscsi.h"
/* ioctl */
struct megascsi_adapter *mega_scsi_adapter;
unsigned char megascsi_adapt_no;
int megascsi_ioctl_initialized = 0;
char dv_xname[] = "PERCSCSI";
unsigned int USCSICMD = 0x80;
void
megascsi_copyhds(scsi_adapter, sizes, props, stats)
struct megascsi_adapter *scsi_adapter;
const unsigned int *sizes;
const unsigned char *props, *stats;
{
int i;
for (i = 0; i < scsi_adapter->adapter_nunits; i++) {
scsi_adapter->adapter_hdr[i].hd_present = 1;
scsi_adapter->adapter_hdr[i].hd_is_logdrv = 1;
scsi_adapter->adapter_hdr[i].hd_size = letoh32(sizes[i]);
scsi_adapter->adapter_hdr[i].hd_prop = props[i];
scsi_adapter->adapter_hdr[i].hd_stat = stats[i];
if (scsi_adapter->adapter_hdr[i].hd_size > 0x200000) {
scsi_adapter->adapter_hdr[i].hd_heads = 255;
scsi_adapter->adapter_hdr[i].hd_secs = 63;
} else {
scsi_adapter->adapter_hdr[i].hd_heads = 64;
scsi_adapter->adapter_hdr[i].hd_secs = 32;
}
}
}
int
megascsi_ioctl_init()
{
int error = 0;
struct utsname uname_buf;
char delimiters[] = ".-";
char *token, cp[128], *tail;
if ( uname(&uname_buf) )return EINVAL;
strncpy(cp, uname_buf.release, 128);
token = strtok(cp, delimiters);
if ( strtol(token, &tail, 0) != 2 ) return EINVAL;
token = strtok(NULL, delimiters);
if ( strtol(token, &tail, 0) == 4 )
USCSICMD = 0xe0; /* kernel 2.4.x */
else if (strtol(token, &tail, 0) == 6 )
USCSICMD = 0x80; /* kernel 2.6.x */
else {
printf("This program not supported on %s\n", uname_buf.release);
return EINVAL;
}
if (!megascsi_ioctl_initialized) {
/* Initialize mega_scsi_adapter structure */
mega_scsi_adapter = malloc(sizeof(struct megascsi_adapter));
if ( mega_scsi_adapter == NULL ) {
printf("MEGA Init Failture: No memory allocation\n");
return EINVAL;
}
memset(mega_scsi_adapter, sizeof(struct megascsi_adapter), 0);
mega_scsi_adapter->adapter_handle = open("/dev/megadev0", O_RDONLY);
if (mega_scsi_adapter->adapter_handle == (uint)-1) {
printf("MEGA Init failture: Can not open device file /dev/megadev0\n");
return EINVAL;
}
megascsi_adapt_no = 0;
mega_scsi_adapter->adapter_adapt_no = megascsi_adapt_no;
megascsi_ioctl_initialized = 1;
}
megascsi_query_adapt(mega_scsi_adapter);
return (error);
}
int
megascsi_query_adapt(scsi_adapter)
struct megascsi_adapter *scsi_adapter;
{
int error = 0, i;
char *p=NULL;
struct megascsi_fc_einquiry *einq;
struct megascsi_fc_prodinfo *pi;
if ( !scsi_adapter ) return EINVAL;
/* try FC inquiry first */
p = malloc(sizeof(struct megascsi_fc_einquiry)+sizeof(struct megascsi_fc_prodinfo));
if (!p) {
printf("%s: No memory for adapter information\n",scsi_adapter->adapter_dev.dv_xname);
return EINVAL;
}
einq = (struct megascsi_fc_einquiry *)p;
pi = (struct megascsi_fc_prodinfo *)(p + sizeof(struct megascsi_fc_einquiry));
memset(einq, 0, sizeof(struct megascsi_fc_einquiry));
memset(pi, 0, sizeof(struct megascsi_fc_prodinfo));
if (megascsi_mgmt(scsi_adapter, MEGASCSI_FCOP, MEGASCSI_FC_EINQ3_SOLICITED_FULL, 0, 0, sizeof (struct megascsi_fc_einquiry), einq)==0) {
scsi_adapter->adapter_nunits = einq->ain_nlogdrv;
megascsi_copyhds(scsi_adapter, einq->ain_ldsize, einq->ain_ldprop,
einq->ain_ldstat);
if (megascsi_mgmt(scsi_adapter, MEGASCSI_FCOP, MEGASCSI_FC_PRODINF, 0, 0, sizeof (struct megascsi_fc_prodinfo), pi)==0) {
scsi_adapter->adapter_maxunits = MEGASCSI_BIG_MAX_LDRIVES;
memcpy(scsi_adapter->adapter_fwver, pi->api_fwver, 16);
scsi_adapter->adapter_fwver[15] = '\0';
memcpy(scsi_adapter->adapter_biosver, pi->api_biosver, 16);
scsi_adapter->adapter_biosver[15] = '\0';
scsi_adapter->adapter_channels = pi->api_channels;
scsi_adapter->adapter_targets = pi->api_fcloops;
scsi_adapter->adapter_memory = letoh16(pi->api_ramsize);
scsi_adapter->adapter_maxcmds = pi->api_maxcmd;
// p = "FC loop";
}
else
{
error = EINVAL;
goto bail2;
}
if (scsi_adapter->adapter_maxunits == 0) {
struct megascsi_inquiry *inq = (struct megascsi_inquiry *)einq;
if (megascsi_mgmt(scsi_adapter, MEGASCSI_EINQUIRY, 0, 0, 0, sizeof(struct megascsi_inquiry) , inq)!=0){
if (megascsi_mgmt(scsi_adapter, MEGASCSI_INQUIRY, 0, 0, 0, sizeof(struct megascsi_inquiry), inq)!=0){
error = EINVAL;
goto bail2;
}
}
scsi_adapter->adapter_maxunits = MEGASCSI_MAX_LDRIVES;
scsi_adapter->adapter_nunits = inq->ain_nlogdrv;
megascsi_copyhds(scsi_adapter, inq->ain_ldsize, inq->ain_ldprop,
inq->ain_ldstat);
memcpy (scsi_adapter->adapter_fwver, inq->ain_fwver, 4);
scsi_adapter->adapter_fwver[4] = '\0';
memcpy (scsi_adapter->adapter_biosver, inq->ain_biosver, 4);
scsi_adapter->adapter_biosver[4] = '\0';
scsi_adapter->adapter_channels = inq->ain_channels;
scsi_adapter->adapter_targets = inq->ain_targets;
scsi_adapter->adapter_memory = inq->ain_ramsize;
scsi_adapter->adapter_maxcmds = inq->ain_maxcmd;
// p = "target";
}
}
else
{
error = EINVAL;
goto bail2;
}
/*
#ifdef MEGASCSI_DEBUG
printf(": FW %s, BIOS v%s, %dMB RAM\n"
"%s: %d channels, %d %ss, %d logical drives, "
"openings %d, max commands %d, quirks: %04x\n",
scsi_adapter->adapter_fwver, scsi_adapter->adapter_biosver, scsi_adapter->adapter_memory,
scsi_adapter->adapter_dev.dv_xname,
scsi_adapter->adapter_channels, scsi_adapter->adapter_targets, p, scsi_adapter->adapter_nunits,
scsi_adapter->adapter_link.openings, scsi_adapter->adapter_maxcmds, scsi_adapter->adapter_flags);
#else
printf(": FW %s, BIOS v%s, %dMB RAM\n"
"%s: %d channels, %d %ss, %d logical drives\n",
scsi_adapter->adapter_fwver, scsi_adapter->adapter_biosver, scsi_adapter->adapter_memory,
scsi_adapter->adapter_dev.dv_xname,
scsi_adapter->adapter_channels, scsi_adapter->adapter_targets, p, scsi_adapter->adapter_nunits);
#endif MEGASCSI_DEBUG */
memcpy(scsi_adapter->adapter_dev.dv_xname, dv_xname, 16);
scsi_adapter->adapter_flags |= MEGASCSI_QUARTZ;
for(i = 0; i < ((scsi_adapter->adapter_flags & MEGASCSI_QUARTZ) ?
MEGASCSI_BIG_MAX_PDRIVES : MEGASCSI_MAX_PDRIVES); i++) {
memcpy(scsi_adapter->adapter_hdr[i].dev, scsi_adapter->adapter_dev.dv_xname, 16);
}
for(i = 0; i < MEGASCSI_MAX_CHANNEL; i++) {
memcpy(scsi_adapter->adapter_rawadapters[i].adapter_procdev, scsi_adapter->adapter_dev.dv_xname, 16);
}
bail2:
if (p) free(p);
return (error);
}
int
megascsi_ioctl_end()
{
int error = 0;
if (mega_scsi_adapter) {
if (mega_scsi_adapter->adapter_handle)
close(mega_scsi_adapter->adapter_handle);
free(mega_scsi_adapter);
megascsi_ioctl_initialized = 0;
}
else
error = EINVAL;
return error;
}
int megascsi_ioctl_sel_adapt(new_adapt_no)
unsigned char new_adapt_no;
{
int old_adapt_no = 0;
if (!mega_scsi_adapter) return EINVAL;
old_adapt_no = mega_scsi_adapter->adapter_adapt_no;
if ( old_adapt_no != new_adapt_no) {
mega_scsi_adapter->adapter_adapt_no = new_adapt_no;
megascsi_query_adapt(mega_scsi_adapter);
}
megascsi_adapt_no = mega_scsi_adapter->adapter_adapt_no;
return old_adapt_no;
}
int
megascsi_ioctl(cmd, addr)
/* struct megascsi_adapter *scsi_adapter;*/
unsigned int cmd;
char * addr;
{
// struct megascsi_adapter *scsi_adapter = (struct megascsi_adapter *)dev;
int error = 0;
switch (cmd) {
case MIOC_INQ:
error = megascsi_ioctl_inq(mega_scsi_adapter, (struct mioc_inq *)addr);
break;
case MIOC_VOL:
error = megascsi_ioctl_vol(mega_scsi_adapter, (struct mioc_vol *)addr);
break;
case MIOC_DISK:
error = megascsi_ioctl_disk(mega_scsi_adapter, (struct mioc_disk *)addr);
break;
default:
error = EINVAL;
}
return (error);
}
int
megascsi_drv_inq(scsi_adapter, ch, tg, page, inqbuf)
struct megascsi_adapter *scsi_adapter;
unsigned char ch;
unsigned char tg;
unsigned char page;
void *inqbuf;
{
mimd_t *mimd;
struct megascsi_iocmd *cmd;
struct megascsi_passthrough *ps;
struct scsi_inquiry_data *pp;
void *idata;
int error = 0;
if (!(idata = malloc(sizeof(mimd_t) + sizeof(struct scsi_inquiry_data)))) {
return (ENOMEM);
}
mimd = (mimd_t *) idata;
memset(mimd, 0, sizeof *mimd);
ps = (struct megascsi_passthrough *)&(mimd->pthru);
pp = idata + sizeof *mimd;
memset(pp, 0, sizeof *pp);
mimd->ui.fcs.opcode = 0x80;
mimd->ui.fcs.adapno = 0x6d00 + scsi_adapter->adapter_adapt_no;
mimd->outlen = sizeof(struct scsi_inquiry_data);
mimd->data = (char *)htole(pp);
cmd = (struct megascsi_iocmd *)&(mimd->mbox);
cmd->acc_cmd = MEGASCSI_PASSTHRU;
cmd->acc_passthru.apt_data = (unsigned int)htole(pp);
ps->apt_channel = ch;
ps->apt_target = tg;
ps->apt_ncdb = sizeof(struct scsi_inquiry);
ps->apt_nsense = sizeof(struct scsi_sense_data);
ps->apt_cdb[0] = INQUIRY;
ps->apt_cdb[1] = 0;
ps->apt_cdb[2] = 0;
ps->apt_cdb[3] = 0;
ps->apt_cdb[4] = sizeof(struct scsi_inquiry_data); /* INQUIRY length */
ps->apt_cdb[5] = 0;
if (page != 0) {
ps->apt_cdb[1] = SI_EVPD;
ps->apt_cdb[2] = page;
}
ps->apt_data = (unsigned int)htole(pp);
ps->apt_datalen = sizeof(struct scsi_inquiry_data);
if (ioctl(scsi_adapter->adapter_handle, USCSICMD, mimd) == 0) {
if (ps->apt_scsistat == 0x00) {
memcpy(inqbuf, pp, sizeof(struct scsi_inquiry_data));
if (pp->device != T_DIRECT)
error = EINVAL;
goto bail;
}
error = EINVAL;
}
else
error = EINVAL;
bail:
free(idata);
return (error);
}
int
megascsi_mgmt(scsi_adapter, opcode, par1, par2, par3, size, buffer)
struct megascsi_adapter *scsi_adapter;
unsigned char opcode;
unsigned char par1;
unsigned char par2;
unsigned char par3;
size_t size;
void *buffer;
{
mimd_t *mimd;
struct megascsi_iocmd *cmd;
void *idata;
void *pa;
int error = 0;
if (!buffer) return (ENOMEM);
if (!(idata = malloc(sizeof(mimd_t)))) {
return (ENOMEM);
}
mimd = (mimd_t *)idata;
memset(mimd, 0, sizeof(mimd_t));
pa = buffer;
mimd->ui.fcs.opcode = 0x80;
mimd->ui.fcs.adapno = 0x6d00 + scsi_adapter->adapter_adapt_no;
mimd->outlen = size;
mimd->data = htole(pa);
cmd = (struct megascsi_iocmd *)&(mimd->mbox);
cmd->acc_cmd = opcode;
/*
* some commands require data to be written to idata before sending
* command to fw
*/
switch (opcode) {
case MEGASCSI_SPEAKER:
*((char *)pa) = par1;
break;
default:
cmd->acc_io.aio_channel = par1;
cmd->acc_io.aio_param = par2;
cmd->acc_io.aio_pad[0] = par3;
};
cmd->acc_io.aio_data = (unsigned int)htole(pa);
if (ioctl(scsi_adapter->adapter_handle, USCSICMD, mimd) == 0) {
/* XXX how do commands fail? */
/* buffer = pa */
/* if (buffer)
memcpy(buffer, pa, size);
*/
}
else
error = EINVAL;
if (idata) free(idata);
return (error);
}
int
megascsi_ioctl_inq(scsi_adapter, bi)
struct megascsi_adapter *scsi_adapter;
struct mioc_inq *bi;
{
struct megascsi_big_diskarray *p; /* struct too large for stack */
char *plist;
int i, s, t;
int off;
int error = 0;
struct scsi_inquiry_data inqbuf;
unsigned char ch, tg;
p = malloc(sizeof(struct megascsi_big_diskarray));
if (!p) {
printf("%s: no memory for disk array\n",scsi_adapter->adapter_dev.dv_xname);
return (ENOMEM);
}
memset(p, 0, sizeof(struct megascsi_big_diskarray));
plist = malloc(MEGASCSI_BIG_MAX_PDRIVES);
if (!plist) {
printf("%s: no memory for disk list\n", scsi_adapter->adapter_dev.dv_xname);
error = ENOMEM;
goto bail;
}
if (megascsi_mgmt(scsi_adapter, MEGASCSI_FCOP, MEGASCSI_FC_RDCONF, 0, 0, sizeof *p, p)) {
error = EINVAL;
goto bail2;
}
memset(plist, 0, MEGASCSI_BIG_MAX_PDRIVES);
bi->bi_novol = p->ada_nld;
bi->bi_nodisk = 0;
strncpy(bi->bi_dev, scsi_adapter->adapter_dev.dv_xname, sizeof(bi->bi_dev));
/* do we actually care how many disks we have at this point? */
for (i = 0; i < p->ada_nld; i++)
for (s = 0; s < p->ald[i].adl_spandepth; s++)
for (t = 0; t < p->ald[i].adl_nstripes; t++) {
off = p->ald[i].asp[s].adv[t].add_channel *
MEGASCSI_MAX_TARGET +
p->ald[i].asp[s].adv[t].add_target;
if (!plist[off]) {
plist[off] = 1;
bi->bi_nodisk++;
}
}
/*
* hack warning!
* Megaraid cards sometimes return a size in the PD structure
* even though there is no disk in that slot. Work around
* that by issuing an INQUIRY to determine if there is
* an actual disk in the slot.
*/
for(i = 0; i < ((scsi_adapter->adapter_flags & MEGASCSI_QUARTZ) ?
MEGASCSI_BIG_MAX_PDRIVES : MEGASCSI_MAX_PDRIVES); i++) {
/* skip claimed drives */
if (plist[i])
continue;
/*
* poke drive to make sure its there. If it is it is either
* unused or a hot spare; at this point we dont care which it is
*/
if (p->apd[i].adp_size) {
ch = (i & 0xf0) >> 4;
tg = i & 0x0f;
if (!megascsi_drv_inq(scsi_adapter, ch, tg, 0, &inqbuf)) {
bi->bi_novol++;
bi->bi_nodisk++;
plist[i] = 1;
}
}
}
bail2:
free(plist);
bail:
free(p);
return (error);
}
int
megascsi_vol(scsi_adapter, bv, p)
struct megascsi_adapter *scsi_adapter;
struct mioc_vol *bv;
struct megascsi_big_diskarray *p;
{
struct scsi_inquiry_data inqbuf;
char *plist;
int i, s, t, off;
int ld = p->ada_nld, error = EINVAL;
unsigned char ch, tg;
plist = malloc(MEGASCSI_BIG_MAX_PDRIVES);
if (!plist) {
printf("%s: no memory for disk list\n",scsi_adapter->adapter_dev.dv_xname);
return (ENOMEM);
}
memset(plist, 0, MEGASCSI_BIG_MAX_PDRIVES);
/* setup plist */
for (i = 0; i < p->ada_nld; i++)
for (s = 0; s < p->ald[i].adl_spandepth; s++)
for (t = 0; t < p->ald[i].adl_nstripes; t++) {
off = p->ald[i].asp[s].adv[t].add_channel *
MEGASCSI_MAX_TARGET +
p->ald[i].asp[s].adv[t].add_target;
if (!plist[off])
plist[off] = 1;
}
for(i = 0; i < ((scsi_adapter->adapter_flags & MEGASCSI_QUARTZ) ?
MEGASCSI_BIG_MAX_PDRIVES : MEGASCSI_MAX_PDRIVES); i++) {
/* skip claimed drives */
if (plist[i])
continue;
/*
* poke drive to make sure its there. If it is it is either
* unused or a hot spare; at this point we dont care which it is
*/
if (p->apd[i].adp_size) {
ch = (i & 0xf0) >> 4;
tg = i & 0x0f;
if (!megascsi_drv_inq(scsi_adapter, ch, tg, 0, &inqbuf)) {
if (ld != bv->bv_volid) {
ld++;
continue;
}
bv->bv_status = MIOC_SVONLINE;
bv->bv_size = (unsigned long long)p->apd[i].adp_size *
(unsigned long long)512;
bv->bv_nodisk = 1;
strncpy(bv->bv_dev,
scsi_adapter->adapter_hdr[bv->bv_volid].dev,
sizeof(bv->bv_dev));
if (p->apd[i].adp_ostatus == MEGASCSI_PD_HOTSPARE
&& p->apd[i].adp_type == 0)
bv->bv_level = -1;
else
bv->bv_level = -2;
error = 0;
goto bail;
}
}
}
bail:
free(plist);
return (error);
}
int
megascsi_disk(scsi_adapter, bd, p)
struct megascsi_adapter *scsi_adapter;
struct mioc_disk *bd;
struct megascsi_big_diskarray *p;
{
struct scsi_inquiry_data inqbuf;
struct scsi_inquiry_vpd vpdbuf;
char *plist;
int i, s, t, off;
int ld = p->ada_nld, error = EINVAL;
unsigned char ch, tg;
plist = malloc(MEGASCSI_BIG_MAX_PDRIVES);
if (!plist) {
printf("%s: no memory for disk list\n",scsi_adapter->adapter_dev.dv_xname);
return (ENOMEM);
}
memset(plist, 0, MEGASCSI_BIG_MAX_PDRIVES);
/* setup plist */
for (i = 0; i < p->ada_nld; i++)
for (s = 0; s < p->ald[i].adl_spandepth; s++)
for (t = 0; t < p->ald[i].adl_nstripes; t++) {
off = p->ald[i].asp[s].adv[t].add_channel *
MEGASCSI_MAX_TARGET +
p->ald[i].asp[s].adv[t].add_target;
if (!plist[off])
plist[off] = 1;
}
for(i = 0; i < ((scsi_adapter->adapter_flags & MEGASCSI_QUARTZ) ?
MEGASCSI_BIG_MAX_PDRIVES : MEGASCSI_MAX_PDRIVES); i++) {
/* skip claimed drives */
if (plist[i])
continue;
/*
* poke drive to make sure its there. If it is it is either
* unused or a hot spare; at this point we dont care which it is
*/
if (p->apd[i].adp_size) {
ch = (i & 0xf0) >> 4;
tg = i & 0x0f;
if (!megascsi_drv_inq(scsi_adapter, ch, tg, 0, &inqbuf)) {
char vend[8+16+4+1];
if (ld != bd->bd_volid) {
ld++;
continue;
}
memcpy(vend, inqbuf.vendor,
sizeof vend - 1);
vend[sizeof vend - 1] = '\0';
strncpy(bd->bd_vendor, vend,
sizeof(bd->bd_vendor));
if (!megascsi_drv_inq(scsi_adapter, ch, tg, 0x80, &vpdbuf)) {
char ser[32 + 1];
memcpy(ser, vpdbuf.serial,
sizeof ser - 1);
ser[sizeof ser - 1] = '\0';
if (vpdbuf.page_length < sizeof ser)
ser[vpdbuf.page_length] = '\0';
strncpy(bd->bd_serial, ser,
sizeof(bd->bd_serial));
}
bd->bd_size = (unsigned long long)p->apd[i].adp_size *
(unsigned long long)512;
bd->bd_channel = ch;
bd->bd_target = tg;
strncpy(bd->bd_procdev,
scsi_adapter->adapter_rawadapters[ch].adapter_procdev,
sizeof(bd->bd_procdev));
if (p->apd[i].adp_ostatus == MEGASCSI_PD_HOTSPARE
&& p->apd[i].adp_type == 0)
bd->bd_status = MIOC_SDHOTSPARE;
else
bd->bd_status = MIOC_SDUNUSED;
error = 0;
goto bail;
}
}
}
bail:
free(plist);
return (error);
}
int
megascsi_ioctl_vol(scsi_adapter, bv)
struct megascsi_adapter *scsi_adapter;
struct mioc_vol *bv;
{
struct megascsi_big_diskarray *p; /* struct too large for stack */
int i, s, t;
int error = 0;
p = malloc(sizeof(struct megascsi_big_diskarray));
if (!p) {
printf("%s: no memory for raw interface\n",scsi_adapter->adapter_dev.dv_xname);
return (ENOMEM);
}
memset(p, 0, sizeof(struct megascsi_big_diskarray));
if (megascsi_mgmt(scsi_adapter, MEGASCSI_FCOP, MEGASCSI_FC_RDCONF, 0, 0, sizeof *p, p)) {
error = EINVAL;
goto bail;
}
if (bv->bv_volid >= p->ada_nld) {
error = megascsi_vol(scsi_adapter, bv, p);
goto bail;
}
i = bv->bv_volid;
switch (p->ald[i].adl_status) {
case MEGASCSI_RDRV_OFFLINE:
bv->bv_status = MIOC_SVOFFLINE;
break;
case MEGASCSI_RDRV_DEGRADED:
bv->bv_status = MIOC_SVDEGRADED;
break;
case MEGASCSI_RDRV_OPTIMAL:
bv->bv_status = MIOC_SVONLINE;
break;
default:
bv->bv_status = MIOC_SVINVALID;
}
bv->bv_size = 0;
bv->bv_level = p->ald[i].adl_raidlvl;
bv->bv_nodisk = 0;
for (s = 0; s < p->ald[i].adl_spandepth; s++) {
for (t = 0; t < p->ald[i].adl_nstripes; t++)
bv->bv_nodisk++;
switch (bv->bv_level) {
case 0:
bv->bv_size += p->ald[i].asp[s].ads_length *
p->ald[i].adl_nstripes;
break;
case 1:
bv->bv_size += p->ald[i].asp[s].ads_length;
break;
case 5:
bv->bv_size += p->ald[i].asp[s].ads_length *
(p->ald[i].adl_nstripes - 1);
break;
}
}
if (p->ald[i].adl_spandepth > 1)
bv->bv_level *= 10;
bv->bv_size *= (unsigned long long)512;
strncpy(bv->bv_dev, scsi_adapter->adapter_hdr[i].dev, sizeof(bv->bv_dev));
bail:
free(p);
return (error);
}
int
megascsi_ioctl_disk(scsi_adapter, bd)
struct megascsi_adapter *scsi_adapter;
struct mioc_disk *bd;
{
struct scsi_inquiry_data inqbuf;
struct scsi_inquiry_vpd vpdbuf;
struct megascsi_big_diskarray *p; /* struct too large for stack */
int i, s, t, d;
int off;
int error = 0;
unsigned short ch, tg;
p = malloc(sizeof(struct megascsi_big_diskarray));
if (!p) {
printf("%s: no memory for raw interface\n",scsi_adapter->adapter_dev.dv_xname);
return (ENOMEM);
}
memset(p, 0, sizeof(struct megascsi_big_diskarray));
if (megascsi_mgmt(scsi_adapter, MEGASCSI_FCOP, MEGASCSI_FC_RDCONF, 0, 0, sizeof *p, p)) {
error = EINVAL;
goto bail;
}
if (bd->bd_volid >= p->ada_nld) {
error = megascsi_disk(scsi_adapter, bd, p);
goto bail;
}
i = bd->bd_volid;
error = EINVAL;
for (s = 0, d = 0; s < p->ald[i].adl_spandepth; s++)
for (t = 0; t < p->ald[i].adl_nstripes; t++) {
if (d != bd->bd_diskid) {
d++;
continue;
}
off = p->ald[i].asp[s].adv[t].add_channel *
MEGASCSI_MAX_TARGET +
p->ald[i].asp[s].adv[t].add_target;
switch (p->apd[off].adp_ostatus) {
case MEGASCSI_PD_UNCNF:
bd->bd_status = MIOC_SDUNUSED;
break;
case MEGASCSI_PD_ONLINE:
bd->bd_status = MIOC_SDONLINE;
break;
case MEGASCSI_PD_FAILED:
bd->bd_status = MIOC_SDFAILED;
break;
case MEGASCSI_PD_RBLD:
bd->bd_status = MIOC_SDREBUILD;
break;
case MEGASCSI_PD_HOTSPARE:
bd->bd_status = MIOC_SDHOTSPARE;
break;
default:
bd->bd_status = MIOC_SDINVALID;
}
bd->bd_size = (unsigned long long)p->apd[off].adp_size *
(unsigned long long)512;
ch = p->ald[i].asp[s].adv[t].add_target >> 4;
tg = p->ald[i].asp[s].adv[t].add_target & 0x0f;
if (!megascsi_drv_inq(scsi_adapter, ch, tg, 0, &inqbuf)) {
char vend[8+16+4+1];
memcpy(vend, inqbuf.vendor, sizeof vend - 1);
vend[sizeof vend - 1] = '\0';
strncpy(bd->bd_vendor, vend,
sizeof(bd->bd_vendor));
}
if (!megascsi_drv_inq(scsi_adapter, ch, tg, 0x80, &vpdbuf)) {
char ser[32 + 1];
memcpy(ser, vpdbuf.serial, sizeof ser - 1);
ser[sizeof ser - 1] = '\0';
if (vpdbuf.page_length < sizeof ser)
ser[vpdbuf.page_length] = '\0';
strncpy(bd->bd_serial, ser,
sizeof(bd->bd_serial));
}
bd->bd_channel = ch;
bd->bd_target = tg;
strncpy(bd->bd_procdev, scsi_adapter->adapter_rawadapters[ch].adapter_procdev,
sizeof(bd->bd_procdev));
error = 0;
goto bail;
}
/* XXX if we reach this do dedicated hotspare magic*/
bail:
free(p);
return (error);
}