aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla4xxx
diff options
context:
space:
mode:
authorVikas Chaudhary <vikas.chaudhary@qlogic.com>2010-04-28 02:12:24 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-05-02 15:40:12 -0400
commit09a0f719896659a6c32df11426e55795012c06ff (patch)
treed80dce19cc98f247970c98a0b003fa1f97f98764 /drivers/scsi/qla4xxx
parent5369887a95da9509163931b21f61a94da09dac15 (diff)
[SCSI] qla4xxx: added support for abort task management command
* Handles SCSI command aborts. * Serialization srb between error handler and command completion path. Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com> Signed-off-by: Ravi Anand <ravi.anand@qlogic.com> Reviewed-by: Mike Christie <michaelc@cs.wisc.edu> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/qla4xxx')
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h1
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h3
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c6
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c53
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c68
6 files changed, 124 insertions, 9 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index b6f2d0152454..428802616e33 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -172,7 +172,7 @@ struct srb {
172 172
173 struct scsi_cmnd *cmd; /* (4) SCSI command block */ 173 struct scsi_cmnd *cmd; /* (4) SCSI command block */
174 dma_addr_t dma_handle; /* (4) for unmap of single transfers */ 174 dma_addr_t dma_handle; /* (4) for unmap of single transfers */
175 atomic_t ref_count; /* reference count for this srb */ 175 struct kref srb_ref; /* reference count for this srb */
176 uint32_t fw_ddb_index; 176 uint32_t fw_ddb_index;
177 uint8_t err_id; /* error id */ 177 uint8_t err_id; /* error id */
178#define SRB_ERR_PORT 1 /* Request failed because "port down" */ 178#define SRB_ERR_PORT 1 /* Request failed because "port down" */
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index dfe7b4dd3912..855226e08665 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -215,6 +215,7 @@ union external_hw_config_reg {
215/* Mailbox command definitions */ 215/* Mailbox command definitions */
216#define MBOX_CMD_ABOUT_FW 0x0009 216#define MBOX_CMD_ABOUT_FW 0x0009
217#define MBOX_CMD_PING 0x000B 217#define MBOX_CMD_PING 0x000B
218#define MBOX_CMD_ABORT_TASK 0x0015
218#define MBOX_CMD_LUN_RESET 0x0016 219#define MBOX_CMD_LUN_RESET 0x0016
219#define MBOX_CMD_TARGET_WARM_RESET 0x0017 220#define MBOX_CMD_TARGET_WARM_RESET 0x0017
220#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E 221#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 987658f5bc13..c4636f6cb3cb 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -25,6 +25,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);
25int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha); 25int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);
26int qla4xxx_relogin_device(struct scsi_qla_host * ha, 26int qla4xxx_relogin_device(struct scsi_qla_host * ha,
27 struct ddb_entry * ddb_entry); 27 struct ddb_entry * ddb_entry);
28int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb);
28int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, 29int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
29 int lun); 30 int lun);
30int qla4xxx_reset_target(struct scsi_qla_host * ha, 31int qla4xxx_reset_target(struct scsi_qla_host * ha,
@@ -65,7 +66,7 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
65int qla4xxx_init_rings(struct scsi_qla_host * ha); 66int qla4xxx_init_rings(struct scsi_qla_host * ha);
66struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, 67struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
67 uint32_t index); 68 uint32_t index);
68void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb); 69void qla4xxx_srb_compl(struct kref *ref);
69int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); 70int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
70int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, 71int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
71 uint32_t state, uint32_t conn_error); 72 uint32_t state, uint32_t conn_error);
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index ce5838eb685e..596c3031483c 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -97,7 +97,7 @@ qla4xxx_status_cont_entry(struct scsi_qla_host *ha,
97 97
98 /* Place command on done queue. */ 98 /* Place command on done queue. */
99 if (srb->req_sense_len == 0) { 99 if (srb->req_sense_len == 0) {
100 qla4xxx_srb_compl(ha, srb); 100 kref_put(&srb->srb_ref, qla4xxx_srb_compl);
101 ha->status_srb = NULL; 101 ha->status_srb = NULL;
102 } 102 }
103} 103}
@@ -329,7 +329,7 @@ status_entry_exit:
329 /* complete the request, if not waiting for status_continuation pkt */ 329 /* complete the request, if not waiting for status_continuation pkt */
330 srb->cc_stat = sts_entry->completionStatus; 330 srb->cc_stat = sts_entry->completionStatus;
331 if (ha->status_srb == NULL) 331 if (ha->status_srb == NULL)
332 qla4xxx_srb_compl(ha, srb); 332 kref_put(&srb->srb_ref, qla4xxx_srb_compl);
333} 333}
334 334
335/** 335/**
@@ -393,7 +393,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
393 /* ETRY normally by sending it back with 393 /* ETRY normally by sending it back with
394 * DID_BUS_BUSY */ 394 * DID_BUS_BUSY */
395 srb->cmd->result = DID_BUS_BUSY << 16; 395 srb->cmd->result = DID_BUS_BUSY << 16;
396 qla4xxx_srb_compl(ha, srb); 396 kref_put(&srb->srb_ref, qla4xxx_srb_compl);
397 break; 397 break;
398 398
399 case ET_CONTINUE: 399 case ET_CONTINUE:
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 43581ce3a1b6..e1315cd8c261 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -762,6 +762,59 @@ exit_get_event_log:
762} 762}
763 763
764/** 764/**
765 * qla4xxx_abort_task - issues Abort Task
766 * @ha: Pointer to host adapter structure.
767 * @srb: Pointer to srb entry
768 *
769 * This routine performs a LUN RESET on the specified target/lun.
770 * The caller must ensure that the ddb_entry and lun_entry pointers
771 * are valid before calling this routine.
772 **/
773int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb)
774{
775 uint32_t mbox_cmd[MBOX_REG_COUNT];
776 uint32_t mbox_sts[MBOX_REG_COUNT];
777 struct scsi_cmnd *cmd = srb->cmd;
778 int status = QLA_SUCCESS;
779 unsigned long flags = 0;
780 uint32_t index;
781
782 /*
783 * Send abort task command to ISP, so that the ISP will return
784 * request with ABORT status
785 */
786 memset(&mbox_cmd, 0, sizeof(mbox_cmd));
787 memset(&mbox_sts, 0, sizeof(mbox_sts));
788
789 spin_lock_irqsave(&ha->hardware_lock, flags);
790 index = (unsigned long)(unsigned char *)cmd->host_scribble;
791 spin_unlock_irqrestore(&ha->hardware_lock, flags);
792
793 /* Firmware already posted completion on response queue */
794 if (index == MAX_SRBS)
795 return status;
796
797 mbox_cmd[0] = MBOX_CMD_ABORT_TASK;
798 mbox_cmd[1] = srb->fw_ddb_index;
799 mbox_cmd[2] = index;
800 /* Immediate Command Enable */
801 mbox_cmd[5] = 0x01;
802
803 qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0],
804 &mbox_sts[0]);
805 if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE) {
806 status = QLA_ERROR;
807
808 DEBUG2(printk(KERN_WARNING "scsi%ld:%d:%d: abort task FAILED: "
809 "mbx0=%04X, mb1=%04X, mb2=%04X, mb3=%04X, mb4=%04X\n",
810 ha->host_no, cmd->device->id, cmd->device->lun, mbox_sts[0],
811 mbox_sts[1], mbox_sts[2], mbox_sts[3], mbox_sts[4]));
812 }
813
814 return status;
815}
816
817/**
765 * qla4xxx_reset_lun - issues LUN Reset 818 * qla4xxx_reset_lun - issues LUN Reset
766 * @ha: Pointer to host adapter structure. 819 * @ha: Pointer to host adapter structure.
767 * @db_entry: Pointer to device database entry 820 * @db_entry: Pointer to device database entry
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 2ca43f0ebcd6..38b1d38afca5 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -74,6 +74,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
74 */ 74 */
75static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, 75static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
76 void (*done) (struct scsi_cmnd *)); 76 void (*done) (struct scsi_cmnd *));
77static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
77static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); 78static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
78static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); 79static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
79static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); 80static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
@@ -88,6 +89,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
88 .proc_name = DRIVER_NAME, 89 .proc_name = DRIVER_NAME,
89 .queuecommand = qla4xxx_queuecommand, 90 .queuecommand = qla4xxx_queuecommand,
90 91
92 .eh_abort_handler = qla4xxx_eh_abort,
91 .eh_device_reset_handler = qla4xxx_eh_device_reset, 93 .eh_device_reset_handler = qla4xxx_eh_device_reset,
92 .eh_target_reset_handler = qla4xxx_eh_target_reset, 94 .eh_target_reset_handler = qla4xxx_eh_target_reset,
93 .eh_host_reset_handler = qla4xxx_eh_host_reset, 95 .eh_host_reset_handler = qla4xxx_eh_host_reset,
@@ -384,7 +386,7 @@ static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
384 if (!srb) 386 if (!srb)
385 return srb; 387 return srb;
386 388
387 atomic_set(&srb->ref_count, 1); 389 kref_init(&srb->srb_ref);
388 srb->ha = ha; 390 srb->ha = ha;
389 srb->ddb = ddb_entry; 391 srb->ddb = ddb_entry;
390 srb->cmd = cmd; 392 srb->cmd = cmd;
@@ -406,9 +408,11 @@ static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
406 CMD_SP(cmd) = NULL; 408 CMD_SP(cmd) = NULL;
407} 409}
408 410
409void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb) 411void qla4xxx_srb_compl(struct kref *ref)
410{ 412{
413 struct srb *srb = container_of(ref, struct srb, srb_ref);
411 struct scsi_cmnd *cmd = srb->cmd; 414 struct scsi_cmnd *cmd = srb->cmd;
415 struct scsi_qla_host *ha = srb->ha;
412 416
413 qla4xxx_srb_free_dma(ha, srb); 417 qla4xxx_srb_free_dma(ha, srb);
414 418
@@ -887,7 +891,7 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
887 srb = qla4xxx_del_from_active_array(ha, i); 891 srb = qla4xxx_del_from_active_array(ha, i);
888 if (srb != NULL) { 892 if (srb != NULL) {
889 srb->cmd->result = DID_RESET << 16; 893 srb->cmd->result = DID_RESET << 16;
890 qla4xxx_srb_compl(ha, srb); 894 kref_put(&srb->srb_ref, qla4xxx_srb_compl);
891 } 895 }
892 } 896 }
893 spin_unlock_irqrestore(&ha->hardware_lock, flags); 897 spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -1501,7 +1505,7 @@ struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t in
1501 1505
1502/** 1506/**
1503 * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware 1507 * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
1504 * @ha: actual ha whose done queue will contain the comd returned by firmware. 1508 * @ha: Pointer to host adapter structure.
1505 * @cmd: Scsi Command to wait on. 1509 * @cmd: Scsi Command to wait on.
1506 * 1510 *
1507 * This routine waits for the command to be returned by the Firmware 1511 * This routine waits for the command to be returned by the Firmware
@@ -1585,6 +1589,62 @@ static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
1585} 1589}
1586 1590
1587/** 1591/**
1592 * qla4xxx_eh_abort - callback for abort task.
1593 * @cmd: Pointer to Linux's SCSI command structure
1594 *
1595 * This routine is called by the Linux OS to abort the specified
1596 * command.
1597 **/
1598static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
1599{
1600 struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
1601 unsigned int id = cmd->device->id;
1602 unsigned int lun = cmd->device->lun;
1603 unsigned long serial = cmd->serial_number;
1604 struct srb *srb = NULL;
1605 int ret = SUCCESS;
1606 int wait = 0;
1607
1608 dev_info(&ha->pdev->dev,
1609 "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n",
1610 ha->host_no, id, lun, cmd, serial);
1611
1612 srb = (struct srb *) CMD_SP(cmd);
1613
1614 if (!srb)
1615 return SUCCESS;
1616
1617 kref_get(&srb->srb_ref);
1618
1619 if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
1620 DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n",
1621 ha->host_no, id, lun));
1622 ret = FAILED;
1623 } else {
1624 DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n",
1625 ha->host_no, id, lun));
1626 wait = 1;
1627 }
1628
1629 kref_put(&srb->srb_ref, qla4xxx_srb_compl);
1630
1631 /* Wait for command to complete */
1632 if (wait) {
1633 if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
1634 DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n",
1635 ha->host_no, id, lun));
1636 ret = FAILED;
1637 }
1638 }
1639
1640 dev_info(&ha->pdev->dev,
1641 "scsi%ld:%d:%d: Abort command - %s\n",
1642 ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed");
1643
1644 return ret;
1645}
1646
1647/**
1588 * qla4xxx_eh_device_reset - callback for target reset. 1648 * qla4xxx_eh_device_reset - callback for target reset.
1589 * @cmd: Pointer to Linux's SCSI command structure 1649 * @cmd: Pointer to Linux's SCSI command structure
1590 * 1650 *