aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/hpsa.c
diff options
context:
space:
mode:
authorStephen M. Cameron <scameron@beardog.cce.hp.com>2012-05-01 12:42:51 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-05-10 04:14:29 -0400
commit75167d2cc7654f57b90497fe90b1f0ae946c22a6 (patch)
treee882cc25860896d37f5ae4b982c1333fa7bc38ac /drivers/scsi/hpsa.c
parent5a3d16f51ef62bf17c9752c469db881dd12bce9b (diff)
[SCSI] hpsa: add abort error handler function
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.c221
1 files changed, 220 insertions, 1 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 1ceea8a42ee7..a2c99245b82c 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -159,6 +159,7 @@ static int hpsa_change_queue_depth(struct scsi_device *sdev,
159 int qdepth, int reason); 159 int qdepth, int reason);
160 160
161static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); 161static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
162static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd);
162static int hpsa_slave_alloc(struct scsi_device *sdev); 163static int hpsa_slave_alloc(struct scsi_device *sdev);
163static void hpsa_slave_destroy(struct scsi_device *sdev); 164static void hpsa_slave_destroy(struct scsi_device *sdev);
164 165
@@ -180,6 +181,7 @@ static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
180static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id); 181static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
181static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev, 182static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
182 void __iomem *vaddr, int wait_for_ready); 183 void __iomem *vaddr, int wait_for_ready);
184static inline void finish_cmd(struct CommandList *c);
183#define BOARD_NOT_READY 0 185#define BOARD_NOT_READY 0
184#define BOARD_READY 1 186#define BOARD_READY 1
185 187
@@ -507,6 +509,7 @@ static struct scsi_host_template hpsa_driver_template = {
507 .change_queue_depth = hpsa_change_queue_depth, 509 .change_queue_depth = hpsa_change_queue_depth,
508 .this_id = -1, 510 .this_id = -1,
509 .use_clustering = ENABLE_CLUSTERING, 511 .use_clustering = ENABLE_CLUSTERING,
512 .eh_abort_handler = hpsa_eh_abort_handler,
510 .eh_device_reset_handler = hpsa_eh_device_reset_handler, 513 .eh_device_reset_handler = hpsa_eh_device_reset_handler,
511 .ioctl = hpsa_ioctl, 514 .ioctl = hpsa_ioctl,
512 .slave_alloc = hpsa_slave_alloc, 515 .slave_alloc = hpsa_slave_alloc,
@@ -2352,6 +2355,191 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
2352 return FAILED; 2355 return FAILED;
2353} 2356}
2354 2357
2358static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
2359 struct CommandList *abort)
2360{
2361 int rc = IO_OK;
2362 struct CommandList *c;
2363 struct ErrorInfo *ei;
2364
2365 c = cmd_special_alloc(h);
2366 if (c == NULL) { /* trouble... */
2367 dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
2368 return -ENOMEM;
2369 }
2370
2371 fill_cmd(c, HPSA_ABORT_MSG, h, abort, 0, 0, scsi3addr, TYPE_MSG);
2372 hpsa_scsi_do_simple_cmd_core(h, c);
2373 dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n",
2374 __func__, abort->Header.Tag.upper, abort->Header.Tag.lower);
2375 /* no unmap needed here because no data xfer. */
2376
2377 ei = c->err_info;
2378 switch (ei->CommandStatus) {
2379 case CMD_SUCCESS:
2380 break;
2381 case CMD_UNABORTABLE: /* Very common, don't make noise. */
2382 rc = -1;
2383 break;
2384 default:
2385 dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: interpreting error.\n",
2386 __func__, abort->Header.Tag.upper,
2387 abort->Header.Tag.lower);
2388 hpsa_scsi_interpret_error(c);
2389 rc = -1;
2390 break;
2391 }
2392 cmd_special_free(h, c);
2393 dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n", __func__,
2394 abort->Header.Tag.upper, abort->Header.Tag.lower);
2395 return rc;
2396}
2397
2398/*
2399 * hpsa_find_cmd_in_queue
2400 *
2401 * Used to determine whether a command (find) is still present
2402 * in queue_head. Optionally excludes the last element of queue_head.
2403 *
2404 * This is used to avoid unnecessary aborts. Commands in h->reqQ have
2405 * not yet been submitted, and so can be aborted by the driver without
2406 * sending an abort to the hardware.
2407 *
2408 * Returns pointer to command if found in queue, NULL otherwise.
2409 */
2410static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h,
2411 struct scsi_cmnd *find, struct list_head *queue_head)
2412{
2413 unsigned long flags;
2414 struct CommandList *c = NULL; /* ptr into cmpQ */
2415
2416 if (!find)
2417 return 0;
2418 spin_lock_irqsave(&h->lock, flags);
2419 list_for_each_entry(c, queue_head, list) {
2420 if (c->scsi_cmd == NULL) /* e.g.: passthru ioctl */
2421 continue;
2422 if (c->scsi_cmd == find) {
2423 spin_unlock_irqrestore(&h->lock, flags);
2424 return c;
2425 }
2426 }
2427 spin_unlock_irqrestore(&h->lock, flags);
2428 return NULL;
2429}
2430
2431/* Send an abort for the specified command.
2432 * If the device and controller support it,
2433 * send a task abort request.
2434 */
2435static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
2436{
2437
2438 int i, rc;
2439 struct ctlr_info *h;
2440 struct hpsa_scsi_dev_t *dev;
2441 struct CommandList *abort; /* pointer to command to be aborted */
2442 struct CommandList *found;
2443 struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */
2444 char msg[256]; /* For debug messaging. */
2445 int ml = 0;
2446
2447 /* Find the controller of the command to be aborted */
2448 h = sdev_to_hba(sc->device);
2449 if (WARN(h == NULL,
2450 "ABORT REQUEST FAILED, Controller lookup failed.\n"))
2451 return FAILED;
2452
2453 /* Check that controller supports some kind of task abort */
2454 if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) &&
2455 !(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags))
2456 return FAILED;
2457
2458 memset(msg, 0, sizeof(msg));
2459 ml += sprintf(msg+ml, "ABORT REQUEST on C%d:B%d:T%d:L%d ",
2460 h->scsi_host->host_no, sc->device->channel,
2461 sc->device->id, sc->device->lun);
2462
2463 /* Find the device of the command to be aborted */
2464 dev = sc->device->hostdata;
2465 if (!dev) {
2466 dev_err(&h->pdev->dev, "%s FAILED, Device lookup failed.\n",
2467 msg);
2468 return FAILED;
2469 }
2470
2471 /* Get SCSI command to be aborted */
2472 abort = (struct CommandList *) sc->host_scribble;
2473 if (abort == NULL) {
2474 dev_err(&h->pdev->dev, "%s FAILED, Command to abort is NULL.\n",
2475 msg);
2476 return FAILED;
2477 }
2478
2479 ml += sprintf(msg+ml, "Tag:0x%08x:%08x ",
2480 abort->Header.Tag.upper, abort->Header.Tag.lower);
2481 as = (struct scsi_cmnd *) abort->scsi_cmd;
2482 if (as != NULL)
2483 ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ",
2484 as->cmnd[0], as->serial_number);
2485 dev_dbg(&h->pdev->dev, "%s\n", msg);
2486 dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n",
2487 h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
2488
2489 /* Search reqQ to See if command is queued but not submitted,
2490 * if so, complete the command with aborted status and remove
2491 * it from the reqQ.
2492 */
2493 found = hpsa_find_cmd_in_queue(h, sc, &h->reqQ);
2494 if (found) {
2495 found->err_info->CommandStatus = CMD_ABORTED;
2496 finish_cmd(found);
2497 dev_info(&h->pdev->dev, "%s Request SUCCEEDED (driver queue).\n",
2498 msg);
2499 return SUCCESS;
2500 }
2501
2502 /* not in reqQ, if also not in cmpQ, must have already completed */
2503 found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
2504 if (!found) {
2505 dev_dbg(&h->pdev->dev, "%s Request FAILED (not known to driver).\n",
2506 msg);
2507 return SUCCESS;
2508 }
2509
2510 /*
2511 * Command is in flight, or possibly already completed
2512 * by the firmware (but not to the scsi mid layer) but we can't
2513 * distinguish which. Send the abort down.
2514 */
2515 rc = hpsa_send_abort(h, dev->scsi3addr, abort);
2516 if (rc != 0) {
2517 dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg);
2518 dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n",
2519 h->scsi_host->host_no,
2520 dev->bus, dev->target, dev->lun);
2521 return FAILED;
2522 }
2523 dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg);
2524
2525 /* If the abort(s) above completed and actually aborted the
2526 * command, then the command to be aborted should already be
2527 * completed. If not, wait around a bit more to see if they
2528 * manage to complete normally.
2529 */
2530#define ABORT_COMPLETE_WAIT_SECS 30
2531 for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) {
2532 found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
2533 if (!found)
2534 return SUCCESS;
2535 msleep(100);
2536 }
2537 dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n",
2538 msg, ABORT_COMPLETE_WAIT_SECS);
2539 return FAILED;
2540}
2541
2542
2355/* 2543/*
2356 * For operations that cannot sleep, a command block is allocated at init, 2544 * For operations that cannot sleep, a command block is allocated at init,
2357 * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track 2545 * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
@@ -2884,6 +3072,7 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
2884 int cmd_type) 3072 int cmd_type)
2885{ 3073{
2886 int pci_dir = XFER_NONE; 3074 int pci_dir = XFER_NONE;
3075 struct CommandList *a; /* for commands to be aborted */
2887 3076
2888 c->cmd_type = CMD_IOCTL_PEND; 3077 c->cmd_type = CMD_IOCTL_PEND;
2889 c->Header.ReplyQueue = 0; 3078 c->Header.ReplyQueue = 0;
@@ -2967,8 +3156,35 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
2967 c->Request.CDB[5] = 0x00; 3156 c->Request.CDB[5] = 0x00;
2968 c->Request.CDB[6] = 0x00; 3157 c->Request.CDB[6] = 0x00;
2969 c->Request.CDB[7] = 0x00; 3158 c->Request.CDB[7] = 0x00;
3159 break;
3160 case HPSA_ABORT_MSG:
3161 a = buff; /* point to command to be aborted */
3162 dev_dbg(&h->pdev->dev, "Abort Tag:0x%08x:%08x using request Tag:0x%08x:%08x\n",
3163 a->Header.Tag.upper, a->Header.Tag.lower,
3164 c->Header.Tag.upper, c->Header.Tag.lower);
3165 c->Request.CDBLen = 16;
3166 c->Request.Type.Type = TYPE_MSG;
3167 c->Request.Type.Attribute = ATTR_SIMPLE;
3168 c->Request.Type.Direction = XFER_WRITE;
3169 c->Request.Timeout = 0; /* Don't time out */
3170 c->Request.CDB[0] = HPSA_TASK_MANAGEMENT;
3171 c->Request.CDB[1] = HPSA_TMF_ABORT_TASK;
3172 c->Request.CDB[2] = 0x00; /* reserved */
3173 c->Request.CDB[3] = 0x00; /* reserved */
3174 /* Tag to abort goes in CDB[4]-CDB[11] */
3175 c->Request.CDB[4] = a->Header.Tag.lower & 0xFF;
3176 c->Request.CDB[5] = (a->Header.Tag.lower >> 8) & 0xFF;
3177 c->Request.CDB[6] = (a->Header.Tag.lower >> 16) & 0xFF;
3178 c->Request.CDB[7] = (a->Header.Tag.lower >> 24) & 0xFF;
3179 c->Request.CDB[8] = a->Header.Tag.upper & 0xFF;
3180 c->Request.CDB[9] = (a->Header.Tag.upper >> 8) & 0xFF;
3181 c->Request.CDB[10] = (a->Header.Tag.upper >> 16) & 0xFF;
3182 c->Request.CDB[11] = (a->Header.Tag.upper >> 24) & 0xFF;
3183 c->Request.CDB[12] = 0x00; /* reserved */
3184 c->Request.CDB[13] = 0x00; /* reserved */
3185 c->Request.CDB[14] = 0x00; /* reserved */
3186 c->Request.CDB[15] = 0x00; /* reserved */
2970 break; 3187 break;
2971
2972 default: 3188 default:
2973 dev_warn(&h->pdev->dev, "unknown message type %d\n", 3189 dev_warn(&h->pdev->dev, "unknown message type %d\n",
2974 cmd); 3190 cmd);
@@ -3848,6 +4064,9 @@ static void __devinit hpsa_find_board_params(struct ctlr_info *h)
3848 h->maxsgentries = 31; /* default to traditional values */ 4064 h->maxsgentries = 31; /* default to traditional values */
3849 h->chainsize = 0; 4065 h->chainsize = 0;
3850 } 4066 }
4067
4068 /* Find out what task management functions are supported and cache */
4069 h->TMFSupportFlags = readl(&(h->cfgtable->TMFSupportFlags));
3851} 4070}
3852 4071
3853static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) 4072static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)