| From fd1232b214af43a973443aec6a2808f16ee5bf70 Mon Sep 17 00:00:00 2001 |
| From: Mikulas Patocka <mpatocka@redhat.com> |
| Date: Tue, 8 Apr 2014 21:52:05 -0400 |
| Subject: sym53c8xx_2: Set DID_REQUEUE return code when aborting squeue |
| |
| From: Mikulas Patocka <mpatocka@redhat.com> |
| |
| commit fd1232b214af43a973443aec6a2808f16ee5bf70 upstream. |
| |
| This patch fixes I/O errors with the sym53c8xx_2 driver when the disk |
| returns QUEUE FULL status. |
| |
| When the controller encounters an error (including QUEUE FULL or BUSY |
| status), it aborts all not yet submitted requests in the function |
| sym_dequeue_from_squeue. |
| |
| This function aborts them with DID_SOFT_ERROR. |
| |
| If the disk has full tag queue, the request that caused the overflow is |
| aborted with QUEUE FULL status (and the scsi midlayer properly retries |
| it until it is accepted by the disk), but the sym53c8xx_2 driver aborts |
| the following requests with DID_SOFT_ERROR --- for them, the midlayer |
| does just a few retries and then signals the error up to sd. |
| |
| The result is that disk returning QUEUE FULL causes request failures. |
| |
| The error was reproduced on 53c895 with COMPAQ BD03685A24 disk |
| (rebranded ST336607LC) with command queue 48 or 64 tags. The disk has |
| 64 tags, but under some access patterns it return QUEUE FULL when there |
| are less than 64 pending tags. The SCSI specification allows returning |
| QUEUE FULL anytime and it is up to the host to retry. |
| |
| Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> |
| Cc: Matthew Wilcox <matthew@wil.cx> |
| Cc: James Bottomley <JBottomley@Parallels.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/scsi/sym53c8xx_2/sym_hipd.c | 4 ++++ |
| 1 file changed, 4 insertions(+) |
| |
| --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c |
| +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c |
| @@ -3000,7 +3000,11 @@ sym_dequeue_from_squeue(struct sym_hcb * |
| if ((target == -1 || cp->target == target) && |
| (lun == -1 || cp->lun == lun) && |
| (task == -1 || cp->tag == task)) { |
| +#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING |
| sym_set_cam_status(cp->cmd, DID_SOFT_ERROR); |
| +#else |
| + sym_set_cam_status(cp->cmd, DID_REQUEUE); |
| +#endif |
| sym_remque(&cp->link_ccbq); |
| sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); |
| } |