Merge branch 'work.splice_read' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / drivers / scsi / hpsa.c
index 030d002..d007ec1 100644 (file)
@@ -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;