diff options
-rw-r--r-- | drivers/scsi/hpsa.c | 74 |
1 files changed, 72 insertions, 2 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index a2c99245b82c..87f8a1b8d2ea 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c | |||
@@ -2355,8 +2355,23 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) | |||
2355 | return FAILED; | 2355 | return FAILED; |
2356 | } | 2356 | } |
2357 | 2357 | ||
2358 | static void swizzle_abort_tag(u8 *tag) | ||
2359 | { | ||
2360 | u8 original_tag[8]; | ||
2361 | |||
2362 | memcpy(original_tag, tag, 8); | ||
2363 | tag[0] = original_tag[3]; | ||
2364 | tag[1] = original_tag[2]; | ||
2365 | tag[2] = original_tag[1]; | ||
2366 | tag[3] = original_tag[0]; | ||
2367 | tag[4] = original_tag[7]; | ||
2368 | tag[5] = original_tag[6]; | ||
2369 | tag[6] = original_tag[5]; | ||
2370 | tag[7] = original_tag[4]; | ||
2371 | } | ||
2372 | |||
2358 | static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, | 2373 | static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, |
2359 | struct CommandList *abort) | 2374 | struct CommandList *abort, int swizzle) |
2360 | { | 2375 | { |
2361 | int rc = IO_OK; | 2376 | int rc = IO_OK; |
2362 | struct CommandList *c; | 2377 | struct CommandList *c; |
@@ -2369,6 +2384,8 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr, | |||
2369 | } | 2384 | } |
2370 | 2385 | ||
2371 | fill_cmd(c, HPSA_ABORT_MSG, h, abort, 0, 0, scsi3addr, TYPE_MSG); | 2386 | fill_cmd(c, HPSA_ABORT_MSG, h, abort, 0, 0, scsi3addr, TYPE_MSG); |
2387 | if (swizzle) | ||
2388 | swizzle_abort_tag(&c->Request.CDB[4]); | ||
2372 | hpsa_scsi_do_simple_cmd_core(h, c); | 2389 | 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", | 2390 | 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); | 2391 | __func__, abort->Header.Tag.upper, abort->Header.Tag.lower); |
@@ -2428,6 +2445,59 @@ static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h, | |||
2428 | return NULL; | 2445 | return NULL; |
2429 | } | 2446 | } |
2430 | 2447 | ||
2448 | static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h, | ||
2449 | u8 *tag, struct list_head *queue_head) | ||
2450 | { | ||
2451 | unsigned long flags; | ||
2452 | struct CommandList *c; | ||
2453 | |||
2454 | spin_lock_irqsave(&h->lock, flags); | ||
2455 | list_for_each_entry(c, queue_head, list) { | ||
2456 | if (memcmp(&c->Header.Tag, tag, 8) != 0) | ||
2457 | continue; | ||
2458 | spin_unlock_irqrestore(&h->lock, flags); | ||
2459 | return c; | ||
2460 | } | ||
2461 | spin_unlock_irqrestore(&h->lock, flags); | ||
2462 | return NULL; | ||
2463 | } | ||
2464 | |||
2465 | /* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to | ||
2466 | * tell which kind we're dealing with, so we send the abort both ways. There | ||
2467 | * shouldn't be any collisions between swizzled and unswizzled tags due to the | ||
2468 | * way we construct our tags but we check anyway in case the assumptions which | ||
2469 | * make this true someday become false. | ||
2470 | */ | ||
2471 | static int hpsa_send_abort_both_ways(struct ctlr_info *h, | ||
2472 | unsigned char *scsi3addr, struct CommandList *abort) | ||
2473 | { | ||
2474 | u8 swizzled_tag[8]; | ||
2475 | struct CommandList *c; | ||
2476 | int rc = 0, rc2 = 0; | ||
2477 | |||
2478 | /* we do not expect to find the swizzled tag in our queue, but | ||
2479 | * check anyway just to be sure the assumptions which make this | ||
2480 | * the case haven't become wrong. | ||
2481 | */ | ||
2482 | memcpy(swizzled_tag, &abort->Request.CDB[4], 8); | ||
2483 | swizzle_abort_tag(swizzled_tag); | ||
2484 | c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ); | ||
2485 | if (c != NULL) { | ||
2486 | dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n"); | ||
2487 | return hpsa_send_abort(h, scsi3addr, abort, 0); | ||
2488 | } | ||
2489 | rc = hpsa_send_abort(h, scsi3addr, abort, 0); | ||
2490 | |||
2491 | /* if the command is still in our queue, we can't conclude that it was | ||
2492 | * aborted (it might have just completed normally) but in any case | ||
2493 | * we don't need to try to abort it another way. | ||
2494 | */ | ||
2495 | c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ); | ||
2496 | if (c) | ||
2497 | rc2 = hpsa_send_abort(h, scsi3addr, abort, 1); | ||
2498 | return rc && rc2; | ||
2499 | } | ||
2500 | |||
2431 | /* Send an abort for the specified command. | 2501 | /* Send an abort for the specified command. |
2432 | * If the device and controller support it, | 2502 | * If the device and controller support it, |
2433 | * send a task abort request. | 2503 | * send a task abort request. |
@@ -2512,7 +2582,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc) | |||
2512 | * by the firmware (but not to the scsi mid layer) but we can't | 2582 | * by the firmware (but not to the scsi mid layer) but we can't |
2513 | * distinguish which. Send the abort down. | 2583 | * distinguish which. Send the abort down. |
2514 | */ | 2584 | */ |
2515 | rc = hpsa_send_abort(h, dev->scsi3addr, abort); | 2585 | rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort); |
2516 | if (rc != 0) { | 2586 | if (rc != 0) { |
2517 | dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg); | 2587 | 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", | 2588 | dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n", |