/* * Disk Array driver for HP Smart Array SAS controllers * Copyright (c) 2019-2020 Microchip Technology Inc. and its subsidiaries * Copyright 2016 Microsemi Corporation * Copyright 2014-2015 PMC-Sierra, Inc. * Copyright 2000,2009-2015 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; 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. * * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com *
*/
/* * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' * with an optional trailing '-' followed by a byte value (0-255).
*/ #define HPSA_DRIVER_VERSION "3.4.20-200" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa"
/* 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: this REPORT_LUNS_CHANGED condition only occurs on the external * 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;
} return 1;
}
/* List of controllers which cannot even be soft reset */ static u32 soft_unresettable_controller[] = {
0x40800E11, /* Smart Array 5i */
0x40700E11, /* Smart Array 5300 */
0x40820E11, /* Smart Array 532 */
0x40830E11, /* Smart Array 5312 */
0x409A0E11, /* Smart Array 641 */
0x409B0E11, /* Smart Array 642 */
0x40910E11, /* Smart Array 6i */ /* Exclude 640x boards. These are two pci devices in one slot * which share a battery backed cache module. One controls the * cache, the other accesses the cache through the one that controls * it. If we reset the one controlling the cache, the other will * likely not be happy. Just forbid resetting this conjoined mess. * The 640x isn't really supported by hpsa anyway.
*/
0x409C0E11, /* Smart Array 6400 */
0x409D0E11, /* Smart Array 6400 EM */
};
staticint board_id_in_array(u32 a[], int nelems, u32 board_id)
{ int i;
for (i = 0; i < nelems; i++) if (a[i] == board_id) return 1; return 0;
}
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;
if (h->transMethod & CFGTBL_Trans_io_accel1) return h->access.command_completed(h, q);
if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) return h->access.command_completed(h, q);
if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
a = rq->head[rq->current_entry];
rq->current_entry++;
atomic_dec(&h->commands_outstanding);
} else {
a = FIFO_EMPTY;
} /* Check for wraparound */ if (rq->current_entry == h->max_commands) {
rq->current_entry = 0;
rq->wraparound ^= 1;
} return a;
}
/* * There are some special bits in the bus address of the * command that we have to set for the controller to know * how to process the command: * * Normal performant mode: * bit 0: 1 means performant mode, 0 means simple mode. * bits 1-3 = block fetch table entry * bits 4-6 = command type (== 0) * * ioaccel1 mode: * bit 0 = "performant mode" bit. * bits 1-3 = block fetch table entry * bits 4-6 = command type (== 110) * (command type is needed because ioaccel1 mode * commands are submitted through the same register as normal * mode commands, so this is how the controller knows whether * the command is normal mode or ioaccel1 mode.) * * ioaccel2 mode: * bit 0 = "performant mode" bit. * bits 1-4 = block fetch table entry (note extra bit) * bits 4-6 = not needed, because ioaccel2 mode has * a separate special register for submitting commands.
*/
/* * set_performant_mode: Modify the tag for cciss performant * set bit 0 for pull model, bits 3-1 for block fetch * register number
*/ #define DEFAULT_REPLY_QUEUE (-1) staticvoid set_performant_mode(struct ctlr_info *h, struct CommandList *c, int reply_queue)
{ if (likely(h->transMethod & CFGTBL_Trans_Performant)) {
c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); if (unlikely(!h->msix_vectors)) return;
c->Header.ReplyQueue = reply_queue;
}
}
/* * Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput.
*/
cp->ReplyQueue = reply_queue; /* * Set the bits in the address sent down to include: * - performant mode bit (bit 0) * - pull count (bits 1-3) * - command type (bits 4-6)
*/
c->busaddr |= 1 | (h->ioaccel1_blockFetchTable[c->Header.SGList] << 1) |
IOACCEL1_BUSADDR_CMDTYPE;
}
/* Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput.
*/
cp->reply_queue = reply_queue; /* Set the bits in the address sent down to include: * - performant mode bit not used in ioaccel mode 2 * - pull count (bits 0-3) * - command type isn't needed for ioaccel2
*/
c->busaddr |= h->ioaccel2_blockFetchTable[0];
}
/* * Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput.
*/
cp->reply_queue = reply_queue; /* * Set the bits in the address sent down to include: * - performant mode bit not used in ioaccel mode 2 * - pull count (bits 0-3) * - command type isn't needed for ioaccel2
*/
c->busaddr |= (h->ioaccel2_blockFetchTable[cp->sg_count]);
}
/* * During firmware flash, the heartbeat register may not update as frequently * as it should. So we dial down lockup detection during firmware flash. and * dial it back up when firmware flash completes.
*/ #define HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH (240 * HZ) #define HEARTBEAT_SAMPLE_INTERVAL (30 * HZ) #define HPSA_EVENT_MONITOR_INTERVAL (15 * HZ) staticvoid dial_down_lockup_detection_during_fw_flash(struct ctlr_info *h, struct CommandList *c)
{ if (!is_firmware_flash_cmd(c->Request.CDB)) return;
atomic_inc(&h->firmware_flash_in_progress);
h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL_DURING_FLASH;
}
staticvoid __enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c, int reply_queue)
{
dial_down_lockup_detection_during_fw_flash(h, c);
atomic_inc(&h->commands_outstanding); /* * Check to see if the command is being retried.
*/ if (c->device && !c->retry_pending)
atomic_inc(&c->device->commands_outstanding);
staticinlineint is_scsi_rev_5(struct ctlr_info *h)
{ if (!h->hba_inquiry_data) return 0; if ((h->hba_inquiry_data[2] & 0x07) == 5) return 1; return 0;
}
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 * assumes h->devlock is held
*/ 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 * byte 4 of the 8-byte LUN addr will contain the logical * unit no, zero otherwise.
*/ 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. * Search through our list and find the device which * has the same 8 byte LUN address, excepting byte 4 and 5. * Assign the same bus and target for this new LUN. * Use the logical unit number from the firmware.
*/
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;
}
/* * Called during a scan operation. * * Update an entry in h->dev[] array.
*/ staticvoid hpsa_scsi_update_entry(struct ctlr_info *h, int entry, struct hpsa_scsi_dev_t *new_entry)
{ /* assumes h->devlock is held */
BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
/* * ioacccel_handle may have changed for a dual domain disk
*/
h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
/* Raid offload parameters changed. Careful about the ordering. */ if (new_entry->offload_config && new_entry->offload_to_be_enabled) { /* * if drive is newly offload_enabled, we want to copy the * raid map data first. If previously offload_enabled and * offload_config were set, raid map data had better be * the same as it was before. If raid map data has changed * then it had better be the case that * h->dev[entry]->offload_enabled is currently 0.
*/
h->dev[entry]->raid_map = new_entry->raid_map;
h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
} if (new_entry->offload_to_be_enabled) {
h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
wmb(); /* set ioaccel_handle *before* hba_ioaccel_enabled */
}
h->dev[entry]->hba_ioaccel_enabled = new_entry->hba_ioaccel_enabled;
h->dev[entry]->offload_config = new_entry->offload_config;
h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror;
h->dev[entry]->queue_depth = new_entry->queue_depth;
/* * We can turn off ioaccel offload now, but need to delay turning * ioaccel on until we can update h->dev[entry]->phys_disk[], but we * can't do that until all the devices are updated.
*/
h->dev[entry]->offload_to_be_enabled = new_entry->offload_to_be_enabled;
/* * turn ioaccel off immediately if told to do so.
*/ if (!new_entry->offload_to_be_enabled)
h->dev[entry]->offload_enabled = 0;
/* Replace an entry from h->dev[] array. */ staticvoid hpsa_scsi_replace_entry(struct ctlr_info *h, int entry, struct hpsa_scsi_dev_t *new_entry, struct hpsa_scsi_dev_t *added[], int *nadded, struct hpsa_scsi_dev_t *removed[], int *nremoved)
{ /* assumes h->devlock is held */
BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
removed[*nremoved] = h->dev[entry];
(*nremoved)++;
/* * New physical devices won't have target/lun assigned yet * so we need to preserve the values in the slot we are replacing.
*/ if (new_entry->target == -1) {
new_entry->target = h->dev[entry]->target;
new_entry->lun = h->dev[entry]->lun;
}
/* 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[] to match the mid layer's view.
*/ 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 * are not yet assigned. Compare parts likely * to differ first
*/ if (memcmp(dev1->scsi3addr, dev2->scsi3addr, sizeof(dev1->scsi3addr)) != 0) return 0; if (memcmp(dev1->device_id, dev2->device_id, sizeof(dev1->device_id)) != 0) return 0; if (memcmp(dev1->model, dev2->model, sizeof(dev1->model)) != 0) return 0; if (memcmp(dev1->vendor, dev2->vendor, sizeof(dev1->vendor)) != 0) return 0; if (dev1->devtype != dev2->devtype) return 0; if (dev1->bus != dev2->bus) return 0; return 1;
}
staticinlineint device_updated(struct hpsa_scsi_dev_t *dev1, struct hpsa_scsi_dev_t *dev2)
{ /* Device attributes that can change, but don't mean * that the device is a different device, nor that the OS * needs to be told anything about the change.
*/ if (dev1->raid_level != dev2->raid_level) return 1; if (dev1->offload_config != dev2->offload_config) return 1; if (dev1->offload_to_be_enabled != dev2->offload_to_be_enabled) return 1; if (!is_logical_dev_addr_mode(dev1->scsi3addr)) if (dev1->queue_depth != dev2->queue_depth) return 1; /* * This can happen for dual domain devices. An active * path change causes the ioaccel handle to change * * for example note the handle differences between p0 and p1 * Device WWN ,WWN hash,Handle * D016 p0|0x3 [02]P2E:01:01,0x5000C5005FC4DACA,0x9B5616,0x01030003 * p1 0x5000C5005FC4DAC9,0x6798C0,0x00040004
*/ if (dev1->ioaccel_handle != dev2->ioaccel_handle) return 1; return 0;
}
/* Find needle in haystack. If exact match found, return DEVICE_SAME, * and return needle location in *index. If scsi3addr matches, but not * vendor, model, serial num, etc. return DEVICE_CHANGED, and return needle * location in *index. * In the case of a minor device attribute change, such as RAID level, just * return DEVICE_UPDATED, along with the updated device's location in index. * If needle not found, return DEVICE_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;
}
}
/* * Figure the list of physical drive pointers for a logical drive with * raid offload configured.
*/ 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;
}
/* * This can happen if a physical drive is removed and * the logical drive is degraded. In that case, the RAID * map data will refer to a physical disk which isn't actually * present. And in that case offload_enabled should already * be 0, but we'll turn it off here just in case
*/ 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) /* * This is correct for reads, too high for full stripe writes, * way too high for partial stripe writes
*/
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 offload is currently enabled, the RAID map and * phys_disk[] assignment *better* not be changing * because we would be changing ioaccel phsy_disk[] pointers * on a ioaccel volume processing I/O requests. * * If an ioaccel volume status changed, initially because it was * re-configured and thus underwent a transformation, or * a drive failed, we would have received a state change * request and ioaccel should have been turned off. When the * transformation completes, we get another state change * request to turn ioaccel back on. In this case, we need * to update the ioaccel information. * * Thus: If it is not currently enabled, but will be after * the scan completes, make sure the ioaccel pointers * are up to date.
*/
if (!dev[i]->offload_enabled && dev[i]->offload_to_be_enabled)
hpsa_figure_phys_disk_ptrs(h, dev, ndevices, dev[i]);
}
}
/* * Allow for commands to drain
*/
device->removed = 1;
hpsa_wait_for_outstanding_commands_for_dev(h, device);
if (is_logical_device(device)) { /* RAID */
sdev = scsi_device_lookup(h->scsi_host, device->bus,
device->target, device->lun); if (sdev) {
scsi_remove_device(sdev);
scsi_device_put(sdev);
} else { /* * We don't expect to get here. Future commands * to this device will get a selection timeout as * if the device were gone.
*/
hpsa_show_dev_msg(KERN_WARNING, h, device, "didn't find device for removal.");
}
} else { /* HBA */
hpsa_remove_sas_device(device);
}
}
staticvoid adjust_hpsa_scsi_table(struct ctlr_info *h, struct hpsa_scsi_dev_t *sd[], int nsds)
{ /* sd contains scsi3 addresses and devtypes, and inquiry * data. This function takes what's in sd to be the current * reality and updates h->dev[] to reflect that reality.
*/ int i, entry, device_change, changes = 0; struct hpsa_scsi_dev_t *csd; unsignedlong flags; struct hpsa_scsi_dev_t **added, **removed; int nadded, nremoved;
/* * A reset can cause a device status to change * re-schedule the scan to see what happened.
*/
spin_lock_irqsave(&h->reset_lock, flags); if (h->reset_in_progress) {
h->drv_req_rescan = 1;
spin_unlock_irqrestore(&h->reset_lock, flags); return;
}
spin_unlock_irqrestore(&h->reset_lock, flags);
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[] and remove them from h->dev[], and for any * devices which have changed, remove the old device * info and add the new device info. * If minor device attributes change, just update * the existing device structure.
*/
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 * at the bottom of hpsa_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 * listed in h->dev[], adding them if they aren't found
*/
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 * as the SCSI mid-layer does not handle such devices well. * It relentlessly loops sending TUR at 3Hz, then READ(10) * at 160Hz, and prevents the system from coming up.
*/ 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);
/* * Now that h->dev[]->phys_disk[] is coherent, we can enable * any logical drives that need it enabled. * * The raid map should be current by now. * * We are updating the device list used for I/O requests.
*/ 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 * brought online later. This must be done without holding h->devlock, * so don't touch h->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 * (or if there are no changes) scsi_scan_host will do it later the * first time through.
*/ 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, * since it didn't get added to scsi mid layer
*/
fixup_botched_add(h, added[i]);
h->drv_req_rescan = 1;
}
free_and_out:
kfree(added);
kfree(removed);
}
/* * Lookup bus/target/lun and return corresponding struct hpsa_scsi_dev_t * * Assume's h->devlock is held.
*/ 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;
}
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.