/* How long to wait for CISS doorbell communication */ #define CLEAR_EVENT_WAIT_INTERVAL 20/* ms for each msleep() call */ #define MODE_CHANGE_WAIT_INTERVAL 10/* ms for each msleep() call */ #define MAX_CLEAR_EVENT_WAIT 30000/* times 20 ms = 600 s */ #define MAX_MODE_CHANGE_WAIT 2000/* times 10 ms = 20 s */ #define MAX_IOCTL_CONFIG_WAIT 1000
/*define how many times we will try a command because of bus resets */ #define MAX_CMD_RETRIES 3 /* How long to wait before giving up on a command */ #define HPSA_EH_PTRAID_TIMEOUT (240 * HZ)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Hewlett-Packard Company");
MODULE_DESCRIPTION("Driver for HP Smart Array Controller version " \
HPSA_DRIVER_VERSION);
MODULE_VERSION(HPSA_DRIVER_VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS("cciss");
staticint hpsa_simple_mode;
module_param(hpsa_simple_mode, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(hpsa_simple_mode, "Use 'simple mode' rather than 'performant mode'");
switch (asc) { case STATE_CHANGED:
dev_warn(&h->pdev->dev, "%s: a state change detected, command retried\n",
h->devname); break; case LUN_FAILED:
dev_warn(&h->pdev->dev, "%s: LUN failure detected\n", h->devname); break; case REPORT_LUNS_CHANGED:
dev_warn(&h->pdev->dev, "%s: report LUN data changed\n", h->devname); /* *Note:thisREPORT_LUNS_CHANGEDconditiononlyoccursontheexternal *target(array)devices.
*/ break; case POWER_OR_RESET:
dev_warn(&h->pdev->dev, "%s: a power on or device reset detected\n",
h->devname); break; case UNIT_ATTENTION_CLEARED:
dev_warn(&h->pdev->dev, "%s: unit attention cleared by another initiator\n",
h->devname); break; default:
dev_warn(&h->pdev->dev, "%s: unknown unit attention detected\n",
h->devname); break;
} return1;
}
sdev = to_scsi_device(dev);
h = sdev_to_hba(sdev);
spin_lock_irqsave(&h->lock, flags);
hdev = sdev->hostdata; if (!hdev) {
spin_unlock_irqrestore(&h->lock, flags); return -ENODEV;
}
/* Is this even a logical drive? */ if (!is_logical_device(hdev)) {
spin_unlock_irqrestore(&h->lock, flags);
l = snprintf(buf, PAGE_SIZE, "N/A\n"); return l;
}
sdev = to_scsi_device(dev);
h = sdev_to_hba(sdev);
spin_lock_irqsave(&h->devlock, flags);
hdev = sdev->hostdata; if (!hdev) {
spin_unlock_irqrestore(&h->devlock, flags); return -ENODEV;
}
bay = hdev->bay; for (i = 0; i < MAX_PATHS; i++) {
path_map_index = 1<<i; if (i == hdev->active_path_index)
active = "Active"; elseif (hdev->path_map & path_map_index)
active = "Inactive"; else continue;
/* Tell the controller to post the reply to the queue for this *processor.ThisseemstogivethebestI/Othroughput.
*/
cp->reply_queue = reply_queue; /* Set the bits in the address sent down to include: *-performantmodebitnotusedinioaccelmode2 *-pullcount(bits0-3) *-commandtypeisn'tneededforioaccel2
*/
c->busaddr |= h->ioaccel2_blockFetchTable[0];
}
staticinlineint is_scsi_rev_5(struct ctlr_info *h)
{ if (!h->hba_inquiry_data) return0; if ((h->hba_inquiry_data[2] & 0x07) == 5) return1; return0;
}
staticint hpsa_find_target_lun(struct ctlr_info *h, unsignedchar scsi3addr[], int bus, int *target, int *lun)
{ /* finds an unused bus, target, lun for a new physical device *assumesh->devlockisheld
*/ int i, found = 0;
DECLARE_BITMAP(lun_taken, HPSA_MAX_DEVICES);
bitmap_zero(lun_taken, HPSA_MAX_DEVICES);
for (i = 0; i < h->ndevices; i++) { if (h->dev[i]->bus == bus && h->dev[i]->target != -1)
__set_bit(h->dev[i]->target, lun_taken);
}
i = find_first_zero_bit(lun_taken, HPSA_MAX_DEVICES); if (i < HPSA_MAX_DEVICES) { /* *bus = 1; */
*target = i;
*lun = 0;
found = 1;
} return !found;
}
/* Add an entry into h->dev[] array. */ staticint hpsa_scsi_add_entry(struct ctlr_info *h, struct hpsa_scsi_dev_t *device, struct hpsa_scsi_dev_t *added[], int *nadded)
{ /* assumes h->devlock is held */ int n = h->ndevices; int i; unsignedchar addr1[8], addr2[8]; struct hpsa_scsi_dev_t *sd;
if (n >= HPSA_MAX_DEVICES) {
dev_err(&h->pdev->dev, "too many devices, some will be " "inaccessible.\n"); return -1;
}
/* physical devices do not have lun or target assigned until now. */ if (device->lun != -1) /* Logical device, lun is already assigned. */ goto lun_assigned;
/* If this device a non-zero lun of a multi-lun device *byte4ofthe8-byteLUNaddrwillcontainthelogical *unitno,zerootherwise.
*/ if (device->scsi3addr[4] == 0) { /* This is not a non-zero lun of a multi-lun device */ if (hpsa_find_target_lun(h, device->scsi3addr,
device->bus, &device->target, &device->lun) != 0) return -1; goto lun_assigned;
}
/* This is a non-zero lun of a multi-lun device. *Searchthroughourlistandfindthedevicewhich *hasthesame8byteLUNaddress,exceptingbyte4and5. *AssignthesamebusandtargetforthisnewLUN. *Usethelogicalunitnumberfromthefirmware.
*/
memcpy(addr1, device->scsi3addr, 8);
addr1[4] = 0;
addr1[5] = 0; for (i = 0; i < n; i++) {
sd = h->dev[i];
memcpy(addr2, sd->scsi3addr, 8);
addr2[4] = 0;
addr2[5] = 0; /* differ only in byte 4 and 5? */ if (memcmp(addr1, addr2, 8) == 0) {
device->bus = sd->bus;
device->target = sd->target;
device->lun = device->scsi3addr[4]; break;
}
} if (device->lun == -1) {
dev_warn(&h->pdev->dev, "physical device with no LUN=0," " suspect firmware bug or unsupported hardware " "configuration.\n"); return -1;
}
/* Remove an entry from h->dev[] array. */ staticvoid hpsa_scsi_remove_entry(struct ctlr_info *h, int entry, struct hpsa_scsi_dev_t *removed[], int *nremoved)
{ /* assumes h->devlock is held */ int i; struct hpsa_scsi_dev_t *sd;
staticvoid fixup_botched_add(struct ctlr_info *h, struct hpsa_scsi_dev_t *added)
{ /* called when scsi_add_device fails in order to re-adjust *h->dev[]tomatchthemidlayer'sview.
*/ unsignedlong flags; int i, j;
spin_lock_irqsave(&h->lock, flags); for (i = 0; i < h->ndevices; i++) { if (h->dev[i] == added) { for (j = i; j < h->ndevices-1; j++)
h->dev[j] = h->dev[j+1];
h->ndevices--; break;
}
}
spin_unlock_irqrestore(&h->lock, flags);
kfree(added);
}
staticinlineint device_is_the_same(struct hpsa_scsi_dev_t *dev1, struct hpsa_scsi_dev_t *dev2)
{ /* we compare everything except lun and target as these *arenotyetassigned.Comparepartslikely *todifferfirst
*/ if (memcmp(dev1->scsi3addr, dev2->scsi3addr, sizeof(dev1->scsi3addr)) != 0) return0; if (memcmp(dev1->device_id, dev2->device_id, sizeof(dev1->device_id)) != 0) return0; if (memcmp(dev1->model, dev2->model, sizeof(dev1->model)) != 0) return0; if (memcmp(dev1->vendor, dev2->vendor, sizeof(dev1->vendor)) != 0) return0; if (dev1->devtype != dev2->devtype) return0; if (dev1->bus != dev2->bus) return0; return1;
}
staticinlineint device_updated(struct hpsa_scsi_dev_t *dev1, struct hpsa_scsi_dev_t *dev2)
{ /* Device attributes that can change, but don't mean *thatthedeviceisadifferentdevice,northattheOS *needstobetoldanythingaboutthechange.
*/ if (dev1->raid_level != dev2->raid_level) return1; if (dev1->offload_config != dev2->offload_config) return1; if (dev1->offload_to_be_enabled != dev2->offload_to_be_enabled) return1; if (!is_logical_dev_addr_mode(dev1->scsi3addr)) if (dev1->queue_depth != dev2->queue_depth) return1; /* *Thiscanhappenfordualdomaindevices.Anactive *pathchangecausestheioaccelhandletochange * *forexamplenotethehandledifferencesbetweenp0andp1 *DeviceWWN,WWNhash,Handle *D016p0|0x3[02]P2E:01:01,0x5000C5005FC4DACA,0x9B5616,0x01030003 *p10x5000C5005FC4DAC9,0x6798C0,0x00040004
*/ if (dev1->ioaccel_handle != dev2->ioaccel_handle) return1; return0;
}
/* Find needle in haystack. If exact match found, return DEVICE_SAME, *andreturnneedlelocationin*index.Ifscsi3addrmatches,butnot *vendor,model,serialnum,etc.returnDEVICE_CHANGED,andreturnneedle *locationin*index. *Inthecaseofaminordeviceattributechange,suchasRAIDlevel,just *returnDEVICE_UPDATED,alongwiththeupdateddevice'slocationinindex. *Ifneedlenotfound,returnDEVICE_NOT_FOUND.
*/ staticint hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle, struct hpsa_scsi_dev_t *haystack[], int haystack_size, int *index)
{ int i; #define DEVICE_NOT_FOUND 0 #define DEVICE_CHANGED 1 #define DEVICE_SAME 2 #define DEVICE_UPDATED 3 if (needle == NULL) return DEVICE_NOT_FOUND;
for (i = 0; i < haystack_size; i++) { if (haystack[i] == NULL) /* previously removed. */ continue; if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
*index = i; if (device_is_the_same(needle, haystack[i])) { if (device_updated(needle, haystack[i])) return DEVICE_UPDATED; return DEVICE_SAME;
} else { /* Keep offline devices offline */ if (needle->volume_offline) return DEVICE_NOT_FOUND; return DEVICE_CHANGED;
}
}
}
*index = -1; return DEVICE_NOT_FOUND;
}
/* Check to see if device is already on the list */
spin_lock_irqsave(&h->offline_device_lock, flags);
list_for_each_entry(device, &h->offline_device_list, offline_list) { if (memcmp(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr)) == 0) {
spin_unlock_irqrestore(&h->offline_device_lock, flags); return;
}
}
spin_unlock_irqrestore(&h->offline_device_lock, flags);
/* Device is not on the list, add it. */
device = kmalloc(sizeof(*device), GFP_KERNEL); if (!device) return;
/* Print a message explaining various offline volume states */ staticvoid hpsa_show_volume_status(struct ctlr_info *h, struct hpsa_scsi_dev_t *sd)
{ if (sd->volume_offline == HPSA_VPD_LV_STATUS_UNSUPPORTED)
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume status is not available through vital product data pages.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); switch (sd->volume_offline) { case HPSA_LV_OK: break; case HPSA_LV_UNDERGOING_ERASE:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is undergoing background erase process.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_NOT_AVAILABLE:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is waiting for transforming volume.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_UNDERGOING_RPI:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is undergoing rapid parity init.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_PENDING_RPI:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is queued for rapid parity initialization process.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_ENCRYPTED_NO_KEY:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is encrypted and cannot be accessed because key is not present.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is not encrypted and cannot be accessed because controller is in encryption-only mode.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_UNDERGOING_ENCRYPTION:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is undergoing encryption process.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is undergoing encryption re-keying process.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is encrypted and cannot be accessed because controller does not have encryption enabled.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_PENDING_ENCRYPTION:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is pending migration to encrypted state, but process has not started.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break; case HPSA_LV_PENDING_ENCRYPTION_REKEYING:
dev_info(&h->pdev->dev, "C%d:B%d:T%d:L%d Volume is encrypted and is pending encryption rekeying.\n",
h->scsi_host->host_no,
sd->bus, sd->target, sd->lun); break;
}
}
/* *Figurethelistofphysicaldrivepointersforalogicaldrivewith *raidoffloadconfigured.
*/ staticvoid hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev[], int ndevices, struct hpsa_scsi_dev_t *logical_drive)
{ struct raid_map_data *map = &logical_drive->raid_map; struct raid_map_disk_data *dd = &map->data[0]; int i, j; int total_disks_per_row = le16_to_cpu(map->data_disks_per_row) +
le16_to_cpu(map->metadata_disks_per_row); int nraid_map_entries = le16_to_cpu(map->row_cnt) *
le16_to_cpu(map->layout_map_count) *
total_disks_per_row; int nphys_disk = le16_to_cpu(map->layout_map_count) *
total_disks_per_row; int qdepth;
if (nraid_map_entries > RAID_MAP_MAX_ENTRIES)
nraid_map_entries = RAID_MAP_MAX_ENTRIES;
qdepth = 0; for (i = 0; i < nraid_map_entries; i++) {
logical_drive->phys_disk[i] = NULL; if (!logical_drive->offload_config) continue; for (j = 0; j < ndevices; j++) { if (dev[j] == NULL) continue; if (dev[j]->devtype != TYPE_DISK &&
dev[j]->devtype != TYPE_ZBC) continue; if (is_logical_device(dev[j])) continue; if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle) continue;
logical_drive->phys_disk[i] = dev[j]; if (i < nphys_disk)
qdepth = min(h->nr_cmds, qdepth +
logical_drive->phys_disk[i]->queue_depth); break;
}
/* *Thiscanhappenifaphysicaldriveisremovedand *thelogicaldriveisdegraded.Inthatcase,theRAID *mapdatawillrefertoaphysicaldiskwhichisn'tactually *present.Andinthatcaseoffload_enabledshouldalready *be0,butwe'llturnitoffherejustincase
*/ if (!logical_drive->phys_disk[i]) {
dev_warn(&h->pdev->dev, "%s: [%d:%d:%d:%d] A phys disk component of LV is missing, turning off offload_enabled for LV.\n",
__func__,
h->scsi_host->host_no, logical_drive->bus,
logical_drive->target, logical_drive->lun);
hpsa_turn_off_ioaccel_for_device(logical_drive);
logical_drive->queue_depth = 8;
}
} if (nraid_map_entries) /* *Thisiscorrectforreads,toohighforfullstripewrites, *waytoohighforpartialstripewrites
*/
logical_drive->queue_depth = qdepth; else { if (logical_drive->external)
logical_drive->queue_depth = EXTERNAL_QD; else
logical_drive->queue_depth = h->nr_cmds;
}
}
staticvoid hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev[], int ndevices)
{ int i;
for (i = 0; i < ndevices; i++) { if (dev[i] == NULL) continue; if (dev[i]->devtype != TYPE_DISK &&
dev[i]->devtype != TYPE_ZBC) continue; if (!is_logical_device(dev[i])) continue;
if (!added || !removed) {
dev_warn(&h->pdev->dev, "out of memory in " "adjust_hpsa_scsi_table\n"); goto free_and_out;
}
spin_lock_irqsave(&h->devlock, flags);
/* find any devices in h->dev[] that are not in *sd[]andremovethemfromh->dev[],andforany *deviceswhichhavechanged,removetheolddevice *infoandaddthenewdeviceinfo. *Ifminordeviceattributeschange,justupdate *theexistingdevicestructure.
*/
i = 0;
nremoved = 0;
nadded = 0; while (i < h->ndevices) {
csd = h->dev[i];
device_change = hpsa_scsi_find_entry(csd, sd, nsds, &entry); if (device_change == DEVICE_NOT_FOUND) {
changes++;
hpsa_scsi_remove_entry(h, i, removed, &nremoved); continue; /* remove ^^^, hence i not incremented */
} elseif (device_change == DEVICE_CHANGED) {
changes++;
hpsa_scsi_replace_entry(h, i, sd[entry],
added, &nadded, removed, &nremoved); /* Set it to NULL to prevent it from being freed *atthebottomofhpsa_update_scsi_devices()
*/
sd[entry] = NULL;
} elseif (device_change == DEVICE_UPDATED) {
hpsa_scsi_update_entry(h, i, sd[entry]);
}
i++;
}
/* Now, make sure every device listed in sd[] is also *listedinh->dev[],addingthemiftheyaren'tfound
*/
for (i = 0; i < nsds; i++) { if (!sd[i]) /* if already added above. */ continue;
/* Don't add devices which are NOT READY, FORMAT IN PROGRESS *astheSCSImid-layerdoesnothandlesuchdeviceswell. *ItrelentlesslyloopssendingTURat3Hz,thenREAD(10) *at160Hz,andpreventsthesystemfromcomingup.
*/ if (sd[i]->volume_offline) {
hpsa_show_volume_status(h, sd[i]);
hpsa_show_dev_msg(KERN_INFO, h, sd[i], "offline"); continue;
}
device_change = hpsa_scsi_find_entry(sd[i], h->dev,
h->ndevices, &entry); if (device_change == DEVICE_NOT_FOUND) {
changes++; if (hpsa_scsi_add_entry(h, sd[i], added, &nadded) != 0) break;
sd[i] = NULL; /* prevent from being freed later. */
} elseif (device_change == DEVICE_CHANGED) { /* should never happen... */
changes++;
dev_warn(&h->pdev->dev, "device unexpectedly changed.\n"); /* but if it does happen, we just ignore that device */
}
}
hpsa_update_log_drive_phys_drive_ptrs(h, h->dev, h->ndevices);
/* *Nowthath->dev[]->phys_disk[]iscoherent,wecanenable *anylogicaldrivesthatneeditenabled. * *Theraidmapshouldbecurrentbynow. * *WeareupdatingthedevicelistusedforI/Orequests.
*/ for (i = 0; i < h->ndevices; i++) { if (h->dev[i] == NULL) continue;
h->dev[i]->offload_enabled = h->dev[i]->offload_to_be_enabled;
}
spin_unlock_irqrestore(&h->devlock, flags);
/* Monitor devices which are in one of several NOT READY states to be *broughtonlinelater.Thismustbedonewithoutholdingh->devlock, *sodon'ttouchh->dev[]
*/ for (i = 0; i < nsds; i++) { if (!sd[i]) /* if already added above. */ continue; if (sd[i]->volume_offline)
hpsa_monitor_offline_device(h, sd[i]->scsi3addr);
}
/* Don't notify scsi mid layer of any changes the first time through *(oriftherearenochanges)scsi_scan_hostwilldoitlaterthe *firsttimethrough.
*/ if (!changes) goto free_and_out;
/* Notify scsi mid layer of any removed devices */ for (i = 0; i < nremoved; i++) { if (removed[i] == NULL) continue; if (removed[i]->expose_device)
hpsa_remove_device(h, removed[i]);
kfree(removed[i]);
removed[i] = NULL;
}
/* Notify scsi mid layer of any added devices */ for (i = 0; i < nadded; i++) { int rc = 0;
if (added[i] == NULL) continue; if (!(added[i]->expose_device)) continue;
rc = hpsa_add_device(h, added[i]); if (!rc) continue;
dev_warn(&h->pdev->dev, "addition failed %d, device not added.", rc); /* now we have to remove it from h->dev, *sinceitdidn'tgetaddedtoscsimidlayer
*/
fixup_botched_add(h, added[i]);
h->drv_req_rescan = 1;
}
free_and_out:
kfree(added);
kfree(removed);
}
/* *Lookupbus/target/lunandreturncorrespondingstructhpsa_scsi_dev_t* *Assume'sh->devlockisheld.
*/ staticstruct hpsa_scsi_dev_t *lookup_hpsa_scsi_dev(struct ctlr_info *h, int bus, int target, int lun)
{ int i; struct hpsa_scsi_dev_t *sd;
for (i = 0; i < h->ndevices; i++) {
sd = h->dev[i]; if (sd->bus == bus && sd->target == target && sd->lun == lun) return sd;
} return NULL;
}
staticvoid hpsa_free_sg_chain_blocks(struct ctlr_info *h)
{ int i;
if (!h->cmd_sg_list) return; for (i = 0; i < h->nr_cmds; i++) {
kfree(h->cmd_sg_list[i]);
h->cmd_sg_list[i] = NULL;
}
kfree(h->cmd_sg_list);
h->cmd_sg_list = NULL;
}
staticint hpsa_alloc_sg_chain_blocks(struct ctlr_info *h)
{ int i;
if (h->chainsize <= 0) return0;
h->cmd_sg_list = kcalloc(h->nr_cmds, sizeof(*h->cmd_sg_list),
GFP_KERNEL); if (!h->cmd_sg_list) return -ENOMEM;
for (i = 0; i < h->nr_cmds; i++) {
h->cmd_sg_list[i] = kmalloc_array(h->chainsize, sizeof(*h->cmd_sg_list[i]),
GFP_KERNEL); if (!h->cmd_sg_list[i]) goto clean;
switch (tmf_status) { case CISS_TMF_COMPLETE: /* *CISS_TMF_COMPLETEneverhappens,instead, *ei->CommandStatus==0forthiscase.
*/ case CISS_TMF_SUCCESS: return0; case CISS_TMF_INVALID_FRAME: case CISS_TMF_NOT_SUPPORTED: case CISS_TMF_FAILED: case CISS_TMF_WRONG_LUN: case CISS_TMF_OVERLAPPED_TAG: break; default:
dev_warn(&h->pdev->dev, "Unknown TMF status: 0x%02x\n",
tmf_status); break;
} return -tmf_status;
}
/* *Wecheckforlockupstatushereasitmaybesetfor *CMD_SCSI,CMD_IOACCEL1andCMD_IOACCEL2commandsby *fail_all_oustanding_cmds()
*/ if (unlikely(ei->CommandStatus == CMD_CTLR_LOCKUP)) { /* DID_NO_CONNECT will prevent a retry */
cmd->result = DID_NO_CONNECT << 16; return hpsa_cmd_free_and_done(h, cp, cmd);
}
if (cp->cmd_type == CMD_IOACCEL2) return process_ioaccel2_completion(h, cp, cmd, dev);
scsi_set_resid(cmd, ei->ResidualCnt); if (ei->CommandStatus == 0) return hpsa_cmd_free_and_done(h, cp, cmd);
/* For I/O accelerator commands, copy over some fields to the normal *CISSheaderusedbelowforerrorhandling.
*/ if (cp->cmd_type == CMD_IOACCEL1) { struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex];
cp->Header.SGList = scsi_sg_count(cmd);
cp->Header.SGTotal = cpu_to_le16(cp->Header.SGList);
cp->Request.CDBLen = le16_to_cpu(c->io_flags) &
IOACCEL1_IOFLAGS_CDBLEN_MASK;
cp->Header.tag = c->tag;
memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8);
memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen);
/* Any RAID offload error results in retry which will use *thenormalI/Opathsothecontrollercanhandlewhatever's *wrong.
*/ if (is_logical_device(dev)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED)
dev->offload_enabled = 0; return hpsa_retry_cmd(h, cp);
}
}
/* an error has occurred */ switch (ei->CommandStatus) {
case CMD_TARGET_STATUS:
cmd->result |= ei->ScsiStatus; /* copy the sense data */ if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo))
sense_data_size = SCSI_SENSE_BUFFERSIZE; else
sense_data_size = sizeof(ei->SenseInfo); if (ei->SenseLen < sense_data_size)
sense_data_size = ei->SenseLen;
memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size); if (ei->ScsiStatus)
decode_sense_data(ei->SenseInfo, sense_data_size,
&sense_key, &asc, &ascq); if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) { switch (sense_key) { case ABORTED_COMMAND:
cmd->result |= DID_SOFT_ERROR << 16; break; case UNIT_ATTENTION: if (asc == 0x3F && ascq == 0x0E)
h->drv_req_rescan = 1; break; case ILLEGAL_REQUEST: if (asc == 0x25 && ascq == 0x00) {
dev->removed = 1;
cmd->result = DID_NO_CONNECT << 16;
} break;
} break;
} /* Problem was not a check condition *Passituptotheupperlayers...
*/ if (ei->ScsiStatus) {
dev_warn(&h->pdev->dev, "cp %p has status 0x%x " "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, " "Returning result: 0x%x\n",
cp, ei->ScsiStatus,
sense_key, asc, ascq,
cmd->result);
} else { /* scsi status is zero??? How??? */
dev_warn(&h->pdev->dev, "cp %p SCSI status was 0. " "Returning no connection.\n", cp),
/* Ordinarily, this case should never happen, *butthereisabuginsomereleasedfirmware *revisionsthatallowsittohappenif,for *example,a4100backplanelosespowerand *thetapedriveisinit.Weassumethat *it'safatalerrorofsomekindbecausewe *can'tshowthatitwasn't.Wewillmakeit *looklikeselectiontimeoutsincethatis *themostcommonreasonforthistooccur, *andit'ssevereenough.
*/
cmd->result = DID_NO_CONNECT << 16;
} break;
case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ break; case CMD_DATA_OVERRUN:
dev_warn(&h->pdev->dev, "CDB %16phN data overrun\n", cp->Request.CDB); break; case CMD_INVALID: { /* print_bytes(cp, sizeof(*cp), 1, 0);
print_cmd(cp); */ /* We get CMD_INVALID if you address a non-existent device *insteadofaselectiontimeout(noresponse).Youwill *seethisifyouyankoutadrive,thentrytoaccessit. *Thisiskindofashamebecauseitmeansthatanyother *CMD_INVALID(e.g.driverbug)willgetinterpretedasa
* missing target. */
cmd->result = DID_NO_CONNECT << 16;
} break; case CMD_PROTOCOL_ERR:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "CDB %16phN : protocol error\n",
cp->Request.CDB); break; case CMD_HARDWARE_ERR:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "CDB %16phN : hardware error\n",
cp->Request.CDB); break; case CMD_CONNECTION_LOST:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "CDB %16phN : connection lost\n",
cp->Request.CDB); break; case CMD_ABORTED:
cmd->result = DID_ABORT << 16; break; case CMD_ABORT_FAILED:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n",
cp->Request.CDB); break; case CMD_UNSOLICITED_ABORT:
cmd->result = DID_SOFT_ERROR << 16; /* retry the command */
dev_warn(&h->pdev->dev, "CDB %16phN : unsolicited abort\n",
cp->Request.CDB); break; case CMD_TIMEOUT:
cmd->result = DID_TIME_OUT << 16;
dev_warn(&h->pdev->dev, "CDB %16phN timed out\n",
cp->Request.CDB); break; case CMD_UNABORTABLE:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "Command unabortable\n"); break; case CMD_TMF_STATUS: if (hpsa_evaluate_tmf_status(h, cp)) /* TMF failed? */
cmd->result = DID_ERROR << 16; break; case CMD_IOACCEL_DISABLED: /* This only handles the direct pass-through case since RAID *offloadishandledabove.Justattemptaretry.
*/
cmd->result = DID_SOFT_ERROR << 16;
dev_warn(&h->pdev->dev, "cp %p had HP SSD Smart Path error\n", cp); break; default:
cmd->result = DID_ERROR << 16;
dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n",
cp, ei->CommandStatus);
}
return hpsa_cmd_free_and_done(h, cp, cmd);
}
staticvoid hpsa_pci_unmap(struct pci_dev *pdev, struct CommandList *c, int sg_used, enum dma_data_direction data_direction)
{ int i;
for (i = 0; i < sg_used; i++)
dma_unmap_single(&pdev->dev, le64_to_cpu(c->SG[i].Addr),
le32_to_cpu(c->SG[i].Len),
data_direction);
}
/* fill_cmd can't fail here, no data buffer to map. */
(void) fill_cmd(c, reset_type, h, NULL, 0, 0, dev->scsi3addr, TYPE_MSG);
rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) {
dev_warn(&h->pdev->dev, "Failed to send reset command\n"); goto out;
} /* no unmap needed here because no data xfer. */
ei = c->err_info; if (ei->CommandStatus != 0) {
hpsa_scsi_interpret_error(h, c);
rc = -1;
}
out:
cmd_free(h, c); return rc;
}
switch (c->cmd_type) { case CMD_SCSI: case CMD_IOCTL_PEND:
match = !memcmp(scsi3addr, &c->Header.LUN.LunAddrBytes, sizeof(c->Header.LUN.LunAddrBytes)); break;
case CMD_IOACCEL1: case CMD_IOACCEL2: if (c->phys_disk == dev) { /* HBA mode match */
match = true;
} else { /* Possible RAID mode -- check each phys dev. */ /* FIXME: Do we need to take out a lock here? If *so,wecouldjustcallhpsa_get_pdisk_of_ioaccel2()
* instead. */ for (i = 0; i < dev->nphysical_disks && !match; i++) { /* FIXME: an alternate test might be * *match=dev->phys_disk[i]->ioaccel_handle
* == c2->scsi_nexus; */
match = dev->phys_disk[i] == c->phys_disk;
}
} break;
case IOACCEL2_TMF: for (i = 0; i < dev->nphysical_disks && !match; i++) {
match = dev->phys_disk[i]->ioaccel_handle ==
le32_to_cpu(ac->it_nexus);
} break;
case0: /* The command is in the middle of being initialized. */
match = false; break;
staticint hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev,
u8 reset_type, int reply_queue)
{ int rc = 0;
/* We can really only handle one reset at a time */ if (mutex_lock_interruptible(&h->reset_mutex) == -EINTR) {
dev_warn(&h->pdev->dev, "concurrent reset wait interrupted.\n"); return -EINTR;
}
rc = hpsa_send_reset(h, dev, reset_type, reply_queue); if (!rc) { /* incremented by sending the reset request */
atomic_dec(&dev->commands_outstanding);
wait_event(h->event_sync_wait_queue,
atomic_read(&dev->commands_outstanding) <= 0 ||
lockup_detected(h));
}
if (unlikely(lockup_detected(h))) {
dev_warn(&h->pdev->dev, "Controller lockup detected during reset wait\n");
rc = -ENODEV;
}
if (!rc)
rc = wait_for_device_to_become_ready(h, dev->scsi3addr, 0);
for (i = 0; i < nphysicals; i++) { if (physdev->LUN[i].device_type ==
BMIC_DEVICE_TYPE_CONTROLLER
&& !is_hba_lunid(physdev->LUN[i].lunid)) {
dev_info(&h->pdev->dev, "External controller present, activate discovery polling and disable rld caching\n");
hpsa_disable_rld_caching(h);
h->discovery_polling = 1; break;
}
}
}
/* Get a device id from inquiry page 0x83 */ staticbool hpsa_vpd_page_supported(struct ctlr_info *h, unsignedchar scsi3addr[], u8 page)
{ int rc; int i; int pages; unsignedchar *buf, bufsize;
buf = kzalloc(256, GFP_KERNEL); if (!buf) returnfalse;
/* Get the size of the page list first */
rc = hpsa_scsi_do_inquiry(h, scsi3addr,
VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
buf, HPSA_VPD_HEADER_SZ); if (rc != 0) goto exit_unsupported;
pages = buf[3]; if ((pages + HPSA_VPD_HEADER_SZ) <= 255)
bufsize = pages + HPSA_VPD_HEADER_SZ; else
bufsize = 255;
/* Get the whole VPD page list */
rc = hpsa_scsi_do_inquiry(h, scsi3addr,
VPD_PAGE | HPSA_VPD_SUPPORTED_PAGES,
buf, bufsize); if (rc != 0) goto exit_unsupported;
pages = buf[3]; for (i = 1; i <= pages; i++) if (buf[3 + i] == page) goto exit_supported;
exit_unsupported:
kfree(buf); returnfalse;
exit_supported:
kfree(buf); returntrue;
}
/* Get the device id from inquiry page 0x83 */ staticint hpsa_get_device_id(struct ctlr_info *h, unsignedchar *scsi3addr, unsignedchar *device_id, int index, int buflen)
{ int rc; unsignedchar *buf;
/* Does controller have VPD for device id? */ if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_DEVICE_ID)) return1; /* not supported */
buf = kzalloc(64, GFP_KERNEL); if (!buf) return -ENOMEM;
staticinlinevoid hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device, int bus, int target, int lun)
{
device->bus = bus;
device->target = target;
device->lun = lun;
}
/* Use VPD inquiry to get details of volume status */ staticint hpsa_get_volume_status(struct ctlr_info *h, unsignedchar scsi3addr[])
{ int rc; int status; int size; unsignedchar *buf;
buf = kzalloc(64, GFP_KERNEL); if (!buf) return HPSA_VPD_LV_STATUS_UNSUPPORTED;
/* Does controller have VPD for logical volume status? */ if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_STATUS)) goto exit_failed;
/* Get the size of the VPD return buffer */
rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,
buf, HPSA_VPD_HEADER_SZ); if (rc != 0) goto exit_failed;
size = buf[3];
/* Now get the whole VPD buffer */
rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | HPSA_VPD_LV_STATUS,
buf, size + HPSA_VPD_HEADER_SZ); if (rc != 0) goto exit_failed;
status = buf[4]; /* status byte */
/* Determine the reason for not ready state */
ldstat = hpsa_get_volume_status(h, scsi3addr);
/* Keep volume offline in certain cases: */ switch (ldstat) { case HPSA_LV_FAILED: case HPSA_LV_UNDERGOING_ERASE: case HPSA_LV_NOT_AVAILABLE: case HPSA_LV_UNDERGOING_RPI: case HPSA_LV_PENDING_RPI: case HPSA_LV_ENCRYPTED_NO_KEY: case HPSA_LV_PLAINTEXT_IN_ENCRYPT_ONLY_CONTROLLER: case HPSA_LV_UNDERGOING_ENCRYPTION: case HPSA_LV_UNDERGOING_ENCRYPTION_REKEYING: case HPSA_LV_ENCRYPTED_IN_NON_ENCRYPTED_CONTROLLER: return ldstat; case HPSA_VPD_LV_STATUS_UNSUPPORTED: /* If VPD status page isn't available, *useASC/ASCQtodeterminestate
*/ if ((ascq == ASCQ_LUN_NOT_READY_FORMAT_IN_PROGRESS) ||
(ascq == ASCQ_LUN_NOT_READY_INITIALIZING_CMD_REQ)) return ldstat; break; default: break;
} return HPSA_LV_OK;
}
/* Do an inquiry to the device to see what it is. */ if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
(unsignedchar) OBDR_TAPE_INQ_SIZE) != 0) {
dev_err(&h->pdev->dev, "%s: inquiry failed, device will be skipped.\n",
__func__);
rc = HPSA_INQUIRY_FAILED; goto bail_out;
}
if (this_device->external)
this_device->queue_depth = EXTERNAL_QD;
if (is_OBDR_device) { /* See if this is a One-Button-Disaster-Recovery device *bylookingfor"$DR-10"atoffset43ininquirydata.
*/
obdr_sig = &inq_buff[OBDR_SIG_OFFSET];
*is_OBDR_device = (this_device->devtype == TYPE_ROM &&
strncmp(obdr_sig, OBDR_TAPE_SIG,
OBDR_SIG_LEN) == 0);
}
kfree(inq_buff); return0;
if (!is_logical_dev_addr_mode(lunaddrbytes)) { /* physical device, target and lun filled in later */ if (is_hba_lunid(lunaddrbytes)) { int bus = HPSA_HBA_BUS;
staticint figure_external_status(struct ctlr_info *h, int raid_ctlr_position, int i, int nphysicals, int nlocal_logicals)
{ /* In report logicals, local logicals are listed first, *thenanyexternals.
*/ int logicals_start = nphysicals + (raid_ctlr_position == 0);
if (i == raid_ctlr_position) return0;
if (i < logicals_start) return0;
/* i is in logicals range, but still within local logicals */ if ((i - nphysicals - (raid_ctlr_position == 0)) < nlocal_logicals) return0;
static u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i, int nphysicals, int nlogicals, struct ReportExtendedLUNdata *physdev_list, struct ReportLUNdata *logdev_list)
{ /* Helper function, figure out where the LUN ID info is coming from *givenindexi,listsofphysicalandlogicaldevices,wherein *thelisttheraidcontrollerissupposedtoappear(firstorlast)
*/
int logicals_start = nphysicals + (raid_ctlr_position == 0); int last_device = nphysicals + nlogicals + (raid_ctlr_position == 0);
if (i == raid_ctlr_position) return RAID_CTLR_LUNID;
if (i < logicals_start) return &physdev_list->LUN[i -
(raid_ctlr_position == 0)].lunid[0];
if (i < last_device) return &logdev_list->LUN[i - nphysicals -
(raid_ctlr_position == 0)][0];
BUG(); return NULL;
}
/* get physical drive ioaccel handle and queue depth */ staticvoid hpsa_get_ioaccel_drive_info(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, struct ReportExtendedLUNdata *rlep, int rle_index, struct bmic_identify_physical_device *id_phys)
{ int rc; struct ext_report_lun_entry *rle;
if (rle_index < 0 || rle_index >= HPSA_MAX_PHYS_LUN) return;
/* get number of local logical disks. */ staticint hpsa_set_local_logical_count(struct ctlr_info *h, struct bmic_identify_controller *id_ctlr,
u32 *nlocals)
{ int rc;
/* Set number of local logicals (non PTRAID) */ if (hpsa_set_local_logical_count(h, id_ctlr, &nlocal_logicals)) {
dev_warn(&h->pdev->dev, "%s: Can't determine number of local logical devices.\n",
__func__);
}
/* We might see up to the maximum number of logical and physical disks *plusexternaltargetdevices,andadeviceforthelocalRAID *controller.
*/
ndevs_to_allocate = nphysicals + nlogicals + MAX_EXT_TARGETS + 1;
hpsa_ext_ctrl_present(h, physdev_list);
/* Allocate the per device structures */ for (i = 0; i < ndevs_to_allocate; i++) { if (i >= HPSA_MAX_DEVICES) {
dev_warn(&h->pdev->dev, "maximum devices (%d) exceeded." " %d devices ignored.\n", HPSA_MAX_DEVICES,
ndevs_to_allocate - HPSA_MAX_DEVICES); break;
}
/* adjust our table of devices */ for (i = 0; i < nphysicals + nlogicals + 1; i++) {
u8 *lunaddrbytes, is_OBDR = 0; int rc = 0; int phys_dev_index = i - (raid_ctlr_position == 0); bool skip_device = false;
memset(tmpdevice, 0, sizeof(*tmpdevice));
physical_device = i < nphysicals + (raid_ctlr_position == 0);
/* Figure out where the LUN ID info is coming from */
lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
i, nphysicals, nlogicals, physdev_list, logdev_list);
/* Determine if this is a lun from an external target array */
tmpdevice->external =
figure_external_status(h, raid_ctlr_position, i,
nphysicals, nlocal_logicals);
/* *GettheSASaddressforphysicaldevicesthatareexposed.
*/ if (this_device->physical_device && this_device->expose_device)
hpsa_get_sas_address(h, lunaddrbytes, this_device);
switch (this_device->devtype) { case TYPE_ROM: /* We don't *really* support actual CD-ROM devices, *just"OneButtonDisasterRecovery"tapedrive *whichtemporarilypretendstobeaCD-ROMdrive. *SowecheckthatthedeviceisreallyanOBDRtape *devicebycheckingfor"$DR-10"inbytes43-48of *theinquirydata.
*/ if (is_OBDR)
ncurrent++; break; case TYPE_DISK: case TYPE_ZBC: if (this_device->physical_device) { /* The disk is in HBA mode. */ /* Never use RAID mapper in HBA mode. */
this_device->offload_enabled = 0;
hpsa_get_ioaccel_drive_info(h, this_device,
physdev_list, phys_dev_index, id_phys);
hpsa_get_path_info(this_device,
physdev_list, phys_dev_index, id_phys);
}
ncurrent++; break; case TYPE_TAPE: case TYPE_MEDIUM_CHANGER:
ncurrent++; break; case TYPE_ENCLOSURE: if (!this_device->external)
hpsa_get_enclosure_info(h, lunaddrbytes,
physdev_list, phys_dev_index,
this_device);
ncurrent++; break; case TYPE_RAID: /* Only present the Smartarray HBA as a RAID controller. *Ifit'saRAIDcontrollerotherthantheHBAitself *(anexternalRAIDcontroller,MSA500orsimilar) *don'tpresentit.
*/ if (!is_hba_lunid(lunaddrbytes)) break;
ncurrent++; break; default: break;
} if (ncurrent >= HPSA_MAX_DEVICES) break;
}
if (h->sas_host == NULL) { int rc = 0;
rc = hpsa_add_sas_host(h); if (rc) {
dev_warn(&h->pdev->dev, "Could not add sas host %d\n", rc); goto out;
}
}
adjust_hpsa_scsi_table(h, currentsd, ncurrent);
out:
kfree(tmpdevice); for (i = 0; i < ndev_allocated; i++)
kfree(currentsd[i]);
kfree(currentsd);
kfree(physdev_list);
kfree(logdev_list);
kfree(id_ctlr);
kfree(id_phys);
}
/* Block zero-length transfer sizes on certain commands. */ switch (cdb[0]) { case READ_10: case WRITE_10: case VERIFY: /* 0x2F */ case WRITE_VERIFY: /* 0x2E */
block_cnt = get_unaligned_be16(&cdb[7]); break; case READ_12: case WRITE_12: case VERIFY_12: /* 0xAF */ case WRITE_VERIFY_12: /* 0xAE */
block_cnt = get_unaligned_be32(&cdb[6]); break; case READ_16: case WRITE_16: case VERIFY_16: /* 0x8F */
block_cnt = get_unaligned_be32(&cdb[10]); break; default: returnfalse;
}
return block_cnt == 0;
}
staticint fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
{ int is_write = 0;
u32 block;
u32 block_cnt;
/* Perform some CDB fixups if needed using 10 byte reads/writes only */ switch (cdb[0]) { case WRITE_6: case WRITE_12:
is_write = 1;
fallthrough; case READ_6: case READ_12: if (*cdb_len == 6) {
block = (((cdb[1] & 0x1F) << 16) |
(cdb[2] << 8) |
cdb[3]);
block_cnt = cdb[4]; if (block_cnt == 0)
block_cnt = 256;
} else {
BUG_ON(*cdb_len != 12);
block = get_unaligned_be32(&cdb[2]);
block_cnt = get_unaligned_be32(&cdb[6]);
} if (block_cnt > 0xffff) return IO_ACCEL_INELIGIBLE;
if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE;
}
c->cmd_type = CMD_IOACCEL1;
/* Adjust the DMA address to point to the accelerated command buffer */
c->busaddr = (u32) h->ioaccel_cmd_pool_dhandle +
(c->cmdindex * sizeof(*cp));
BUG_ON(c->busaddr & 0x0000007F);
switch (cmd->sc_data_direction) { case DMA_TO_DEVICE:
control |= IOACCEL1_CONTROL_DATA_OUT; break; case DMA_FROM_DEVICE:
control |= IOACCEL1_CONTROL_DATA_IN; break; case DMA_NONE:
control |= IOACCEL1_CONTROL_NODATAXFER; break; default:
dev_err(&h->pdev->dev, "unknown data direction: %d\n",
cmd->sc_data_direction);
BUG(); break;
}
} else {
control |= IOACCEL1_CONTROL_NODATAXFER;
}
c->Header.SGList = use_sg; /* Fill out the command structure to submit */
cp->dev_handle = cpu_to_le16(ioaccel_handle & 0xFFFF);
cp->transfer_len = cpu_to_le32(total_len);
cp->io_flags = cpu_to_le16(IOACCEL1_IOFLAGS_IO_REQ |
(cdb_len & IOACCEL1_IOFLAGS_CDBLEN_MASK));
cp->control = cpu_to_le32(control);
memcpy(cp->CDB, cdb, cdb_len);
memcpy(cp->CISS_LUN, scsi3addr, 8); /* Tag was already set at init time. */
enqueue_cmd_and_start_io(h, c); return0;
}
/* Are we doing encryption on this device */ if (!(le16_to_cpu(map->flags) & RAID_MAP_FLAG_ENCRYPT_ON)) return; /* Set the data encryption key index. */
cp->dekindex = map->dekindex;
/* Set the encryption enable flag, encoded into direction field. */
cp->direction |= IOACCEL2_DIRECTION_ENCRYPT_MASK;
/* Set encryption tweak values based on logical block address *Ifblocksizeis512,tweakvalueisLBA. *Forotherblocksizes,tweakis(LBA*blocksize)/512)
*/ switch (cmd->cmnd[0]) { /* Required? 6-byte cdbs eliminated by fixup_ioaccel_cdb */ case READ_6: case WRITE_6:
first_block = (((cmd->cmnd[1] & 0x1F) << 16) |
(cmd->cmnd[2] << 8) |
cmd->cmnd[3]); break; case WRITE_10: case READ_10: /* Required? 12-byte cdbs eliminated by fixup_ioaccel_cdb */ case WRITE_12: case READ_12:
first_block = get_unaligned_be32(&cmd->cmnd[2]); break; case WRITE_16: case READ_16:
first_block = get_unaligned_be64(&cmd->cmnd[2]); break; default:
dev_err(&h->pdev->dev, "ERROR: %s: size (0x%x) not supported for encryption\n",
__func__, cmd->cmnd[0]);
BUG(); break;
}
if (le32_to_cpu(map->volume_blk_size) != 512)
first_block = first_block *
le32_to_cpu(map->volume_blk_size)/512;
/* Try to honor the device's queue depth */ if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) >
phys_disk->queue_depth) {
atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE;
} if (h->transMethod & CFGTBL_Trans_io_accel1) return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle,
cdb, cdb_len, scsi3addr,
phys_disk); else return hpsa_scsi_ioaccel2_queue_command(h, c, ioaccel_handle,
cdb, cdb_len, scsi3addr,
phys_disk);
}
staticvoid raid_map_helper(struct raid_map_data *map, int offload_to_mirror, u32 *map_index, u32 *current_group)
{ if (offload_to_mirror == 0) { /* use physical disk in the first mirrored group. */
*map_index %= le16_to_cpu(map->data_disks_per_row); return;
} do { /* determine mirror group that *map_index indicates */
*current_group = *map_index /
le16_to_cpu(map->data_disks_per_row); if (offload_to_mirror == *current_group) continue; if (*current_group < le16_to_cpu(map->layout_map_count) - 1) { /* select map index from next group */
*map_index += le16_to_cpu(map->data_disks_per_row);
(*current_group)++;
} else { /* select map index from first group */
*map_index %= le16_to_cpu(map->data_disks_per_row);
*current_group = 0;
}
} while (offload_to_mirror != *current_group);
}
/* if this isn't a single row/column then give to the controller */ if ((first_row != last_row) || (first_column != last_column)) return IO_ACCEL_INELIGIBLE;
switch (dev->raid_level) { case HPSA_RAID_0: break; /* nothing special to do */ case HPSA_RAID_1: /* Handles load balance across RAID 1 members. *(2-driveR1andR10witheven#ofdrives.) *AppropriateforSSDs,notoptimalforHDDs *Ensurewehavethecorrectraid_map.
*/ if (le16_to_cpu(map->layout_map_count) != 2) {
hpsa_turn_off_ioaccel_for_device(dev); return IO_ACCEL_INELIGIBLE;
} if (dev->offload_to_mirror)
map_index += le16_to_cpu(map->data_disks_per_row);
dev->offload_to_mirror = !dev->offload_to_mirror; break; case HPSA_RAID_ADM: /* Handles N-way mirrors (R1-ADM) *andR10with#ofdrivesdivisibleby3.) *Ensurewehavethecorrectraid_map.
*/ if (le16_to_cpu(map->layout_map_count) != 3) {
hpsa_turn_off_ioaccel_for_device(dev); return IO_ACCEL_INELIGIBLE;
}
offload_to_mirror = dev->offload_to_mirror;
raid_map_helper(map, offload_to_mirror,
&map_index, ¤t_group); /* set mirror group to use next time */
offload_to_mirror =
(offload_to_mirror >=
le16_to_cpu(map->layout_map_count) - 1)
? 0 : offload_to_mirror + 1;
dev->offload_to_mirror = offload_to_mirror; /* Avoid direct use of dev->offload_to_mirror within this *functionsincemultiplethreadsmightsimultaneously *incrementitbeyondtherangeofdev->layout_map_count-1.
*/ break; case HPSA_RAID_5: case HPSA_RAID_6: if (le16_to_cpu(map->layout_map_count) <= 1) break;
/* Verify first and last block are in same RAID group */
r5or6_blocks_per_row =
le16_to_cpu(map->strip_size) *
le16_to_cpu(map->data_disks_per_row); if (r5or6_blocks_per_row == 0) {
hpsa_turn_off_ioaccel_for_device(dev); return IO_ACCEL_INELIGIBLE;
}
stripesize = r5or6_blocks_per_row *
le16_to_cpu(map->layout_map_count); #if BITS_PER_LONG == 32
tmpdiv = first_block;
first_group = do_div(tmpdiv, stripesize);
tmpdiv = first_group;
(void) do_div(tmpdiv, r5or6_blocks_per_row);
first_group = tmpdiv;
tmpdiv = last_block;
last_group = do_div(tmpdiv, stripesize);
tmpdiv = last_group;
(void) do_div(tmpdiv, r5or6_blocks_per_row);
last_group = tmpdiv; #else
first_group = (first_block % stripesize) / r5or6_blocks_per_row;
last_group = (last_block % stripesize) / r5or6_blocks_per_row; #endif if (first_group != last_group) return IO_ACCEL_INELIGIBLE;
c->Request.Timeout = 0;
BUG_ON(cmd->cmd_len > sizeof(c->Request.CDB));
c->Request.CDBLen = cmd->cmd_len;
memcpy(c->Request.CDB, cmd->cmnd, cmd->cmd_len); switch (cmd->sc_data_direction) { case DMA_TO_DEVICE:
c->Request.type_attr_dir =
TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_WRITE); break; case DMA_FROM_DEVICE:
c->Request.type_attr_dir =
TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_READ); break; case DMA_NONE:
c->Request.type_attr_dir =
TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_NONE); break; case DMA_BIDIRECTIONAL: /* This can happen if a buggy application does a scsi passthru *andsetsbothinlenandoutlentonon-zero.(see *../scsi/scsi_ioctl.c:scsi_ioctl_send_command())
*/
c->Request.type_attr_dir =
TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_RSVD); /* This is technically wrong, and hpsa controllers should *rejectitwithCMD_INVALID,whichisthemostcorrect *response,butnon-fibrebackendsappeartoletit *slideby,andgivethesameresultsasifthisfield *weresetcorrectly.Eitherwayisacceptablefor *ourpurposeshere.
*/
break;
default:
dev_err(&h->pdev->dev, "unknown data direction: %d\n",
cmd->sc_data_direction);
BUG(); break;
}
if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */
hpsa_cmd_resolve_and_free(h, c); return SCSI_MLQUEUE_HOST_BUSY;
}
if (dev->in_reset) {
hpsa_cmd_resolve_and_free(h, c); return SCSI_MLQUEUE_HOST_BUSY;
}
c->device = dev;
enqueue_cmd_and_start_io(h, c); /* the cmd'll come back via intr handler in complete_scsi_command() */ return0;
}
/* wait until any scan already in progress is finished. */ while (1) {
spin_lock_irqsave(&h->scan_lock, flags); if (h->scan_finished) break;
h->scan_waiting = 1;
spin_unlock_irqrestore(&h->scan_lock, flags);
wait_event(h->scan_wait_queue, h->scan_finished); /* Note: We don't need to worry about a race between this *threadanddriverunloadbecausethemidlayerwill *haveincrementedthereferencecount,sounloadwon't *happenifwe'reinhere.
*/
}
h->scan_finished = 0; /* mark scan as in progress */
h->scan_waiting = 0;
spin_unlock_irqrestore(&h->scan_lock, flags);
if (unlikely(lockup_detected(h))) return hpsa_scan_complete(h);
/* Offset to leave space for internal cmds. */ return idx += HPSA_NRESERVED_CMDS;
}
/* *SendaTEST_UNIT_READYcommandtothespecifiedLUNusingthespecified *replyqueue;returnszeroiftheunitisready,andnon-zerootherwise.
*/ staticint hpsa_send_test_unit_ready(struct ctlr_info *h, struct CommandList *c, unsignedchar lunaddr[], int reply_queue)
{ int rc;
/* Send the Test Unit Ready, fill_cmd can't fail, no mapping */
(void) fill_cmd(c, TEST_UNIT_READY, h,
NULL, 0, 0, lunaddr, TYPE_CMD);
rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) return rc; /* no unmap needed here because no data xfer. */
/* Check if the unit is already ready. */ if (c->err_info->CommandStatus == CMD_SUCCESS) return0;
rc = hpsa_send_test_unit_ready(h, c, lunaddr, reply_queue); if (!rc) break;
/* Increase wait time with each try, up to a point. */ if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS)
waittime *= 2;
dev_warn(&h->pdev->dev, "waiting %d secs for device to become ready.\n",
waittime);
}
return rc;
}
staticint wait_for_device_to_become_ready(struct ctlr_info *h, unsignedchar lunaddr[], int reply_queue)
{ int first_queue; int last_queue; int rq; int rc = 0; struct CommandList *c;
for (rq = first_queue; rq <= last_queue; rq++) {
rc = hpsa_wait_for_test_unit_ready(h, c, lunaddr, rq); if (rc) break;
}
if (rc)
dev_warn(&h->pdev->dev, "giving up on device.\n"); else
dev_warn(&h->pdev->dev, "device is ready.\n");
cmd_free(h, c); return rc;
}
/* Need at least one of these error handlers to keep ../scsi/hosts.c from *complaining.Doingahost-orbus-resetcan'tdoanythinggoodhere.
*/ staticint hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
{ int rc = SUCCESS; int i; struct ctlr_info *h; struct hpsa_scsi_dev_t *dev = NULL;
u8 reset_type; char msg[48]; unsignedlong flags;
/* find the controller to which the command to be aborted was sent */
h = sdev_to_hba(scsicmd->device); if (h == NULL) /* paranoia */ return FAILED;
/* if controller locked up, we can guarantee command won't complete */ if (lockup_detected(h)) {
snprintf(msg, sizeof(msg), "cmd %d RESET FAILED, lockup detected",
hpsa_get_cmd_index(scsicmd));
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
rc = FAILED; goto return_reset_status;
}
/* this reset request might be the result of a lockup; check */ if (detect_controller_lockup(h)) {
snprintf(msg, sizeof(msg), "cmd %d RESET FAILED, new lockup detected",
hpsa_get_cmd_index(scsicmd));
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
rc = FAILED; goto return_reset_status;
}
/* Do not attempt on controller */ if (is_hba_lunid(dev->scsi3addr)) {
rc = SUCCESS; goto return_reset_status;
}
if (is_logical_dev_addr_mode(dev->scsi3addr))
reset_type = HPSA_DEVICE_RESET_MSG; else
reset_type = HPSA_PHYS_TARGET_RESET;
/* *waittoseeifanycommandswillcompletebeforesendingreset
*/
dev->in_reset = true; /* block any new cmds from OS for this device */ for (i = 0; i < 10; i++) { if (atomic_read(&dev->commands_outstanding) > 0)
msleep(1000); else break;
}
/* send a reset to the SCSI LUN which the command was sent to */
rc = hpsa_do_reset(h, dev, reset_type, DEFAULT_REPLY_QUEUE); if (rc == 0)
rc = SUCCESS; else
rc = FAILED;
if (idx < HPSA_NRESERVED_CMDS || idx >= h->nr_cmds) {
dev_err(&h->pdev->dev, "Bad block tag: %d not in [%d..%d]\n",
idx, HPSA_NRESERVED_CMDS, h->nr_cmds - 1); /* The index value comes from the block layer, so if it's out of *bounds,it'sprobablynotourbug.
*/
BUG();
}
if (unlikely(!hpsa_is_cmd_idle(c))) { /* *WeexpectthattheSCSIlayerwillhandusauniquetag *value.Thus,thereshouldneverbeacollisionherebetween *tworequests...becauseiftheselectedcommandisn'tidle *thensomeoneisgoingtobeverydisappointed.
*/ if (idx != h->last_collision_tag) { /* Print once per tag */
dev_warn(&h->pdev->dev, "%s: tag collision (tag=%d)\n", __func__, idx); if (scmd)
scsi_print_command(scmd);
h->last_collision_tag = idx;
} return NULL;
}
if (!arg) return -EINVAL;
memset(&arg64, 0, sizeof(arg64)); if (copy_from_user(&arg64, arg32,
offsetof(BIG_IOCTL32_Command_struct, buf))) return -EFAULT; if (get_user(cp, &arg32->buf)) return -EFAULT;
arg64.buf = compat_ptr(cp);
if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0) return -EAGAIN;
err = hpsa_big_passthru_ioctl(h, &arg64);
atomic_inc(&h->passthru_cmds_avail); if (err) return err; if (copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(arg32->error_info))) return -EFAULT; return0;
}
staticint hpsa_compat_ioctl(struct scsi_device *dev, unsignedint cmd, void __user *arg)
{ switch (cmd) { case CCISS_GETPCIINFO: case CCISS_GETINTINFO: case CCISS_SETINTINFO: case CCISS_GETNODENAME: case CCISS_SETNODENAME: case CCISS_GETHEARTBEAT: case CCISS_GETBUSTYPES: case CCISS_GETFIRMVER: case CCISS_GETDRIVVER: case CCISS_REVALIDVOLS: case CCISS_DEREGDISK: case CCISS_REGNEWDISK: case CCISS_REGNEWD: case CCISS_RESCANDISK: case CCISS_GETLUNINFO: return hpsa_ioctl(dev, cmd, arg);
case CCISS_PASSTHRU32: return hpsa_ioctl32_passthru(dev, cmd, arg); case CCISS_BIG_PASSTHRU32: return hpsa_ioctl32_big_passthru(dev, cmd, arg);
if (!capable(CAP_SYS_RAWIO)) return -EPERM; if ((iocommand->buf_size < 1) &&
(iocommand->Request.Type.Direction != XFER_NONE)) { return -EINVAL;
} if (iocommand->buf_size > 0) {
buff = kmalloc(iocommand->buf_size, GFP_KERNEL); if (buff == NULL) return -ENOMEM; if (iocommand->Request.Type.Direction & XFER_WRITE) { /* Copy the data into the buffer we created */ if (copy_from_user(buff, iocommand->buf,
iocommand->buf_size)) {
rc = -EFAULT; goto out_kfree;
}
} else {
memset(buff, 0, iocommand->buf_size);
}
}
c = cmd_alloc(h);
/* Fill in the command type */
c->cmd_type = CMD_IOCTL_PEND;
c->scsi_cmd = SCSI_CMD_BUSY; /* Fill in Command Header */
c->Header.ReplyQueue = 0; /* unused in simple mode */ if (iocommand->buf_size > 0) { /* buffer to fill */
c->Header.SGList = 1;
c->Header.SGTotal = cpu_to_le16(1);
} else { /* no buffers to fill */
c->Header.SGList = 0;
c->Header.SGTotal = cpu_to_le16(0);
}
memcpy(&c->Header.LUN, &iocommand->LUN_info, sizeof(c->Header.LUN));
/* Fill in Request block */
memcpy(&c->Request, &iocommand->Request, sizeof(c->Request));
/* Fill in the scatter gather information */ if (iocommand->buf_size > 0) {
temp64 = dma_map_single(&h->pdev->dev, buff,
iocommand->buf_size, DMA_BIDIRECTIONAL); if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) {
c->SG[0].Addr = cpu_to_le64(0);
c->SG[0].Len = cpu_to_le32(0);
rc = -ENOMEM; goto out;
}
c->SG[0].Addr = cpu_to_le64(temp64);
c->SG[0].Len = cpu_to_le32(iocommand->buf_size);
c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */
}
rc = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
NO_TIMEOUT); if (iocommand->buf_size > 0)
hpsa_pci_unmap(h->pdev, c, 1, DMA_BIDIRECTIONAL);
check_ioctl_unit_attention(h, c); if (rc) {
rc = -EIO; goto out;
}
/* Copy the error information out */
memcpy(&iocommand->error_info, c->err_info, sizeof(iocommand->error_info)); if ((iocommand->Request.Type.Direction & XFER_READ) &&
iocommand->buf_size > 0) { /* Copy the data out of the buffer we created */ if (copy_to_user(iocommand->buf, buff, iocommand->buf_size)) {
rc = -EFAULT; goto out;
}
}
out:
cmd_free(h, c);
out_kfree:
kfree(buff); return rc;
}
if ((ioc->buf_size < 1) &&
(ioc->Request.Type.Direction != XFER_NONE)) return -EINVAL; /* Check kmalloc limits using all SGs */ if (ioc->malloc_size > MAX_KMALLOC_SIZE) return -EINVAL; if (ioc->buf_size > ioc->malloc_size * SG_ENTRIES_IN_CMD) return -EINVAL;
buff = kcalloc(SG_ENTRIES_IN_CMD, sizeof(char *), GFP_KERNEL); if (!buff) {
status = -ENOMEM; goto cleanup1;
}
buff_size = kmalloc_array(SG_ENTRIES_IN_CMD, sizeof(int), GFP_KERNEL); if (!buff_size) {
status = -ENOMEM; goto cleanup1;
}
left = ioc->buf_size;
data_ptr = ioc->buf; while (left) {
sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
buff_size[sg_used] = sz;
if (ioc->Request.Type.Direction & XFER_WRITE) {
buff[sg_used] = memdup_user(data_ptr, sz); if (IS_ERR(buff[sg_used])) {
status = PTR_ERR(buff[sg_used]); goto cleanup1;
}
} else {
buff[sg_used] = kzalloc(sz, GFP_KERNEL); if (!buff[sg_used]) {
status = -ENOMEM; goto cleanup1;
}
}
left -= sz;
data_ptr += sz;
sg_used++;
}
c = cmd_alloc(h);
c->cmd_type = CMD_IOCTL_PEND;
c->scsi_cmd = SCSI_CMD_BUSY;
c->Header.ReplyQueue = 0;
c->Header.SGList = (u8) sg_used;
c->Header.SGTotal = cpu_to_le16(sg_used);
memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN));
memcpy(&c->Request, &ioc->Request, sizeof(c->Request)); if (ioc->buf_size > 0) { int i; for (i = 0; i < sg_used; i++) {
temp64 = dma_map_single(&h->pdev->dev, buff[i],
buff_size[i], DMA_BIDIRECTIONAL); if (dma_mapping_error(&h->pdev->dev,
(dma_addr_t) temp64)) {
c->SG[i].Addr = cpu_to_le64(0);
c->SG[i].Len = cpu_to_le32(0);
hpsa_pci_unmap(h->pdev, c, i,
DMA_BIDIRECTIONAL);
status = -ENOMEM; goto cleanup0;
}
c->SG[i].Addr = cpu_to_le64(temp64);
c->SG[i].Len = cpu_to_le32(buff_size[i]);
c->SG[i].Ext = cpu_to_le32(0);
}
c->SG[--i].Ext = cpu_to_le32(HPSA_SG_LAST);
}
status = hpsa_scsi_do_simple_cmd(h, c, DEFAULT_REPLY_QUEUE,
NO_TIMEOUT); if (sg_used)
hpsa_pci_unmap(h->pdev, c, sg_used, DMA_BIDIRECTIONAL);
check_ioctl_unit_attention(h, c); if (status) {
status = -EIO; goto cleanup0;
}
/* Copy the error information out */
memcpy(&ioc->error_info, c->err_info, sizeof(ioc->error_info)); if ((ioc->Request.Type.Direction & XFER_READ) && ioc->buf_size > 0) { int i;
/* Copy the data out of the buffer we created */
BYTE __user *ptr = ioc->buf; for (i = 0; i < sg_used; i++) { if (copy_to_user(ptr, buff[i], buff_size[i])) {
status = -EFAULT; goto cleanup0;
}
ptr += buff_size[i];
}
}
status = 0;
cleanup0:
cmd_free(h, c);
cleanup1: if (buff) { int i;
for (i = 0; i < sg_used; i++)
kfree(buff[i]);
kfree(buff);
}
kfree(buff_size); return status;
}
switch (cmd) { case CCISS_DEREGDISK: case CCISS_REGNEWDISK: case CCISS_REGNEWD:
hpsa_scan_start(h->scsi_host); return0; case CCISS_GETPCIINFO: return hpsa_getpciinfo_ioctl(h, argp); case CCISS_GETDRIVVER: return hpsa_getdrivver_ioctl(h, argp); case CCISS_PASSTHRU: {
IOCTL_Command_struct iocommand;
if (!argp) return -EINVAL; if (copy_from_user(&iocommand, argp, sizeof(iocommand))) return -EFAULT; if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0) return -EAGAIN;
rc = hpsa_passthru_ioctl(h, &iocommand);
atomic_inc(&h->passthru_cmds_avail); if (!rc && copy_to_user(argp, &iocommand, sizeof(iocommand)))
rc = -EFAULT; return rc;
} case CCISS_BIG_PASSTHRU: {
BIG_IOCTL_Command_struct ioc; if (!argp) return -EINVAL; if (copy_from_user(&ioc, argp, sizeof(ioc))) return -EFAULT; if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0) return -EAGAIN;
rc = hpsa_big_passthru_ioctl(h, &ioc);
atomic_inc(&h->passthru_cmds_avail); if (!rc && copy_to_user(argp, &ioc, sizeof(ioc)))
rc = -EFAULT; return rc;
} default: return -ENOTTY;
}
}
case HPSA_PHYS_TARGET_RESET:
c->Request.CDBLen = 16;
c->Request.type_attr_dir =
TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE);
c->Request.Timeout = 0; /* Don't time out */
memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
c->Request.CDB[0] = HPSA_RESET;
c->Request.CDB[1] = HPSA_TARGET_RESET_TYPE; /* Physical target reset needs no control bytes 4-7*/
c->Request.CDB[4] = 0x00;
c->Request.CDB[5] = 0x00;
c->Request.CDB[6] = 0x00;
c->Request.CDB[7] = 0x00; break; case HPSA_DEVICE_RESET_MSG:
c->Request.CDBLen = 16;
c->Request.type_attr_dir =
TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE);
c->Request.Timeout = 0; /* Don't time out */
memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
c->Request.CDB[0] = cmd;
c->Request.CDB[1] = HPSA_RESET_TYPE_LUN; /* If bytes 4-7 are zero, it means reset the */ /* LunID device */
c->Request.CDB[4] = 0x00;
c->Request.CDB[5] = 0x00;
c->Request.CDB[6] = 0x00;
c->Request.CDB[7] = 0x00; break; default:
dev_warn(&h->pdev->dev, "unknown message type %d\n",
cmd);
BUG();
}
} else {
dev_warn(&h->pdev->dev, "unknown command type %d\n", cmd_type);
BUG();
}
switch (GET_DIR(c->Request.type_attr_dir)) { case XFER_READ:
dir = DMA_FROM_DEVICE; break; case XFER_WRITE:
dir = DMA_TO_DEVICE; break; case XFER_NONE:
dir = DMA_NONE; break; default:
dir = DMA_BIDIRECTIONAL;
} if (hpsa_map_one(h->pdev, c, buff, size, dir)) return -1; return0;
}
/* process completion of an indexed ("direct lookup") command */ staticinlinevoid process_indexed_cmd(struct ctlr_info *h,
u32 raw_tag)
{
u32 tag_index; struct CommandList *c;
tag_index = raw_tag >> DIRECT_LOOKUP_SHIFT; if (!bad_tag(h, tag_index, raw_tag)) {
c = h->cmd_pool + tag_index;
finish_cmd(c);
}
}
/* Some controllers, like p400, will give us one interrupt *afterasoftreset,evenifweturnedinterruptsoff. *Onlyneedtocheckforthisinthehpsa_xxx_discard_completions *functions.
*/ staticint ignore_bogus_interrupt(struct ctlr_info *h)
{ if (likely(!reset_devices)) return0;
/* Send a message CDB to the firmware. Careful, this only works *insimplemode,notperformantmodeduetothetaglookup. *Weonlyeverusethisimmediatelyafteracontrollerreset.
*/ staticint hpsa_message(struct pci_dev *pdev, unsignedchar opcode, unsignedchar type)
{ struct Command { struct CommandListHeader CommandHeader; struct RequestBlock Request; struct ErrDescriptor ErrorDescriptor;
}; struct Command *cmd; staticconst size_t cmd_sz = sizeof(*cmd) + sizeof(cmd->ErrorDescriptor);
dma_addr_t paddr64;
__le32 paddr32;
u32 tag; void __iomem *vaddr; int i, err;
vaddr = pci_ioremap_bar(pdev, 0); if (vaddr == NULL) return -ENOMEM;
/* The Inbound Post Queue only accepts 32-bit physical addresses for the *CCISScommands,sotheymustbeallocatedfromthelower4GiBof *memory.
*/
err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (err) {
iounmap(vaddr); return err;
}
/* This must fit, because of the 32-bit consistent DMA mask. Also, *althoughthere'snoguarantee,weassumethattheaddressisat *least4-bytealigned(mostlikely,it'spage-aligned).
*/
paddr32 = cpu_to_le32(paddr64);
for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) {
tag = readl(vaddr + SA5_REPLY_PORT_OFFSET); if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr64) break;
msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS);
}
iounmap(vaddr);
/* we leak the DMA buffer here ... no choice since the controller could *stillcompletethecommand.
*/ if (i == HPSA_MSG_SEND_RETRY_LIMIT) {
dev_err(&pdev->dev, "controller message %02x:%02x timed out\n",
opcode, type); return -ETIMEDOUT;
}
if (use_doorbell) { /* For everything after the P600, the PCI power state method *ofresettingthecontrollerdoesn'twork,sowehavethis *otherwayusingthedoorbellregister.
*/
dev_info(&pdev->dev, "using doorbell to reset controller\n");
writel(use_doorbell, vaddr + SA5_DOORBELL);
/* PMC hardware guys tell us we need a 10 second delay after *doorbellresetandbeforeanyattempttotalktotheboard *atalltoensurethatthisactuallyworksanddoesn'tfall *overinsomeweirdcornercases.
*/
msleep(10000);
} else { /* Try to do it the PCI power state way */
/* Quoting from the Open CISS Specification: "The Power *ManagementControl/StatusRegister(CSR)controlsthepower *stateofthedevice.ThenormaloperatingstateisD0, *CSR=00h.ThesoftwareoffstateisD3,CSR=03h.Toreset *thecontroller,placetheinterfacedeviceinD3thentoD0, *thiscausesasecondaryPCIresetwhichwillresetthe
* controller." */
int rc = 0;
dev_info(&pdev->dev, "using PCI PM to reset controller\n");
/* enter the D3hot power management state */
rc = pci_set_power_state(pdev, PCI_D3hot); if (rc) return rc;
msleep(500);
/* enter the D0 power management state */
rc = pci_set_power_state(pdev, PCI_D0); if (rc) return rc;
staticint write_driver_ver_to_cfgtable(struct CfgTable __iomem *cfgtable)
{ char *driver_version; int i, size = sizeof(cfgtable->driver_version);
driver_version = kmalloc(size, GFP_KERNEL); if (!driver_version) return -ENOMEM;
init_driver_version(driver_version, size); for (i = 0; i < size; i++)
writeb(driver_version[i], &cfgtable->driver_version[i]);
kfree(driver_version); return0;
}
staticvoid read_driver_ver_from_cfgtable(struct CfgTable __iomem *cfgtable, unsignedchar *driver_ver)
{ int i;
for (i = 0; i < sizeof(cfgtable->driver_version); i++)
driver_ver[i] = readb(&cfgtable->driver_version[i]);
}
/* After a reset, the 32 bytes of "driver version" in the cfgtable *shouldhavebeenchanged,otherwiseweknowtheresetfailed.
*/
init_driver_version(old_driver_ver, size);
read_driver_ver_from_cfgtable(cfgtable, driver_ver);
rc = !memcmp(driver_ver, old_driver_ver, size);
kfree(old_driver_ver); return rc;
} /* This does a hard reset of the controller using PCI power management *statesortheusingthedoorbellregister.
*/ staticint hpsa_kdump_hard_reset_controller(struct pci_dev *pdev, u32 board_id)
{
u64 cfg_offset;
u32 cfg_base_addr;
u64 cfg_base_addr_index; void __iomem *vaddr; unsignedlong paddr;
u32 misc_fw_support; int rc; struct CfgTable __iomem *cfgtable;
u32 use_doorbell;
u16 command_register;
/* For controllers as old as the P600, this is very nearly *thesamethingas * *pci_save_state(pci_dev); *pci_set_power_state(pci_dev,PCI_D3hot); *pci_set_power_state(pci_dev,PCI_D0); *pci_restore_state(pci_dev); * *ForcontrollersnewerthantheP600,thepcipowerstate *methodofresettingdoesn'tworksowehaveanotherway *usingthedoorbellregister.
*/
if (!ctlr_is_resettable(board_id)) {
dev_warn(&pdev->dev, "Controller not resettable\n"); return -ENODEV;
}
/* if controller is soft- but not hard resettable... */ if (!ctlr_is_hard_resettable(board_id)) return -ENOTSUPP; /* try soft reset later. */
/* Save the PCI command register */
pci_read_config_word(pdev, 4, &command_register);
pci_save_state(pdev);
/* find the first memory BAR, so we can find the cfg table */
rc = hpsa_pci_find_memory_BAR(pdev, &paddr); if (rc) return rc;
vaddr = remap_pci_mem(paddr, 0x250); if (!vaddr) return -ENOMEM;
/* find cfgtable in order to check if reset via doorbell is supported */
rc = hpsa_find_cfg_addrs(pdev, vaddr, &cfg_base_addr,
&cfg_base_addr_index, &cfg_offset); if (rc) goto unmap_vaddr;
cfgtable = remap_pci_mem(pci_resource_start(pdev,
cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable)); if (!cfgtable) {
rc = -ENOMEM; goto unmap_vaddr;
}
rc = write_driver_ver_to_cfgtable(cfgtable); if (rc) goto unmap_cfgtable;
/* If reset via doorbell register is supported, use that. *Therearetwosuchmethods.Favorthenewestmethod.
*/
misc_fw_support = readl(&cfgtable->misc_fw_support);
use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2; if (use_doorbell) {
use_doorbell = DOORBELL_CTLR_RESET2;
} else {
use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; if (use_doorbell) {
dev_warn(&pdev->dev, "Soft reset not supported. Firmware update is required.\n");
rc = -ENOTSUPP; /* try soft reset */ goto unmap_cfgtable;
}
}
rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell); if (rc) goto unmap_cfgtable;
/* Some devices (notably the HP Smart Array 5i Controller)
need a little pause here */
msleep(HPSA_POST_RESET_PAUSE_MSECS);
rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY); if (rc) {
dev_warn(&pdev->dev, "Failed waiting for board to become ready after hard reset\n"); goto unmap_cfgtable;
}
rc = controller_reset_failed(vaddr); if (rc < 0) goto unmap_cfgtable; if (rc) {
dev_warn(&pdev->dev, "Unable to successfully reset " "controller. Will try soft reset.\n");
rc = -ENOTSUPP;
} else {
dev_info(&pdev->dev, "board ready after hard reset.\n");
}
/* If MSI/MSI-X is supported by the kernel we will try to enable it on *controllersthatarecapable.Ifnot,weuselegacyINTxmode.
*/ staticint hpsa_interrupt_mode(struct ctlr_info *h)
{ unsignedint flags = PCI_IRQ_INTX; int ret;
/* Some boards advertise MSI but don't really support it */ switch (h->board_id) { case0x40700E11: case0x40800E11: case0x40820E11: case0x40830E11: break; default:
ret = pci_alloc_irq_vectors(h->pdev, 1, MAX_REPLY_QUEUES,
PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); if (ret > 0) {
h->msix_vectors = ret; return0;
}
flags |= PCI_IRQ_MSI; break;
}
ret = pci_alloc_irq_vectors(h->pdev, 1, 1, flags); if (ret < 0) return ret; return0;
}
/* Limit commands in memory limited kdump scenario. */ if (reset_devices && h->max_commands > 32)
h->max_commands = 32;
if (h->max_commands < MIN_MAX_COMMANDS) {
dev_warn(&h->pdev->dev, "Controller reports max supported commands of %d Using %d instead. Ensure that firmware is up to date.\n",
h->max_commands,
MIN_MAX_COMMANDS);
h->max_commands = MIN_MAX_COMMANDS;
}
}
/* If the controller reports that the total max sg entries is greater than 512, *thenweknowthatchainedSGblockswork.(Originalsmartarraysdidnot *supportchainedSGblocksandwouldreturnzeroformaxsgentries.)
*/ staticint hpsa_supports_chained_sg_blocks(struct ctlr_info *h)
{ return h->maxsgentries > 512;
}
/* Interrogate the hardware for some limits: *maxcommands,maxSGelementswithoutchaining,andwithchaining, *SGchainblocksize,etc.
*/ staticvoid hpsa_find_board_params(struct ctlr_info *h)
{
hpsa_get_max_perf_mode_cmds(h);
h->nr_cmds = h->max_commands;
h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
h->fw_support = readl(&(h->cfgtable->misc_fw_support)); if (hpsa_supports_chained_sg_blocks(h)) { /* Limit in-command s/g elements to 32 save dma'able memory. */
h->max_cmd_sg_entries = 32;
h->chainsize = h->maxsgentries - h->max_cmd_sg_entries;
h->maxsgentries--; /* save one for chain pointer */
} else { /* *Originalsmartarrayssupportedatmost31s/gentries *embeddedinlineinthecommand(tryingtousemore *wouldlockupthecontroller)
*/
h->max_cmd_sg_entries = 31;
h->maxsgentries = 31; /* default to traditional values */
h->chainsize = 0;
}
/* Find out what task management functions are supported and cache */
h->TMFSupportFlags = readl(&(h->cfgtable->TMFSupportFlags)); if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags))
dev_warn(&h->pdev->dev, "Physical aborts not supported\n"); if (!(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags))
dev_warn(&h->pdev->dev, "Logical aborts not supported\n"); if (!(HPSATMF_IOACCEL_ENABLED & h->TMFSupportFlags))
dev_warn(&h->pdev->dev, "HP SSD Smart Path aborts not supported\n");
}
driver_support = readl(&(h->cfgtable->driver_support)); /* Need to enable prefetch in the SCSI core for 6400 in x86 */ #ifdef CONFIG_X86
driver_support |= ENABLE_SCSI_PREFETCH; #endif
driver_support |= ENABLE_UNIT_ATTN;
writel(driver_support, &(h->cfgtable->driver_support));
}
/* Disable DMA prefetch for the P600. Otherwise an ASIC bug may result *inaprefetchbeyondphysicalmemory.
*/ staticinlinevoid hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
{
u32 dma_prefetch;
staticint hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h)
{ int i;
u32 doorbell_value; unsignedlong flags; /* wait until the clear_event_notify bit 6 is cleared by controller. */ for (i = 0; i < MAX_CLEAR_EVENT_WAIT; i++) {
spin_lock_irqsave(&h->lock, flags);
doorbell_value = readl(h->vaddr + SA5_DOORBELL);
spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & DOORBELL_CLEAR_EVENTS)) goto done; /* delay and try again */
msleep(CLEAR_EVENT_WAIT_INTERVAL);
} return -ENODEV;
done: return0;
}
/* under certain very rare conditions, this can take awhile. *(e.g.:hotreplaceafailed144GBdriveinaRAID5setright *asweenterthiscode.)
*/ for (i = 0; i < MAX_MODE_CHANGE_WAIT; i++) { if (h->remove_in_progress) goto done;
spin_lock_irqsave(&h->lock, flags);
doorbell_value = readl(h->vaddr + SA5_DOORBELL);
spin_unlock_irqrestore(&h->lock, flags); if (!(doorbell_value & CFGTBL_ChangeReq)) goto done; /* delay and try again */
msleep(MODE_CHANGE_WAIT_INTERVAL);
} return -ENODEV;
done: return0;
}
/* return -ENODEV or other reason on error, 0 on success */ staticint hpsa_enter_simple_mode(struct ctlr_info *h)
{
u32 trans_support;
trans_support = readl(&(h->cfgtable->TransportSupport)); if (!(trans_support & SIMPLE_MODE)) return -ENOTSUPP;
/* Update the field, and then ring the doorbell */
writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); if (hpsa_wait_for_mode_change_ack(h)) goto error;
print_cfg_table(&h->pdev->dev, h->cfgtable); if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) goto error;
h->transMethod = CFGTBL_Trans_Simple; return0;
error:
dev_err(&h->pdev->dev, "failed to enter simple mode\n"); return -ENODEV;
}
/* kdump kernel is loading, we don't know in which state is *thepciinterface.Thedev->enable_cntisequalzero *sowecallenable+disable,waitawhileandswitchiton.
*/
rc = pci_enable_device(pdev); if (rc) {
dev_warn(&pdev->dev, "Failed to enable PCI device\n"); return -ENODEV;
}
pci_disable_device(pdev);
msleep(260); /* a randomly chosen number */
rc = pci_enable_device(pdev); if (rc) {
dev_warn(&pdev->dev, "failed to enable device.\n"); return -ENODEV;
}
/* Reset the controller with a PCI power-cycle or via doorbell */
rc = hpsa_kdump_hard_reset_controller(pdev, board_id);
/* -ENOTSUPP here means we cannot reset the controller *butit'salready(andstill)upandrunningin *"performantmode".Or,itmightbe640x,whichcan'treset *duetoconcernsaboutsharedbbwcbetween6402/6404pair.
*/ if (rc) goto out_disable;
/* Now try to get the controller to respond to a no-op */
dev_info(&pdev->dev, "Waiting for controller to respond to no-op\n"); for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) { if (hpsa_noop(pdev) == 0) break; else
dev_warn(&pdev->dev, "no-op failed%s\n",
(i < 11 ? "; re-trying" : ""));
}
/* clear affinity hints and free MSI-X, MSI, or legacy INTx vectors */ staticvoid hpsa_free_irqs(struct ctlr_info *h)
{ int i; int irq_vector = 0;
if (hpsa_simple_mode)
irq_vector = h->intr_mode;
if (!h->msix_vectors || h->intr_mode != PERF_MODE_INT) { /* Single reply queue, only one irq to free */
free_irq(pci_irq_vector(h->pdev, irq_vector),
&h->q[h->intr_mode]);
h->q[h->intr_mode] = 0; return;
}
for (i = 0; i < h->msix_vectors; i++) {
free_irq(pci_irq_vector(h->pdev, i), &h->q[i]);
h->q[i] = 0;
} for (; i < MAX_REPLY_QUEUES; i++)
h->q[i] = 0;
}
/* returns 0 on success; cleans up and returns -Enn on error */ staticint hpsa_request_irqs(struct ctlr_info *h,
irqreturn_t (*msixhandler)(int, void *),
irqreturn_t (*intxhandler)(int, void *))
{ int rc, i; int irq_vector = 0;
if (hpsa_simple_mode)
irq_vector = h->intr_mode;
/* *initializeh->q[x]=xsothatinterrupthandlersknowwhich *queuetoprocess.
*/ for (i = 0; i < MAX_REPLY_QUEUES; i++)
h->q[i] = (u8) i;
if (h->intr_mode == PERF_MODE_INT && h->msix_vectors > 0) { /* If performant mode and MSI-X, use multiple reply queues */ for (i = 0; i < h->msix_vectors; i++) {
sprintf(h->intrname[i], "%s-msix%d", h->devname, i);
rc = request_irq(pci_irq_vector(h->pdev, i), msixhandler, 0, h->intrname[i],
&h->q[i]); if (rc) { int j;
dev_err(&h->pdev->dev, "failed to get irq %d for %s\n",
pci_irq_vector(h->pdev, i), h->devname); for (j = 0; j < i; j++) {
free_irq(pci_irq_vector(h->pdev, j), &h->q[j]);
h->q[j] = 0;
} for (; j < MAX_REPLY_QUEUES; j++)
h->q[j] = 0; return rc;
}
}
} else { /* Use single reply pool */ if (h->msix_vectors > 0 || h->pdev->msi_enabled) {
sprintf(h->intrname[0], "%s-msi%s", h->devname,
h->msix_vectors ? "x" : "");
rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
msixhandler, 0,
h->intrname[0],
&h->q[h->intr_mode]);
} else {
sprintf(h->intrname[h->intr_mode], "%s-intx", h->devname);
rc = request_irq(pci_irq_vector(h->pdev, irq_vector),
intxhandler, IRQF_SHARED,
h->intrname[0],
&h->q[h->intr_mode]);
}
} if (rc) {
dev_err(&h->pdev->dev, "failed to get irq %d for %s\n",
pci_irq_vector(h->pdev, irq_vector), h->devname);
hpsa_free_irqs(h); return -ENODEV;
} return0;
}
staticint hpsa_kdump_soft_reset(struct ctlr_info *h)
{ int rc;
hpsa_send_host_reset(h, HPSA_RESET_TYPE_CONTROLLER);
dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n");
rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY); if (rc) {
dev_warn(&h->pdev->dev, "Soft reset had no effect.\n"); return rc;
}
dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n");
rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY); if (rc) {
dev_warn(&h->pdev->dev, "Board failed to become ready " "after soft reset.\n"); return rc;
}
return0;
}
staticvoid hpsa_free_reply_queues(struct ctlr_info *h)
{ int i;
for (i = 0; i < h->nreply_queues; i++) { if (!h->reply_queue[i].head) continue;
dma_free_coherent(&h->pdev->dev,
h->reply_queue_size,
h->reply_queue[i].head,
h->reply_queue[i].busaddr);
h->reply_queue[i].head = NULL;
h->reply_queue[i].busaddr = 0;
}
h->reply_queue_size = 0;
}
/* Called when controller lockup detected. */ staticvoid fail_all_outstanding_cmds(struct ctlr_info *h)
{ int i, refcount; struct CommandList *c; int failcount = 0;
flush_workqueue(h->resubmit_wq); /* ensure all cmds are fully built */ for (i = 0; i < h->nr_cmds; i++) {
c = h->cmd_pool + i;
refcount = atomic_inc_return(&c->refcount); if (refcount > 1) {
c->err_info->CommandStatus = CMD_CTLR_LOCKUP;
finish_cmd(c);
atomic_dec(&h->commands_outstanding);
failcount++;
}
cmd_free(h, c);
}
dev_warn(&h->pdev->dev, "failed %d commands in fail_all\n", failcount);
}
staticvoid set_lockup_detected_for_all_cpus(struct ctlr_info *h, u32 value)
{ int cpu;
for_each_online_cpu(cpu) {
u32 *lockup_detected;
lockup_detected = per_cpu_ptr(h->lockup_detected, cpu);
*lockup_detected = value;
}
wmb(); /* be sure the per-cpu variables are out to memory */
}
now = get_jiffies_64(); /* If we've received an interrupt recently, we're ok. */ if (time_after64(h->last_intr_timestamp +
(h->heartbeat_sample_interval), now)) returnfalse;
/* If heartbeat has not changed since we last looked, we're not ok. */
spin_lock_irqsave(&h->lock, flags);
heartbeat = readl(&h->cfgtable->HeartBeat);
spin_unlock_irqrestore(&h->lock, flags); if (h->last_heartbeat == heartbeat) {
controller_lockup_detected(h); returntrue;
}
if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) return;
/* Ask the controller to clear the events we're handling. */ if ((h->transMethod & (CFGTBL_Trans_io_accel1
| CFGTBL_Trans_io_accel2)) &&
(h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE ||
h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)) {
if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE)
event_type = "state change"; if (h->events & HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE)
event_type = "configuration change"; /* Stop sending new RAID offload reqs via the IO accelerator */
scsi_block_requests(h->scsi_host);
hpsa_set_ioaccel_status(h);
hpsa_drain_accel_commands(h); /* Set 'accelerator path config change' bit */
dev_warn(&h->pdev->dev, "Acknowledging event: 0x%08x (HP SSD Smart Path %s)\n",
h->events, event_type);
writel(h->events, &(h->cfgtable->clear_event_notify)); /* Set the "clear event notify field update" bit 6 */
writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL); /* Wait until ctlr clears 'clear event notify field', bit 6 */
hpsa_wait_for_clear_event_notify_ack(h);
scsi_unblock_requests(h->scsi_host);
} else { /* Acknowledge controller notification events. */
writel(h->events, &(h->cfgtable->clear_event_notify));
writel(DOORBELL_CLEAR_EVENTS, h->vaddr + SA5_DOORBELL);
hpsa_wait_for_clear_event_notify_ack(h);
} return;
}
/* Check a register on the controller to see if there are configuration *changes(added/changed/removedlogicaldrives,etc.)whichmeanthat *weshouldrescanthecontrollerfordevices. *Alsocheckflagfordriver-initiatedrescan.
*/ staticint hpsa_ctlr_needs_rescan(struct ctlr_info *h)
{ if (h->drv_req_rescan) {
h->drv_req_rescan = 0; return1;
}
if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) return0;
if (number_of_controllers == 0)
printk(KERN_INFO DRIVER_NAME "\n");
rc = hpsa_lookup_board_id(pdev, &board_id, NULL); if (rc < 0) {
dev_warn(&pdev->dev, "Board ID not found\n"); return rc;
}
rc = hpsa_init_reset_devices(pdev, board_id); if (rc) { if (rc != -ENOTSUPP) return rc; /* If the reset fails in a particular way (it has no way to do *aproperhardreset,soreturns-ENOTSUPP)wecantrytodo *asoftresetoncewegetthecontrollerconfigureduptothe *pointthatitcanacceptacommand.
*/
try_soft_reset = 1;
rc = 0;
}
reinit_after_soft_reset:
/* Command structures must be aligned on a 32-byte boundary because *the5lowerbitsoftheaddressareusedbythehardware.andby *thedriver.Seecommentsinhpsa.hformoreinfo.
*/
BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT);
h = hpda_alloc_ctlr_info(); if (!h) {
dev_err(&pdev->dev, "Failed to allocate controller head\n"); return -ENOMEM;
}
/* relies on h-> settings made by hpsa_pci_init, including
* interrupt_mode h->intr */
rc = hpsa_scsi_host_alloc(h); if (rc) goto clean2_5; /* pci, lu, aer/h */
/* *Atthispoint,thecontrollerisreadytotakecommands. *Now,ifreset_devicesandthehardresetdidn'twork,try *thesoftresetandseeifthatworks.
*/ if (try_soft_reset) {
/* This is kind of gross. We may or may not get a completion *fromthesoftresetcommand,andifwedo,thenthevalue *fromthefifomayormaynotbevalid.So,wewait10secs *aftertheresetthrowingawayanycompletionswegetduring *thattime.Unregistertheinterrupthandlerandregister *fakeonestoscoopupanyresidualcompletions.
*/
spin_lock_irqsave(&h->lock, flags);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
spin_unlock_irqrestore(&h->lock, flags);
hpsa_free_irqs(h);
rc = hpsa_request_irqs(h, hpsa_msix_discard_completions,
hpsa_intx_discard_completions); if (rc) {
dev_warn(&h->pdev->dev, "Failed to request_irq after soft reset.\n"); /* *cannotgotoclean7orfree_irqswillbecalled *again.Instead,doitswork
*/
hpsa_free_performant_mode(h); /* clean7 */
hpsa_free_sg_chain_blocks(h); /* clean6 */
hpsa_free_cmd_pool(h); /* clean5 */ /* *skiphpsa_free_irqs(h)clean4sincethat *wasjustcalledbeforerequest_irqsfailed
*/ goto clean3;
}
rc = hpsa_kdump_soft_reset(h); if (rc) /* Neither hard nor soft reset worked, we're hosed. */ goto clean7;
dev_info(&h->pdev->dev, "Board READY.\n");
dev_info(&h->pdev->dev, "Waiting for stale completions to drain.\n");
h->access.set_intr_mask(h, HPSA_INTR_ON);
msleep(10000);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
rc = controller_reset_failed(h->cfgtable); if (rc)
dev_info(&h->pdev->dev, "Soft reset appears to have failed.\n");
/* since the controller's reset, we have to go back and re-init *everything.Easiesttojustforgetwhatwe'vedoneanddoit *alloveragain.
*/
hpsa_undo_allocations_after_kdump_soft_reset(h);
try_soft_reset = 0; if (rc) /* don't goto clean, we already unallocated */ return -ENODEV;
if (unlikely(lockup_detected(h))) return;
flush_buf = kzalloc(4, GFP_KERNEL); if (!flush_buf) return;
c = cmd_alloc(h);
if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0,
RAID_CTLR_LUNID, TYPE_CMD)) { goto out;
}
rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, DMA_TO_DEVICE,
DEFAULT_TIMEOUT); if (rc) goto out; if (c->err_info->CommandStatus != 0)
out:
dev_warn(&h->pdev->dev, "error flushing cache on controller\n");
cmd_free(h, c);
kfree(flush_buf);
}
/* Make controller gather fresh report lun data each time we *senddownareportlunsrequest
*/ staticvoid hpsa_disable_rld_caching(struct ctlr_info *h)
{
u32 *options; struct CommandList *c; int rc;
/* Don't bother trying to set diag options if locked up */ if (unlikely(h->lockup_detected)) return;
options = kzalloc(sizeof(*options), GFP_KERNEL); if (!options) return;
c = cmd_alloc(h);
/* first, get the current diag options settings */ if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0,
RAID_CTLR_LUNID, TYPE_CMD)) goto errout;
/* Fill in bucket_map[], given nsgs (the max number of *scattergatherelementssupported)andbucket[], *whichisanarrayof8integers.Thebucket[]array *contains8differentDMAtransfersizes(in16 *byteincrements)whichthecontrollerusestofetch *commands.Thisfunctionfillsinbucket_map[],which *mapsagivennumberofscattergatherelementstooneof *the8DMAtransfersizes.Thepointofitistoallowthe *controllertoonlydoasmuchDMAasneededtofetchthe *command,withtheDMAtransfersizeencodedinthelower *bitsofthecommandaddress.
*/ staticvoid calc_bucket_map(int bucket[], int num_buckets, int nsgs, int min_blocks, u32 *bucket_map)
{ int i, j, b, size;
/* Note, bucket_map must have nsgs+1 entries. */ for (i = 0; i <= nsgs; i++) { /* Compute size of a command with i SG entries */
size = i + min_blocks;
b = num_buckets; /* Assume the biggest bucket */ /* Find the bucket that is just big enough */ for (j = 0; j < num_buckets; j++) { if (bucket[j] >= size) {
b = j; break;
}
} /* for a command with i SG entries, use bucket b. */
bucket_map[i] = b;
}
}
/* If the controller supports either ioaccel method then *wecanalsousetheRAIDstacksubmitpaththatdoesnot *performthesuperfluousreadl()aftereachcommandsubmission.
*/ if (trans_support & (CFGTBL_Trans_io_accel1 | CFGTBL_Trans_io_accel2))
access = SA5_performant_access_no_read;
/* Controller spec: zero out this buffer. */ for (i = 0; i < h->nreply_queues; i++)
memset(h->reply_queue[i].head, 0, h->reply_queue_size);
bft[7] = SG_ENTRIES_IN_CMD + 4;
calc_bucket_map(bft, ARRAY_SIZE(bft),
SG_ENTRIES_IN_CMD, 4, h->blockFetchTable); for (i = 0; i < 8; i++)
writel(bft[i], &h->transtable->BlockFetch[i]);
/* size of controller ring buffer */
writel(h->max_commands, &h->transtable->RepQSize);
writel(h->nreply_queues, &h->transtable->RepQCount);
writel(0, &h->transtable->RepQCtrAddrLow32);
writel(0, &h->transtable->RepQCtrAddrHigh32);
for (i = 0; i < h->nreply_queues; i++) {
writel(0, &h->transtable->RepQAddr[i].upper);
writel(h->reply_queue[i].busaddr,
&h->transtable->RepQAddr[i].lower);
}
writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
writel(transMethod, &(h->cfgtable->HostWrite.TransportRequest)); /* *enableoutboundinterruptcoalescinginacceleratormode;
*/ if (trans_support & CFGTBL_Trans_io_accel1) {
access = SA5_ioaccel_mode1_access;
writel(10, &h->cfgtable->HostWrite.CoalIntDelay);
writel(4, &h->cfgtable->HostWrite.CoalIntCount);
} else if (trans_support & CFGTBL_Trans_io_accel2)
access = SA5_ioaccel_mode2_access;
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); if (hpsa_wait_for_mode_change_ack(h)) {
dev_err(&h->pdev->dev, "performant mode problem - doorbell timeout\n"); return -ENODEV;
}
register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) {
dev_err(&h->pdev->dev, "performant mode problem - transport not active\n"); return -ENODEV;
} /* Change the access methods to the performant access methods */
h->access = access;
h->transMethod = transMethod;
if (!((trans_support & CFGTBL_Trans_io_accel1) ||
(trans_support & CFGTBL_Trans_io_accel2))) return0;
if (trans_support & CFGTBL_Trans_io_accel1) { /* Set up I/O accelerator mode */ for (i = 0; i < h->nreply_queues; i++) {
writel(i, h->vaddr + IOACCEL_MODE1_REPLY_QUEUE_INDEX);
h->reply_queue[i].current_entry =
readl(h->vaddr + IOACCEL_MODE1_PRODUCER_INDEX);
}
bft[7] = h->ioaccel_maxsg + 8;
calc_bucket_map(bft, ARRAY_SIZE(bft), h->ioaccel_maxsg, 8,
h->ioaccel1_blockFetchTable);
/* initialize all reply queue entries to unused */ for (i = 0; i < h->nreply_queues; i++)
memset(h->reply_queue[i].head,
(u8) IOACCEL_MODE1_REPLY_UNUSED,
h->reply_queue_size);
/* set all the constant fields in the accelerator command *framesonceatinittimetosaveCPUcycleslater.
*/ for (i = 0; i < h->nr_cmds; i++) { struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[i];
/* return -ENODEV on error, 0 on success (or no action) *allocatesnumerousitemsthatmustbefreedlater
*/ staticint hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
{
u32 trans_support; int i, rc;
if (hpsa_simple_mode) return0;
trans_support = readl(&(h->cfgtable->TransportSupport)); if (!(trans_support & PERFORMANT_MODE)) return0;
/* Check for I/O accelerator mode support */ if (trans_support & CFGTBL_Trans_io_accel1) {
rc = hpsa_alloc_ioaccel1_cmd_and_bft(h); if (rc) return rc;
} elseif (trans_support & CFGTBL_Trans_io_accel2) {
rc = hpsa_alloc_ioaccel2_cmd_and_bft(h); if (rc) return rc;
}
h->nreply_queues = h->msix_vectors > 0 ? h->msix_vectors : 1;
hpsa_get_max_perf_mode_cmds(h); /* Performant mode ring buffer and supporting data structures */
h->reply_queue_size = h->max_commands * sizeof(u64);
for (i = 0; i < h->nreply_queues; i++) {
h->reply_queue[i].head = dma_alloc_coherent(&h->pdev->dev,
h->reply_queue_size,
&h->reply_queue[i].busaddr,
GFP_KERNEL); if (!h->reply_queue[i].head) {
rc = -ENOMEM; goto clean1; /* rq, ioaccel */
}
h->reply_queue[i].size = h->max_commands;
h->reply_queue[i].wraparound = 1; /* spec: init to 1 */
h->reply_queue[i].current_entry = 0;
}
/* Need a block fetch table for performant mode */
h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) * sizeof(u32)), GFP_KERNEL); if (!h->blockFetchTable) {
rc = -ENOMEM; goto clean1; /* rq, ioaccel */
}
staticvoid hpsa_drain_accel_commands(struct ctlr_info *h)
{ struct CommandList *c = NULL; int i, accel_cmds_out; int refcount;
do { /* wait for all outstanding ioaccel commands to drain out */
accel_cmds_out = 0; for (i = 0; i < h->nr_cmds; i++) {
c = h->cmd_pool + i;
refcount = atomic_inc_return(&c->refcount); if (refcount > 1) /* Command is allocated */
accel_cmds_out += is_accelerated_cmd(c);
cmd_free(h, c);
} if (accel_cmds_out <= 0) break;
msleep(100);
} while (1);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.