mirror of https://gitee.com/openkylin/linux.git
[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>
This commit is contained in:
parent
5369887a95
commit
09a0f71989
|
@ -172,7 +172,7 @@ struct srb {
|
|||
|
||||
struct scsi_cmnd *cmd; /* (4) SCSI command block */
|
||||
dma_addr_t dma_handle; /* (4) for unmap of single transfers */
|
||||
atomic_t ref_count; /* reference count for this srb */
|
||||
struct kref srb_ref; /* reference count for this srb */
|
||||
uint32_t fw_ddb_index;
|
||||
uint8_t err_id; /* error id */
|
||||
#define SRB_ERR_PORT 1 /* Request failed because "port down" */
|
||||
|
|
|
@ -215,6 +215,7 @@ union external_hw_config_reg {
|
|||
/* Mailbox command definitions */
|
||||
#define MBOX_CMD_ABOUT_FW 0x0009
|
||||
#define MBOX_CMD_PING 0x000B
|
||||
#define MBOX_CMD_ABORT_TASK 0x0015
|
||||
#define MBOX_CMD_LUN_RESET 0x0016
|
||||
#define MBOX_CMD_TARGET_WARM_RESET 0x0017
|
||||
#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E
|
||||
|
|
|
@ -25,6 +25,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);
|
|||
int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);
|
||||
int qla4xxx_relogin_device(struct scsi_qla_host * ha,
|
||||
struct ddb_entry * ddb_entry);
|
||||
int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb);
|
||||
int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
|
||||
int lun);
|
||||
int qla4xxx_reset_target(struct scsi_qla_host * ha,
|
||||
|
@ -65,7 +66,7 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
|
|||
int qla4xxx_init_rings(struct scsi_qla_host * ha);
|
||||
struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
|
||||
uint32_t index);
|
||||
void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
|
||||
void qla4xxx_srb_compl(struct kref *ref);
|
||||
int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
|
||||
int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
|
||||
uint32_t state, uint32_t conn_error);
|
||||
|
|
|
@ -97,7 +97,7 @@ qla4xxx_status_cont_entry(struct scsi_qla_host *ha,
|
|||
|
||||
/* Place command on done queue. */
|
||||
if (srb->req_sense_len == 0) {
|
||||
qla4xxx_srb_compl(ha, srb);
|
||||
kref_put(&srb->srb_ref, qla4xxx_srb_compl);
|
||||
ha->status_srb = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
|
|||
/* complete the request, if not waiting for status_continuation pkt */
|
||||
srb->cc_stat = sts_entry->completionStatus;
|
||||
if (ha->status_srb == NULL)
|
||||
qla4xxx_srb_compl(ha, srb);
|
||||
kref_put(&srb->srb_ref, qla4xxx_srb_compl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -393,7 +393,7 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
|
|||
/* ETRY normally by sending it back with
|
||||
* DID_BUS_BUSY */
|
||||
srb->cmd->result = DID_BUS_BUSY << 16;
|
||||
qla4xxx_srb_compl(ha, srb);
|
||||
kref_put(&srb->srb_ref, qla4xxx_srb_compl);
|
||||
break;
|
||||
|
||||
case ET_CONTINUE:
|
||||
|
|
|
@ -761,6 +761,59 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
|
|||
event_log_dma);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_abort_task - issues Abort Task
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @srb: Pointer to srb entry
|
||||
*
|
||||
* This routine performs a LUN RESET on the specified target/lun.
|
||||
* The caller must ensure that the ddb_entry and lun_entry pointers
|
||||
* are valid before calling this routine.
|
||||
**/
|
||||
int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb)
|
||||
{
|
||||
uint32_t mbox_cmd[MBOX_REG_COUNT];
|
||||
uint32_t mbox_sts[MBOX_REG_COUNT];
|
||||
struct scsi_cmnd *cmd = srb->cmd;
|
||||
int status = QLA_SUCCESS;
|
||||
unsigned long flags = 0;
|
||||
uint32_t index;
|
||||
|
||||
/*
|
||||
* Send abort task command to ISP, so that the ISP will return
|
||||
* request with ABORT status
|
||||
*/
|
||||
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
|
||||
memset(&mbox_sts, 0, sizeof(mbox_sts));
|
||||
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
index = (unsigned long)(unsigned char *)cmd->host_scribble;
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
|
||||
/* Firmware already posted completion on response queue */
|
||||
if (index == MAX_SRBS)
|
||||
return status;
|
||||
|
||||
mbox_cmd[0] = MBOX_CMD_ABORT_TASK;
|
||||
mbox_cmd[1] = srb->fw_ddb_index;
|
||||
mbox_cmd[2] = index;
|
||||
/* Immediate Command Enable */
|
||||
mbox_cmd[5] = 0x01;
|
||||
|
||||
qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0],
|
||||
&mbox_sts[0]);
|
||||
if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE) {
|
||||
status = QLA_ERROR;
|
||||
|
||||
DEBUG2(printk(KERN_WARNING "scsi%ld:%d:%d: abort task FAILED: "
|
||||
"mbx0=%04X, mb1=%04X, mb2=%04X, mb3=%04X, mb4=%04X\n",
|
||||
ha->host_no, cmd->device->id, cmd->device->lun, mbox_sts[0],
|
||||
mbox_sts[1], mbox_sts[2], mbox_sts[3], mbox_sts[4]));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_reset_lun - issues LUN Reset
|
||||
* @ha: Pointer to host adapter structure.
|
||||
|
|
|
@ -74,6 +74,7 @@ static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
|
|||
*/
|
||||
static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
|
||||
void (*done) (struct scsi_cmnd *));
|
||||
static int qla4xxx_eh_abort(struct scsi_cmnd *cmd);
|
||||
static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
|
||||
static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
|
||||
static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
|
||||
|
@ -88,6 +89,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
|
|||
.proc_name = DRIVER_NAME,
|
||||
.queuecommand = qla4xxx_queuecommand,
|
||||
|
||||
.eh_abort_handler = qla4xxx_eh_abort,
|
||||
.eh_device_reset_handler = qla4xxx_eh_device_reset,
|
||||
.eh_target_reset_handler = qla4xxx_eh_target_reset,
|
||||
.eh_host_reset_handler = qla4xxx_eh_host_reset,
|
||||
|
@ -384,7 +386,7 @@ static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
|
|||
if (!srb)
|
||||
return srb;
|
||||
|
||||
atomic_set(&srb->ref_count, 1);
|
||||
kref_init(&srb->srb_ref);
|
||||
srb->ha = ha;
|
||||
srb->ddb = ddb_entry;
|
||||
srb->cmd = cmd;
|
||||
|
@ -406,9 +408,11 @@ static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
|
|||
CMD_SP(cmd) = NULL;
|
||||
}
|
||||
|
||||
void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb)
|
||||
void qla4xxx_srb_compl(struct kref *ref)
|
||||
{
|
||||
struct srb *srb = container_of(ref, struct srb, srb_ref);
|
||||
struct scsi_cmnd *cmd = srb->cmd;
|
||||
struct scsi_qla_host *ha = srb->ha;
|
||||
|
||||
qla4xxx_srb_free_dma(ha, srb);
|
||||
|
||||
|
@ -887,7 +891,7 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
|
|||
srb = qla4xxx_del_from_active_array(ha, i);
|
||||
if (srb != NULL) {
|
||||
srb->cmd->result = DID_RESET << 16;
|
||||
qla4xxx_srb_compl(ha, srb);
|
||||
kref_put(&srb->srb_ref, qla4xxx_srb_compl);
|
||||
}
|
||||
}
|
||||
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
|
|||
|
||||
/**
|
||||
* qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
|
||||
* @ha: actual ha whose done queue will contain the comd returned by firmware.
|
||||
* @ha: Pointer to host adapter structure.
|
||||
* @cmd: Scsi Command to wait on.
|
||||
*
|
||||
* This routine waits for the command to be returned by the Firmware
|
||||
|
@ -1584,6 +1588,62 @@ static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
|
|||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_eh_abort - callback for abort task.
|
||||
* @cmd: Pointer to Linux's SCSI command structure
|
||||
*
|
||||
* This routine is called by the Linux OS to abort the specified
|
||||
* command.
|
||||
**/
|
||||
static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
|
||||
unsigned int id = cmd->device->id;
|
||||
unsigned int lun = cmd->device->lun;
|
||||
unsigned long serial = cmd->serial_number;
|
||||
struct srb *srb = NULL;
|
||||
int ret = SUCCESS;
|
||||
int wait = 0;
|
||||
|
||||
dev_info(&ha->pdev->dev,
|
||||
"scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n",
|
||||
ha->host_no, id, lun, cmd, serial);
|
||||
|
||||
srb = (struct srb *) CMD_SP(cmd);
|
||||
|
||||
if (!srb)
|
||||
return SUCCESS;
|
||||
|
||||
kref_get(&srb->srb_ref);
|
||||
|
||||
if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) {
|
||||
DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n",
|
||||
ha->host_no, id, lun));
|
||||
ret = FAILED;
|
||||
} else {
|
||||
DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n",
|
||||
ha->host_no, id, lun));
|
||||
wait = 1;
|
||||
}
|
||||
|
||||
kref_put(&srb->srb_ref, qla4xxx_srb_compl);
|
||||
|
||||
/* Wait for command to complete */
|
||||
if (wait) {
|
||||
if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
|
||||
DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n",
|
||||
ha->host_no, id, lun));
|
||||
ret = FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&ha->pdev->dev,
|
||||
"scsi%ld:%d:%d: Abort command - %s\n",
|
||||
ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla4xxx_eh_device_reset - callback for target reset.
|
||||
* @cmd: Pointer to Linux's SCSI command structure
|
||||
|
|
Loading…
Reference in New Issue