|
@@ -2355,8 +2355,23 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
|
|
|
return FAILED;
|
|
|
}
|
|
|
|
|
|
+static void swizzle_abort_tag(u8 *tag)
|
|
|
+{
|
|
|
+ u8 original_tag[8];
|
|
|
+
|
|
|
+ memcpy(original_tag, tag, 8);
|
|
|
+ tag[0] = original_tag[3];
|
|
|
+ tag[1] = original_tag[2];
|
|
|
+ tag[2] = original_tag[1];
|
|
|
+ tag[3] = original_tag[0];
|
|
|
+ tag[4] = original_tag[7];
|
|
|
+ tag[5] = original_tag[6];
|
|
|
+ tag[6] = original_tag[5];
|
|
|
+ tag[7] = original_tag[4];
|
|
|
+}
|
|
|
+
|
|
|
static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
|
|
|
- struct CommandList *abort)
|
|
|
+ struct CommandList *abort, int swizzle)
|
|
|
{
|
|
|
int rc = IO_OK;
|
|
|
struct CommandList *c;
|
|
@@ -2369,6 +2384,8 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
|
|
|
}
|
|
|
|
|
|
fill_cmd(c, HPSA_ABORT_MSG, h, abort, 0, 0, scsi3addr, TYPE_MSG);
|
|
|
+ if (swizzle)
|
|
|
+ swizzle_abort_tag(&c->Request.CDB[4]);
|
|
|
hpsa_scsi_do_simple_cmd_core(h, c);
|
|
|
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: do_simple_cmd_core completed.\n",
|
|
|
__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,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
|
|
|
+ u8 *tag, struct list_head *queue_head)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ struct CommandList *c;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&h->lock, flags);
|
|
|
+ list_for_each_entry(c, queue_head, list) {
|
|
|
+ if (memcmp(&c->Header.Tag, tag, 8) != 0)
|
|
|
+ continue;
|
|
|
+ spin_unlock_irqrestore(&h->lock, flags);
|
|
|
+ return c;
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&h->lock, flags);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* Some Smart Arrays need the abort tag swizzled, and some don't. It's hard to
|
|
|
+ * tell which kind we're dealing with, so we send the abort both ways. There
|
|
|
+ * shouldn't be any collisions between swizzled and unswizzled tags due to the
|
|
|
+ * way we construct our tags but we check anyway in case the assumptions which
|
|
|
+ * make this true someday become false.
|
|
|
+ */
|
|
|
+static int hpsa_send_abort_both_ways(struct ctlr_info *h,
|
|
|
+ unsigned char *scsi3addr, struct CommandList *abort)
|
|
|
+{
|
|
|
+ u8 swizzled_tag[8];
|
|
|
+ struct CommandList *c;
|
|
|
+ int rc = 0, rc2 = 0;
|
|
|
+
|
|
|
+ /* we do not expect to find the swizzled tag in our queue, but
|
|
|
+ * check anyway just to be sure the assumptions which make this
|
|
|
+ * the case haven't become wrong.
|
|
|
+ */
|
|
|
+ memcpy(swizzled_tag, &abort->Request.CDB[4], 8);
|
|
|
+ swizzle_abort_tag(swizzled_tag);
|
|
|
+ c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ);
|
|
|
+ if (c != NULL) {
|
|
|
+ dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n");
|
|
|
+ return hpsa_send_abort(h, scsi3addr, abort, 0);
|
|
|
+ }
|
|
|
+ rc = hpsa_send_abort(h, scsi3addr, abort, 0);
|
|
|
+
|
|
|
+ /* if the command is still in our queue, we can't conclude that it was
|
|
|
+ * aborted (it might have just completed normally) but in any case
|
|
|
+ * we don't need to try to abort it another way.
|
|
|
+ */
|
|
|
+ c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ);
|
|
|
+ if (c)
|
|
|
+ rc2 = hpsa_send_abort(h, scsi3addr, abort, 1);
|
|
|
+ return rc && rc2;
|
|
|
+}
|
|
|
+
|
|
|
/* Send an abort for the specified command.
|
|
|
* If the device and controller support it,
|
|
|
* send a task abort request.
|
|
@@ -2512,7 +2582,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
|
|
|
* by the firmware (but not to the scsi mid layer) but we can't
|
|
|
* distinguish which. Send the abort down.
|
|
|
*/
|
|
|
- rc = hpsa_send_abort(h, dev->scsi3addr, abort);
|
|
|
+ rc = hpsa_send_abort_both_ways(h, dev->scsi3addr, abort);
|
|
|
if (rc != 0) {
|
|
|
dev_dbg(&h->pdev->dev, "%s Request FAILED.\n", msg);
|
|
|
dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n",
|