X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fblock%2Fcciss_scsi.c;h=e1233aabda771493718b5f37f9228e00301098e3;hb=2fdc86901d2ab30a12402b46238951d2a7891590;hp=4aca7ddfdddf9c242730d9cb625eb7b23486f4c3;hpb=b91cba52e9b7b3f1c0037908a192d93a869ca9e5;p=linux-2.6 diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 4aca7ddfdd..e1233aabda 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -1,20 +1,20 @@ /* - * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module - * Copyright 2001 Compaq Computer Corporation + * Disk Array driver for HP Smart Array controllers, SCSI Tape module. + * (C) Copyright 2001, 2007 Hewlett-Packard Development Company, L.P. * * 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 of the License, or - * (at your option) any later version. + * the Free Software Foundation; version 2 of the License. * * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more details. + * 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; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 59 Temple Place, Suite 300, Boston, MA + * 02111-1307, USA. * * Questions/Comments/Bugfixes to iss_storagedev@hp.com * @@ -358,23 +358,68 @@ find_bus_target_lun(int ctlr, int *bus, int *target, int *lun) } return (!found); } +struct scsi2map { + char scsi3addr[8]; + int bus, target, lun; +}; static int cciss_scsi_add_entry(int ctlr, int hostno, - unsigned char *scsi3addr, int devtype) + unsigned char *scsi3addr, int devtype, + struct scsi2map *added, int *nadded) { /* assumes hba[ctlr]->scsi_ctlr->lock is held */ int n = ccissscsi[ctlr].ndevices; struct cciss_scsi_dev_t *sd; + int i, bus, target, lun; + unsigned char addr1[8], addr2[8]; if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) { printk("cciss%d: Too many devices, " "some will be inaccessible.\n", ctlr); return -1; } + + bus = target = -1; + lun = 0; + /* Is this device a non-zero lun of a multi-lun device */ + /* byte 4 of the 8-byte LUN addr will contain the logical unit no. */ + if (scsi3addr[4] != 0) { + /* Search through our list and find the device which */ + /* has the same 8 byte LUN address, excepting byte 4. */ + /* Assign the same bus and target for this new LUN. */ + /* Use the logical unit number from the firmware. */ + memcpy(addr1, scsi3addr, 8); + addr1[4] = 0; + for (i = 0; i < n; i++) { + sd = &ccissscsi[ctlr].dev[i]; + memcpy(addr2, sd->scsi3addr, 8); + addr2[4] = 0; + /* differ only in byte 4? */ + if (memcmp(addr1, addr2, 8) == 0) { + bus = sd->bus; + target = sd->target; + lun = scsi3addr[4]; + break; + } + } + } + sd = &ccissscsi[ctlr].dev[n]; - if (find_bus_target_lun(ctlr, &sd->bus, &sd->target, &sd->lun) != 0) - return -1; + if (lun == 0) { + if (find_bus_target_lun(ctlr, + &sd->bus, &sd->target, &sd->lun) != 0) + return -1; + } else { + sd->bus = bus; + sd->target = target; + sd->lun = lun; + } + added[*nadded].bus = sd->bus; + added[*nadded].target = sd->target; + added[*nadded].lun = sd->lun; + (*nadded)++; + memcpy(&sd->scsi3addr[0], scsi3addr, 8); sd->devtype = devtype; ccissscsi[ctlr].ndevices++; @@ -390,7 +435,8 @@ cciss_scsi_add_entry(int ctlr, int hostno, } static void -cciss_scsi_remove_entry(int ctlr, int hostno, int entry) +cciss_scsi_remove_entry(int ctlr, int hostno, int entry, + struct scsi2map *removed, int *nremoved) { /* assumes hba[ctlr]->scsi_ctlr->lock is held */ int i; @@ -398,6 +444,10 @@ cciss_scsi_remove_entry(int ctlr, int hostno, int entry) if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return; sd = ccissscsi[ctlr].dev[entry]; + removed[*nremoved].bus = sd.bus; + removed[*nremoved].target = sd.target; + removed[*nremoved].lun = sd.lun; + (*nremoved)++; for (i=entry;iscsi_ctlr)->scsi_host; + /* find any devices in ccissscsi[] that are not in sd[] and remove them from ccissscsi[] */ i = 0; + nremoved = 0; + nadded = 0; while(idevtype), hostno, csd->bus, csd->target, csd->lun); */ - cciss_scsi_remove_entry(ctlr, hostno, i); - /* note, i not incremented */ + cciss_scsi_remove_entry(ctlr, hostno, i, + removed, &nremoved); + /* remove ^^^, hence i not incremented */ } else if (found == 1) { /* device is different kind */ changes++; @@ -464,8 +555,15 @@ adjust_cciss_scsi_table(int ctlr, int hostno, "(device type now %s).\n", ctlr, hostno, csd->bus, csd->target, csd->lun, scsi_device_type(csd->devtype)); + cciss_scsi_remove_entry(ctlr, hostno, i, + removed, &nremoved); + /* remove ^^^, hence i not incremented */ + if (cciss_scsi_add_entry(ctlr, hostno, + &sd[j].scsi3addr[0], sd[j].devtype, + added, &nadded) != 0) + /* we just removed one, so add can't fail. */ + BUG(); csd->devtype = sd[j].devtype; - i++; /* so just move along. */ } else /* device is same as it ever was, */ i++; /* so just move along. */ } @@ -489,7 +587,9 @@ adjust_cciss_scsi_table(int ctlr, int hostno, if (!found) { changes++; if (cciss_scsi_add_entry(ctlr, hostno, - &sd[i].scsi3addr[0], sd[i].devtype) != 0) + + &sd[i].scsi3addr[0], sd[i].devtype, + added, &nadded) != 0) break; } else if (found == 1) { /* should never happen... */ @@ -501,9 +601,50 @@ adjust_cciss_scsi_table(int ctlr, int hostno, } CPQ_TAPE_UNLOCK(ctlr, flags); - if (!changes) - printk("cciss%d: No device changes detected.\n", ctlr); + /* Don't notify scsi mid layer of any changes the first time through */ + /* (or if there are no changes) scsi_scan_host will do it later the */ + /* first time through. */ + if (hostno == -1 || !changes) + goto free_and_out; + + /* Notify scsi mid layer of any removed devices */ + for (i = 0; i < nremoved; i++) { + struct scsi_device *sdev = + scsi_device_lookup(sh, removed[i].bus, + removed[i].target, removed[i].lun); + if (sdev != NULL) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } else { + /* We don't expect to get here. */ + /* future cmds to this device will get selection */ + /* timeout as if the device was gone. */ + printk(KERN_WARNING "cciss%d: didn't find " + "c%db%dt%dl%d\n for removal.", + ctlr, hostno, removed[i].bus, + removed[i].target, removed[i].lun); + } + } + + /* Notify scsi mid layer of any added devices */ + for (i = 0; i < nadded; i++) { + int rc; + rc = scsi_add_device(sh, added[i].bus, + added[i].target, added[i].lun); + if (rc == 0) + continue; + printk(KERN_WARNING "cciss%d: scsi_add_device " + "c%db%dt%dl%d failed, device not added.\n", + ctlr, hostno, + added[i].bus, added[i].target, added[i].lun); + /* now we have to remove it from ccissscsi, */ + /* since it didn't get added to scsi mid layer */ + fixup_botched_add(ctlr, added[i].scsi3addr); + } +free_and_out: + kfree(added); + kfree(removed); return 0; } @@ -1349,35 +1490,9 @@ cciss_unregister_scsi(int ctlr) /* set scsi_host to NULL so our detect routine will find us on register */ sa->scsi_host = NULL; + spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); scsi_cmd_stack_free(ctlr); kfree(sa); - spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); -} - -static int -cciss_register_scsi(int ctlr) -{ - unsigned long flags; - - CPQ_TAPE_LOCK(ctlr, flags); - - /* Since this is really a block driver, the SCSI core may not be - initialized at init time, in which case, calling scsi_register_host - would hang. Instead, we do it later, via /proc filesystem - and rc scripts, when we know SCSI core is good to go. */ - - /* Only register if SCSI devices are detected. */ - if (ccissscsi[ctlr].ndevices != 0) { - ((struct cciss_scsi_adapter_data_t *) - hba[ctlr]->scsi_ctlr)->registered = 1; - CPQ_TAPE_UNLOCK(ctlr, flags); - return cciss_scsi_detect(ctlr); - } - CPQ_TAPE_UNLOCK(ctlr, flags); - printk(KERN_INFO - "cciss%d: No appropriate SCSI device detected, " - "SCSI subsystem not engaged.\n", ctlr); - return 0; } static int @@ -1391,34 +1506,31 @@ cciss_engage_scsi(int ctlr) sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; stk = &sa->cmd_stack; - if (((struct cciss_scsi_adapter_data_t *) - hba[ctlr]->scsi_ctlr)->registered) { + if (sa->registered) { printk("cciss%d: SCSI subsystem already engaged.\n", ctlr); spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); return ENXIO; } + sa->registered = 1; spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); cciss_update_non_disk_devices(ctlr, -1); - cciss_register_scsi(ctlr); + cciss_scsi_detect(ctlr); return 0; } static void -cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len) +cciss_seq_tape_report(struct seq_file *seq, int ctlr) { unsigned long flags; - int size; - - *pos = *pos -1; *len = *len - 1; // cut off the last trailing newline CPQ_TAPE_LOCK(ctlr, flags); - size = sprintf(buffer + *len, + seq_printf(seq, "Sequential access devices: %d\n\n", ccissscsi[ctlr].ndevices); CPQ_TAPE_UNLOCK(ctlr, flags); - *pos += size; *len += size; } + /* Need at least one of these error handlers to keep ../scsi/hosts.c from * complaining. Doing a host- or bus-reset can't do anything good here. * Despite what it might say in scsi_error.c, there may well be commands @@ -1453,7 +1565,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], TYPE_MSG); - /* sendcmd turned off interrputs on the board, turn 'em back on. */ + /* sendcmd turned off interrupts on the board, turn 'em back on. */ (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); if (rc == 0) return SUCCESS; @@ -1483,7 +1595,7 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) 0, 2, 0, 0, (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], TYPE_MSG); - /* sendcmd turned off interrputs on the board, turn 'em back on. */ + /* sendcmd turned off interrupts on the board, turn 'em back on. */ (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); if (rc == 0) return SUCCESS; @@ -1496,8 +1608,5 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) /* If no tape support, then these become defined out of existence */ #define cciss_scsi_setup(cntl_num) -#define cciss_unregister_scsi(ctlr) -#define cciss_register_scsi(ctlr) -#define cciss_proc_tape_report(ctlr, buffer, pos, len) #endif /* CONFIG_CISS_SCSI_TAPE */