summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hpsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/hpsa.c')
-rw-r--r--drivers/scsi/hpsa.c139
1 files changed, 112 insertions, 27 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 030d0023e1d2..d007ec18179a 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -293,6 +293,8 @@ static int detect_controller_lockup(struct ctlr_info *h);
static void hpsa_disable_rld_caching(struct ctlr_info *h);
static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
struct ReportExtendedLUNdata *buf, int bufsize);
+static bool hpsa_vpd_page_supported(struct ctlr_info *h,
+ unsigned char scsi3addr[], u8 page);
static int hpsa_luns_changed(struct ctlr_info *h);
static bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c,
struct hpsa_scsi_dev_t *dev,
@@ -2388,7 +2390,8 @@ static void hpsa_cmd_free_and_done(struct ctlr_info *h,
struct CommandList *c, struct scsi_cmnd *cmd)
{
hpsa_cmd_resolve_and_free(h, c);
- cmd->scsi_done(cmd);
+ if (cmd && cmd->scsi_done)
+ cmd->scsi_done(cmd);
}
static void hpsa_retry_cmd(struct ctlr_info *h, struct CommandList *c)
@@ -2489,7 +2492,17 @@ static void complete_scsi_command(struct CommandList *cp)
ei = cp->err_info;
cmd = cp->scsi_cmd;
h = cp->h;
+
+ if (!cmd->device) {
+ cmd->result = DID_NO_CONNECT << 16;
+ return hpsa_cmd_free_and_done(h, cp, cmd);
+ }
+
dev = cmd->device->hostdata;
+ if (!dev) {
+ cmd->result = DID_NO_CONNECT << 16;
+ return hpsa_cmd_free_and_done(h, cp, cmd);
+ }
c2 = &h->ioaccel2_cmd_pool[cp->cmdindex];
scsi_dma_unmap(cmd); /* undo the DMA mappings */
@@ -2504,8 +2517,15 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
- if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1)
- atomic_dec(&cp->phys_disk->ioaccel_cmds_out);
+ if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1) {
+ if (dev->physical_device && dev->expose_device &&
+ dev->removed) {
+ cmd->result = DID_NO_CONNECT << 16;
+ return hpsa_cmd_free_and_done(h, cp, cmd);
+ }
+ if (likely(cp->phys_disk != NULL))
+ atomic_dec(&cp->phys_disk->ioaccel_cmds_out);
+ }
/*
* We check for lockup status here as it may be set for
@@ -3074,11 +3094,19 @@ static void hpsa_get_raid_level(struct ctlr_info *h,
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return;
- rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0xC1, buf, 64);
+
+ if (!hpsa_vpd_page_supported(h, scsi3addr,
+ HPSA_VPD_LV_DEVICE_GEOMETRY))
+ goto exit;
+
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE |
+ HPSA_VPD_LV_DEVICE_GEOMETRY, buf, 64);
+
if (rc == 0)
*raid_level = buf[8];
if (*raid_level > RAID_UNKNOWN)
*raid_level = RAID_UNKNOWN;
+exit:
kfree(buf);
return;
}
@@ -3436,7 +3464,7 @@ static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr,
}
/* Get a device id from inquiry page 0x83 */
-static int hpsa_vpd_page_supported(struct ctlr_info *h,
+static bool hpsa_vpd_page_supported(struct ctlr_info *h,
unsigned char scsi3addr[], u8 page)
{
int rc;
@@ -3446,7 +3474,7 @@ static int hpsa_vpd_page_supported(struct ctlr_info *h,
buf = kzalloc(256, GFP_KERNEL);
if (!buf)
- return 0;
+ return false;
/* Get the size of the page list first */
rc = hpsa_scsi_do_inquiry(h, scsi3addr,
@@ -3473,10 +3501,10 @@ static int hpsa_vpd_page_supported(struct ctlr_info *h,
goto exit_supported;
exit_unsupported:
kfree(buf);
- return 0;
+ return false;
exit_supported:
kfree(buf);
- return 1;
+ return true;
}
static void hpsa_get_ioaccel_status(struct ctlr_info *h,
@@ -3525,18 +3553,25 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
int rc;
unsigned char *buf;
- if (buflen > 16)
- buflen = 16;
+ /* Does controller have VPD for device id? */
+ if (!hpsa_vpd_page_supported(h, scsi3addr, HPSA_VPD_LV_DEVICE_ID))
+ return 1; /* not supported */
+
buf = kzalloc(64, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64);
- if (rc == 0)
- memcpy(device_id, &buf[index], buflen);
+
+ rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE |
+ HPSA_VPD_LV_DEVICE_ID, buf, 64);
+ if (rc == 0) {
+ if (buflen > 16)
+ buflen = 16;
+ memcpy(device_id, &buf[8], buflen);
+ }
kfree(buf);
- return rc != 0;
+ return rc; /*0 - got id, otherwise, didn't */
}
static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
@@ -3807,8 +3842,15 @@ static int hpsa_update_device_info(struct ctlr_info *h,
sizeof(this_device->model));
memset(this_device->device_id, 0,
sizeof(this_device->device_id));
- hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
- sizeof(this_device->device_id));
+ if (hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
+ sizeof(this_device->device_id)))
+ dev_err(&h->pdev->dev,
+ "hpsa%d: %s: can't get device id for host %d:C0:T%d:L%d\t%s\t%.16s\n",
+ h->ctlr, __func__,
+ h->scsi_host->host_no,
+ this_device->target, this_device->lun,
+ scsi_device_type(this_device->devtype),
+ this_device->model);
if ((this_device->devtype == TYPE_DISK ||
this_device->devtype == TYPE_ZBC) &&
@@ -4034,7 +4076,17 @@ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h,
struct bmic_identify_physical_device *id_phys)
{
int rc;
- struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
+ struct ext_report_lun_entry *rle;
+
+ /*
+ * external targets don't support BMIC
+ */
+ if (dev->external) {
+ dev->queue_depth = 7;
+ return;
+ }
+
+ rle = &rlep->LUN[rle_index];
dev->ioaccel_handle = rle->ioaccel_handle;
if ((rle->device_flags & 0x08) && dev->ioaccel_handle)
@@ -4270,6 +4322,11 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
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);
+
/*
* Skip over some devices such as a spare.
*/
@@ -4295,11 +4352,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h)
continue;
}
- /* Determine if this is a lun from an external target array */
- tmpdevice->external =
- figure_external_status(h, raid_ctlr_position, i,
- nphysicals, nlocal_logicals);
-
figure_bus_target_lun(h, lunaddrbytes, tmpdevice);
hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes);
this_device = currentsd[ncurrent];
@@ -4513,7 +4565,9 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
case READ_6:
case READ_12:
if (*cdb_len == 6) {
- block = get_unaligned_be16(&cdb[2]);
+ block = (((cdb[1] & 0x1F) << 16) |
+ (cdb[2] << 8) |
+ cdb[3]);
block_cnt = cdb[4];
if (block_cnt == 0)
block_cnt = 256;
@@ -4638,6 +4692,9 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
struct scsi_cmnd *cmd = c->scsi_cmd;
struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+ if (!dev)
+ return -1;
+
c->phys_disk = dev;
return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle,
@@ -4670,9 +4727,11 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h,
*/
switch (cmd->cmnd[0]) {
/* Required? 6-byte cdbs eliminated by fixup_ioaccel_cdb */
- case WRITE_6:
case READ_6:
- first_block = get_unaligned_be16(&cmd->cmnd[2]);
+ case WRITE_6:
+ first_block = (((cmd->cmnd[1] & 0x1F) << 16) |
+ (cmd->cmnd[2] << 8) |
+ cmd->cmnd[3]);
break;
case WRITE_10:
case READ_10:
@@ -4714,6 +4773,12 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
u32 len;
u32 total_len = 0;
+ if (!cmd->device)
+ return -1;
+
+ if (!cmd->device->hostdata)
+ return -1;
+
BUG_ON(scsi_sg_count(cmd) > h->maxsgentries);
if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
@@ -4822,6 +4887,12 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk)
{
+ if (!c->scsi_cmd->device)
+ return -1;
+
+ if (!c->scsi_cmd->device->hostdata)
+ return -1;
+
/* Try to honor the device's queue depth */
if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) >
phys_disk->queue_depth) {
@@ -4902,12 +4973,17 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
#endif
int offload_to_mirror;
+ if (!dev)
+ return -1;
+
/* check for valid opcode, get LBA and block count */
switch (cmd->cmnd[0]) {
case WRITE_6:
is_write = 1;
case READ_6:
- first_block = get_unaligned_be16(&cmd->cmnd[2]);
+ first_block = (((cmd->cmnd[1] & 0x1F) << 16) |
+ (cmd->cmnd[2] << 8) |
+ cmd->cmnd[3]);
block_cnt = cmd->cmnd[4];
if (block_cnt == 0)
block_cnt = 256;
@@ -5314,6 +5390,9 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h,
struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
int rc = IO_ACCEL_INELIGIBLE;
+ if (!dev)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
cmd->host_scribble = (unsigned char *) c;
if (dev->offload_enabled) {
@@ -5852,6 +5931,9 @@ static void setup_ioaccel2_abort_cmd(struct CommandList *c, struct ctlr_info *h,
struct scsi_cmnd *scmd = command_to_abort->scsi_cmd;
struct hpsa_scsi_dev_t *dev = scmd->device->hostdata;
+ if (!dev)
+ return;
+
/*
* We're overlaying struct hpsa_tmf_struct on top of something which
* was allocated as a struct io_accel2_cmd, so we better be sure it
@@ -5935,7 +6017,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
"Reset as abort: Resetting physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
psa[0], psa[1], psa[2], psa[3],
psa[4], psa[5], psa[6], psa[7]);
- rc = hpsa_do_reset(h, dev, psa, HPSA_RESET_TYPE_TARGET, reply_queue);
+ rc = hpsa_do_reset(h, dev, psa, HPSA_PHYS_TARGET_RESET, reply_queue);
if (rc != 0) {
dev_warn(&h->pdev->dev,
"Reset as abort: Failed on physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
@@ -5972,6 +6054,9 @@ static int hpsa_send_abort_ioaccel2(struct ctlr_info *h,
struct io_accel2_cmd *c2;
dev = abort->scsi_cmd->device->hostdata;
+ if (!dev)
+ return -1;
+
if (!dev->offload_enabled && !dev->hba_ioaccel_enabled)
return -1;