aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hpsa.c
diff options
context:
space:
mode:
authorScott Teel <scott.teel@hp.com>2014-02-18 14:56:45 -0500
committerJames Bottomley <JBottomley@Parallels.com>2014-03-15 13:19:06 -0400
commit54b6e9e97ace5ab58fa6afebeeee9032e328c0f1 (patch)
tree11a6ba9c019112f9afc00fc1f216dfd256bbb953 /drivers/scsi/hpsa.c
parentbf711ac654539182bf6935cd019d7bac17b7ca95 (diff)
[SCSI] hpsa: add task management for ioaccel mode 2
Underlying firmware cannot handle task abort on accelerated path (SSD Smart Path). Change abort requests for accelerated path commands to physical target reset. Send reset request on normal IO path. Signed-off-by: Scott Teel <scott.teel@hp.com> Signed-off-by: Mike Miller <michael.miller@canonical.com> Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/hpsa.c')
-rw-r--r--drivers/scsi/hpsa.c166
1 files changed, 163 insertions, 3 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 563cf2f588d2..498aaa872d06 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -2307,6 +2307,85 @@ static int add_ext_target_dev(struct ctlr_info *h,
2307} 2307}
2308 2308
2309/* 2309/*
2310 * Get address of physical disk used for an ioaccel2 mode command:
2311 * 1. Extract ioaccel2 handle from the command.
2312 * 2. Find a matching ioaccel2 handle from list of physical disks.
2313 * 3. Return:
2314 * 1 and set scsi3addr to address of matching physical
2315 * 0 if no matching physical disk was found.
2316 */
2317static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
2318 struct CommandList *ioaccel2_cmd_to_abort, unsigned char *scsi3addr)
2319{
2320 struct ReportExtendedLUNdata *physicals = NULL;
2321 int responsesize = 24; /* size of physical extended response */
2322 int extended = 2; /* flag forces reporting 'other dev info'. */
2323 int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize;
2324 u32 nphysicals = 0; /* number of reported physical devs */
2325 int found = 0; /* found match (1) or not (0) */
2326 u32 find; /* handle we need to match */
2327 int i;
2328 struct scsi_cmnd *scmd; /* scsi command within request being aborted */
2329 struct hpsa_scsi_dev_t *d; /* device of request being aborted */
2330 struct io_accel2_cmd *c2a; /* ioaccel2 command to abort */
2331 u32 it_nexus; /* 4 byte device handle for the ioaccel2 cmd */
2332 u32 scsi_nexus; /* 4 byte device handle for the ioaccel2 cmd */
2333
2334 if (ioaccel2_cmd_to_abort->cmd_type != CMD_IOACCEL2)
2335 return 0; /* no match */
2336
2337 /* point to the ioaccel2 device handle */
2338 c2a = &h->ioaccel2_cmd_pool[ioaccel2_cmd_to_abort->cmdindex];
2339 if (c2a == NULL)
2340 return 0; /* no match */
2341
2342 scmd = (struct scsi_cmnd *) ioaccel2_cmd_to_abort->scsi_cmd;
2343 if (scmd == NULL)
2344 return 0; /* no match */
2345
2346 d = scmd->device->hostdata;
2347 if (d == NULL)
2348 return 0; /* no match */
2349
2350 it_nexus = cpu_to_le32((u32) d->ioaccel_handle);
2351 scsi_nexus = cpu_to_le32((u32) c2a->scsi_nexus);
2352 find = c2a->scsi_nexus;
2353
2354 /* Get the list of physical devices */
2355 physicals = kzalloc(reportsize, GFP_KERNEL);
2356 if (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals,
2357 reportsize, extended)) {
2358 dev_err(&h->pdev->dev,
2359 "Can't lookup %s device handle: report physical LUNs failed.\n",
2360 "HP SSD Smart Path");
2361 kfree(physicals);
2362 return 0;
2363 }
2364 nphysicals = be32_to_cpu(*((__be32 *)physicals->LUNListLength)) /
2365 responsesize;
2366
2367
2368 /* find ioaccel2 handle in list of physicals: */
2369 for (i = 0; i < nphysicals; i++) {
2370 /* handle is in bytes 28-31 of each lun */
2371 if (memcmp(&((struct ReportExtendedLUNdata *)
2372 physicals)->LUN[i][20], &find, 4) != 0) {
2373 continue; /* didn't match */
2374 }
2375 found = 1;
2376 memcpy(scsi3addr, &((struct ReportExtendedLUNdata *)
2377 physicals)->LUN[i][0], 8);
2378 break; /* found it */
2379 }
2380
2381 kfree(physicals);
2382 if (found)
2383 return 1;
2384 else
2385 return 0;
2386
2387}
2388/*
2310 * Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev, 2389 * Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev,
2311 * logdev. The number of luns in physdev and logdev are returned in 2390 * logdev. The number of luns in physdev and logdev are returned in
2312 * *nphysicals and *nlogicals, respectively. 2391 * *nphysicals and *nlogicals, respectively.
@@ -3423,12 +3502,20 @@ static void hpsa_get_tag(struct ctlr_info *h,
3423 &h->ioaccel_cmd_pool[c->cmdindex]; 3502 &h->ioaccel_cmd_pool[c->cmdindex];
3424 *tagupper = cm1->Tag.upper; 3503 *tagupper = cm1->Tag.upper;
3425 *taglower = cm1->Tag.lower; 3504 *taglower = cm1->Tag.lower;
3426 } else { 3505 return;
3427 *tagupper = c->Header.Tag.upper; 3506 }
3428 *taglower = c->Header.Tag.lower; 3507 if (c->cmd_type == CMD_IOACCEL2) {
3508 struct io_accel2_cmd *cm2 = (struct io_accel2_cmd *)
3509 &h->ioaccel2_cmd_pool[c->cmdindex];
3510 *tagupper = cm2->Tag.upper;
3511 *taglower = cm2->Tag.lower;
3512 return;
3429 } 3513 }
3514 *tagupper = c->Header.Tag.upper;
3515 *taglower = c->Header.Tag.lower;
3430} 3516}
3431 3517
3518
3432static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, 3519static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
3433 struct CommandList *abort, int swizzle) 3520 struct CommandList *abort, int swizzle)
3434{ 3521{
@@ -3524,6 +3611,71 @@ static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
3524 return NULL; 3611 return NULL;
3525} 3612}
3526 3613
3614/* ioaccel2 path firmware cannot handle abort task requests.
3615 * Change abort requests to physical target reset, and send to the
3616 * address of the physical disk used for the ioaccel 2 command.
3617 * Return 0 on success (IO_OK)
3618 * -1 on failure
3619 */
3620
3621static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
3622 unsigned char *scsi3addr, struct CommandList *abort)
3623{
3624 int rc = IO_OK;
3625 struct scsi_cmnd *scmd; /* scsi command within request being aborted */
3626 struct hpsa_scsi_dev_t *dev; /* device to which scsi cmd was sent */
3627 unsigned char phys_scsi3addr[8]; /* addr of phys disk with volume */
3628 unsigned char *psa = &phys_scsi3addr[0];
3629
3630 /* Get a pointer to the hpsa logical device. */
3631 scmd = (struct scsi_cmnd *) abort->scsi_cmd;
3632 dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata);
3633 if (dev == NULL) {
3634 dev_warn(&h->pdev->dev,
3635 "Cannot abort: no device pointer for command.\n");
3636 return -1; /* not abortable */
3637 }
3638
3639 if (!dev->offload_enabled) {
3640 dev_warn(&h->pdev->dev,
3641 "Can't abort: device is not operating in HP SSD Smart Path mode.\n");
3642 return -1; /* not abortable */
3643 }
3644
3645 /* Incoming scsi3addr is logical addr. We need physical disk addr. */
3646 if (!hpsa_get_pdisk_of_ioaccel2(h, abort, psa)) {
3647 dev_warn(&h->pdev->dev, "Can't abort: Failed lookup of physical address.\n");
3648 return -1; /* not abortable */
3649 }
3650
3651 /* send the reset */
3652 rc = hpsa_send_reset(h, psa, HPSA_RESET_TYPE_TARGET);
3653 if (rc != 0) {
3654 dev_warn(&h->pdev->dev,
3655 "Reset as abort: Failed on physical device at scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
3656 psa[0], psa[1], psa[2], psa[3],
3657 psa[4], psa[5], psa[6], psa[7]);
3658 return rc; /* failed to reset */
3659 }
3660
3661 /* wait for device to recover */
3662 if (wait_for_device_to_become_ready(h, psa) != 0) {
3663 dev_warn(&h->pdev->dev,
3664 "Reset as abort: Failed: Device never recovered from reset: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
3665 psa[0], psa[1], psa[2], psa[3],
3666 psa[4], psa[5], psa[6], psa[7]);
3667 return -1; /* failed to recover */
3668 }
3669
3670 /* device recovered */
3671 dev_info(&h->pdev->dev,
3672 "Reset as abort: Device recovered from reset: scsi3addr 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
3673 psa[0], psa[1], psa[2], psa[3],
3674 psa[4], psa[5], psa[6], psa[7]);
3675
3676 return rc; /* success */
3677}
3678
3527/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to 3679/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to
3528 * tell which kind we're dealing with, so we send the abort both ways. There 3680 * tell which kind we're dealing with, so we send the abort both ways. There
3529 * shouldn't be any collisions between swizzled and unswizzled tags due to the 3681 * shouldn't be any collisions between swizzled and unswizzled tags due to the
@@ -3537,6 +3689,14 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h,
3537 struct CommandList *c; 3689 struct CommandList *c;
3538 int rc = 0, rc2 = 0; 3690 int rc = 0, rc2 = 0;
3539 3691
3692 /* ioccelerator mode 2 commands should be aborted via the
3693 * accelerated path, since RAID path is unaware of these commands,
3694 * but underlying firmware can't handle abort TMF.
3695 * Change abort to physical device reset.
3696 */
3697 if (abort->cmd_type == CMD_IOACCEL2)
3698 return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort);
3699
3540 /* we do not expect to find the swizzled tag in our queue, but 3700 /* we do not expect to find the swizzled tag in our queue, but
3541 * check anyway just to be sure the assumptions which make this 3701 * check anyway just to be sure the assumptions which make this
3542 * the case haven't become wrong. 3702 * the case haven't become wrong.