* RFC: add target reset handler to scsi_error.c
@ 2007-12-19 4:11 michaelc
2007-12-19 4:11 ` [PATCH 1/2] scsi error: add target reset eh handler michaelc
0 siblings, 1 reply; 6+ messages in thread
From: michaelc @ 2007-12-19 4:11 UTC (permalink / raw)
To: linux-scsi
These patches add a target reset handler to scsi_error.c's error
handler. It is needed because drivers like qla4xxx either have to
do a target reset in the eh_device_reset_handler then do some
tricks so that when that handler is called again we do not send
extra resets, or the driver has to do its own loop in the bus
or host reset handler that loops over the host's targets and sends a
target reset for each target.
Patches were made over scsi-misc.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] scsi error: add target reset eh handler
2007-12-19 4:11 RFC: add target reset handler to scsi_error.c michaelc
@ 2007-12-19 4:11 ` michaelc
2007-12-19 4:11 ` [PATCH 2/2] qla4xxx: Add target reset functionality michaelc
2007-12-21 21:36 ` [PATCH 1/2] scsi error: add target reset eh handler James Bottomley
0 siblings, 2 replies; 6+ messages in thread
From: michaelc @ 2007-12-19 4:11 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
Drivers like qla4xxx and bnx2i (and it looks like some fcp drivers too),
want to be able to send a lun reset in the eh device handler and then a
target reset in some other handler. The old linux-iscsi driver, which did
the host per session like open-iscsi did the target reset in the host reset,
because the scsi command accounting that scsi_error.c does worked out
nicely for software iscsi, but does not work for hardware iscsi well.
This patch adds a eh_target_reset_handler any driver can use to send
a target reset.
The next patch will hook qla4xxx into it, and patches for iscsi_tcp/iser
and bnx2i will follow later when bnx2i is closer to getting merged.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/scsi_error.c | 121 ++++++++++++++++++++++++++++++++++++++-------
include/scsi/scsi_eh.h | 1 +
include/scsi/scsi_host.h | 1 +
3 files changed, 105 insertions(+), 18 deletions(-)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 169bc59..fb1f5bc 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -524,6 +524,41 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
return rtn;
}
+static void __scsi_report_device_reset(struct scsi_device *sdev, void *data)
+{
+ sdev->was_reset = 1;
+ sdev->expecting_cc_ua = 1;
+}
+
+/**
+ * scsi_try_target_reset - Ask host to perform a target reset
+ * @scmd: SCSI cmd used to send a target reset
+ *
+ * Notes:
+ * There is no timeout for this operation. if this operation is
+ * unreliable for a given host, then the host itself needs to put a
+ * timer on it, and set the host back to a consistent state prior to
+ * returning.
+ */
+static int scsi_try_target_reset(struct scsi_cmnd *scmd)
+{
+ unsigned long flags;
+ int rtn;
+
+ if (!scmd->device->host->hostt->eh_target_reset_handler)
+ return FAILED;
+
+ rtn = scmd->device->host->hostt->eh_target_reset_handler(scmd);
+ if (rtn == SUCCESS) {
+ spin_lock_irqsave(scmd->device->host->host_lock, flags);
+ __starget_for_each_device(scsi_target(scmd->device), NULL,
+ __scsi_report_device_reset);
+ spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+ }
+
+ return rtn;
+}
+
/**
* scsi_try_bus_device_reset - Ask host to perform a BDR on a dev
* @scmd: SCSI cmd used to send BDR
@@ -542,11 +577,8 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
return FAILED;
rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd);
- if (rtn == SUCCESS) {
- scmd->device->was_reset = 1;
- scmd->device->expecting_cc_ua = 1;
- }
-
+ if (rtn == SUCCESS)
+ __scsi_report_device_reset(scmd->device, NULL);
return rtn;
}
@@ -584,8 +616,9 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
{
if (__scsi_try_to_abort_cmd(scmd) != SUCCESS)
if (scsi_try_bus_device_reset(scmd) != SUCCESS)
- if (scsi_try_bus_reset(scmd) != SUCCESS)
- scsi_try_host_reset(scmd);
+ if (scsi_try_target_reset(scmd) != SUCCESS)
+ if (scsi_try_bus_reset(scmd) != SUCCESS)
+ scsi_try_host_reset(scmd);
}
/**
@@ -1064,6 +1097,56 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
}
/**
+ * scsi_eh_target_reset - send target reset if needed
+ * @shost: scsi host being recovered.
+ * @work_q: &list_head for pending commands.
+ * @done_q: &list_head for processed commands.
+ *
+ * Notes:
+ * Try a target reset.
+ */
+static int scsi_eh_target_reset(struct Scsi_Host *shost,
+ struct list_head *work_q,
+ struct list_head *done_q)
+{
+ struct scsi_cmnd *scmd, *tgtr_scmd, *next;
+ unsigned int id;
+ int rtn;
+
+ for (id = 0; id <= shost->max_id; id++) {
+ tgtr_scmd = NULL;
+ list_for_each_entry(scmd, work_q, eh_entry) {
+ if (id == scmd_id(scmd)) {
+ tgtr_scmd = scmd;
+ break;
+ }
+ }
+ if (!tgtr_scmd)
+ continue;
+
+ SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset "
+ "to target %d\n",
+ current->comm, id));
+ rtn = scsi_try_target_reset(tgtr_scmd);
+ if (rtn == SUCCESS) {
+ list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
+ if (id == scmd_id(scmd))
+ if (!scsi_device_online(scmd->device) ||
+ !scsi_eh_tur(tgtr_scmd))
+ scsi_eh_finish_cmd(scmd,
+ done_q);
+ }
+ } else
+ SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Target reset"
+ " failed target: "
+ "%d\n",
+ current->comm, id));
+ }
+
+ return list_empty(work_q);
+}
+
+/**
* scsi_eh_bus_reset - send a bus reset
* @shost: &scsi host being recovered.
* @work_q: &list_head for pending commands.
@@ -1451,9 +1534,11 @@ void scsi_eh_ready_devs(struct Scsi_Host *shost,
{
if (!scsi_eh_stu(shost, work_q, done_q))
if (!scsi_eh_bus_device_reset(shost, work_q, done_q))
- if (!scsi_eh_bus_reset(shost, work_q, done_q))
- if (!scsi_eh_host_reset(work_q, done_q))
- scsi_eh_offline_sdevs(work_q, done_q);
+ if (!scsi_eh_target_reset(shost, work_q, done_q))
+ if (!scsi_eh_bus_reset(shost, work_q, done_q))
+ if (!scsi_eh_host_reset(work_q, done_q))
+ scsi_eh_offline_sdevs(work_q,
+ done_q);
}
EXPORT_SYMBOL_GPL(scsi_eh_ready_devs);
@@ -1623,10 +1708,8 @@ void scsi_report_bus_reset(struct Scsi_Host *shost, int channel)
struct scsi_device *sdev;
__shost_for_each_device(sdev, shost) {
- if (channel == sdev_channel(sdev)) {
- sdev->was_reset = 1;
- sdev->expecting_cc_ua = 1;
- }
+ if (channel == sdev_channel(sdev))
+ __scsi_report_device_reset(sdev, NULL);
}
}
EXPORT_SYMBOL(scsi_report_bus_reset);
@@ -1659,10 +1742,8 @@ void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target)
__shost_for_each_device(sdev, shost) {
if (channel == sdev_channel(sdev) &&
- target == sdev_id(sdev)) {
- sdev->was_reset = 1;
- sdev->expecting_cc_ua = 1;
- }
+ target == sdev_id(sdev))
+ __scsi_report_device_reset(sdev, NULL);
}
}
EXPORT_SYMBOL(scsi_report_device_reset);
@@ -1724,6 +1805,10 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
if (rtn == SUCCESS)
break;
/* FALLTHROUGH */
+ case SCSI_TRY_RESET_TARGET:
+ rtn = scsi_try_target_reset(scmd);
+ if (rtn == SUCCESS)
+ break;
case SCSI_TRY_RESET_HOST:
rtn = scsi_try_host_reset(scmd);
break;
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index d21b891..8bfdee8 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -64,6 +64,7 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
#define SCSI_TRY_RESET_DEVICE 1
#define SCSI_TRY_RESET_BUS 2
#define SCSI_TRY_RESET_HOST 3
+#define SCSI_TRY_RESET_TARGET 4
extern int scsi_reset_provider(struct scsi_device *, int);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 0fd4746..8bb0644 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -171,6 +171,7 @@ struct scsi_host_template {
*/
int (* eh_abort_handler)(struct scsi_cmnd *);
int (* eh_device_reset_handler)(struct scsi_cmnd *);
+ int (* eh_target_reset_handler)(struct scsi_cmnd *);
int (* eh_bus_reset_handler)(struct scsi_cmnd *);
int (* eh_host_reset_handler)(struct scsi_cmnd *);
--
1.5.1.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/2] qla4xxx: Add target reset functionality
2007-12-19 4:11 ` [PATCH 1/2] scsi error: add target reset eh handler michaelc
@ 2007-12-19 4:11 ` michaelc
2007-12-21 21:26 ` David Somayajulu
2007-12-21 21:36 ` [PATCH 1/2] scsi error: add target reset eh handler James Bottomley
1 sibling, 1 reply; 6+ messages in thread
From: michaelc @ 2007-12-19 4:11 UTC (permalink / raw)
To: linux-scsi; +Cc: Mike Christie
From: Mike Christie <michaelc@cs.wisc.edu>
This patch adds target reset functionalty.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
---
drivers/scsi/qla4xxx/ql4_fw.h | 1 +
drivers/scsi/qla4xxx/ql4_glbl.h | 2 +
drivers/scsi/qla4xxx/ql4_mbx.c | 39 ++++++++++++++++++++
drivers/scsi/qla4xxx/ql4_os.c | 74 ++++++++++++++++++++++++++++++++++-----
4 files changed, 107 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index fe415ec..ed8ee66 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -216,6 +216,7 @@ union external_hw_config_reg {
#define MBOX_CMD_ABOUT_FW 0x0009
#define MBOX_CMD_PING 0x000B
#define MBOX_CMD_LUN_RESET 0x0016
+#define MBOX_CMD_TARGET_WARM_RESET 0x0017
#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E
#define MBOX_CMD_GET_FW_STATUS 0x001F
#define MBOX_CMD_SET_ISNS_SERVICE 0x0021
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index a3608e0..b403a17 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -27,6 +27,8 @@ int qla4xxx_relogin_device(struct scsi_qla_host * ha,
struct ddb_entry * ddb_entry);
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,
+ struct ddb_entry * ddb_entry);
int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
uint32_t offset, uint32_t len);
int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 35cd73c..c577d79 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -713,6 +713,45 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
return status;
}
+/**
+ * qla4xxx_reset_target - issues target Reset
+ * @ha: Pointer to host adapter structure.
+ * @db_entry: Pointer to device database entry
+ * @un_entry: Pointer to lun entry structure
+ *
+ * This routine performs a TARGET RESET on the specified target.
+ * The caller must ensure that the ddb_entry pointers
+ * are valid before calling this routine.
+ **/
+int qla4xxx_reset_target(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ int status = QLA_SUCCESS;
+
+ DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no,
+ ddb_entry->os_target_id));
+
+ /*
+ * Send target reset command to ISP, so that the ISP will return all
+ * outstanding requests with RESET status
+ */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+ mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET;
+ mbox_cmd[1] = ddb_entry->fw_ddb_index;
+ mbox_cmd[5] = 0x01; /* Immediate Command Enable */
+
+ qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+ &mbox_sts[0]);
+ if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
+ mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
+ status = QLA_ERROR;
+
+ return status;
+}
int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
uint32_t offset, uint32_t len)
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index f55b9f7..05e6991 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -73,6 +73,7 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
void (*done) (struct scsi_cmnd *));
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);
static int qla4xxx_slave_alloc(struct scsi_device *device);
static int qla4xxx_slave_configure(struct scsi_device *device);
@@ -85,6 +86,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
.queuecommand = qla4xxx_queuecommand,
.eh_device_reset_handler = qla4xxx_eh_device_reset,
+ .eh_target_reset_handler = qla4xxx_eh_target_reset,
.eh_host_reset_handler = qla4xxx_eh_host_reset,
.slave_configure = qla4xxx_slave_configure,
@@ -1506,7 +1508,7 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
}
/**
- * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish.
+ * qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
* @ha: pointer to to HBA
* @t: target id
* @l: lun id
@@ -1514,20 +1516,22 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
* This function waits for all outstanding commands to a lun to complete. It
* returns 0 if all pending commands are returned and 1 otherwise.
**/
-static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha,
- int t, int l)
+static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
+ struct scsi_target *stgt,
+ struct scsi_device *sdev)
{
int cnt;
int status = 0;
struct scsi_cmnd *cmd;
/*
- * Waiting for all commands for the designated target in the active
- * array
+ * Waiting for all commands for the designated target or dev
+ * in the active array
*/
for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
cmd = scsi_host_find_tag(ha->host, cnt);
- if (cmd && cmd->device->id == t && cmd->device->lun == l) {
+ if (cmd && stgt == scsi_target(cmd->device) &&
+ (!sdev || sdev == cmd->device)) {
if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
status++;
break;
@@ -1580,9 +1584,8 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
* for the device.
*/
if (cmd->device->host->shost_state == SHOST_RECOVERY) {
- if (qla4xxx_eh_wait_for_active_target_commands(ha,
- cmd->device->id,
- cmd->device->lun)){
+ if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
+ cmd->device)) {
dev_info(&ha->pdev->dev,
"DEVICE RESET FAILED - waiting for "
"commands.\n");
@@ -1603,6 +1606,59 @@ eh_dev_reset_done:
}
/**
+ * qla4xxx_eh_target_reset - callback for target reset.
+ * @cmd: Pointer to Linux's SCSI command structure
+ *
+ * This routine is called by the Linux OS to reset the target.
+ **/
+static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
+{
+ struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+ struct ddb_entry *ddb_entry = cmd->device->hostdata;
+ int stat;
+
+ if (!ddb_entry)
+ return FAILED;
+
+ starget_printk(KERN_INFO, scsi_target(cmd->device),
+ "WARM TARGET RESET ISSUED.\n");
+
+ DEBUG2(printk(KERN_INFO
+ "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, "
+ "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
+ ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ,
+ ha->dpc_flags, cmd->result, cmd->allowed));
+
+ stat = qla4xxx_reset_target(ha, ddb_entry);
+ if (stat != QLA_SUCCESS) {
+ starget_printk(KERN_INFO, scsi_target(cmd->device),
+ "WARM TARGET RESET FAILED.\n");
+ return FAILED;
+ }
+
+ /* Send marker. */
+ ha->marker_needed = 1;
+
+ /*
+ * If we are coming down the EH path, wait for all commands to complete
+ * for the target
+ */
+ if (cmd->device->host->shost_state == SHOST_RECOVERY) {
+ if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device),
+ NULL)) {
+ starget_printk(KERN_INFO, scsi_target(cmd->device),
+ "WARM TARGET DEVICE RESET FAILED - "
+ "waiting for commands.\n");
+ return FAILED;
+ }
+ }
+
+ starget_printk(KERN_INFO, scsi_target(cmd->device),
+ "WARM TARGET RESET SUCCEEDED.\n");
+ return SUCCESS;
+}
+
+/**
* qla4xxx_eh_host_reset - kernel callback
* @cmd: Pointer to Linux's SCSI command structure
*
--
1.5.1.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* RE: [PATCH 2/2] qla4xxx: Add target reset functionality
2007-12-19 4:11 ` [PATCH 2/2] qla4xxx: Add target reset functionality michaelc
@ 2007-12-21 21:26 ` David Somayajulu
0 siblings, 0 replies; 6+ messages in thread
From: David Somayajulu @ 2007-12-21 21:26 UTC (permalink / raw)
To: michaelc, linux-scsi
Mike Christie <michaelc@cs.wisc.edu> wrote:
> This patch adds target reset functionalty.
>
> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
> ---
> drivers/scsi/qla4xxx/ql4_fw.h | 1 +
> drivers/scsi/qla4xxx/ql4_glbl.h | 2 +
> drivers/scsi/qla4xxx/ql4_mbx.c | 39 ++++++++++++++++++++
> drivers/scsi/qla4xxx/ql4_os.c | 74
> ++++++++++++++++++++++++++++++++++-----
> 4 files changed, 107 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/scsi/qla4xxx/ql4_fw.h
> b/drivers/scsi/qla4xxx/ql4_fw.h
> index fe415ec..ed8ee66 100644
> --- a/drivers/scsi/qla4xxx/ql4_fw.h
> +++ b/drivers/scsi/qla4xxx/ql4_fw.h
> @@ -216,6 +216,7 @@ union external_hw_config_reg {
> #define MBOX_CMD_ABOUT_FW 0x0009
> #define MBOX_CMD_PING 0x000B
> #define MBOX_CMD_LUN_RESET 0x0016
> +#define MBOX_CMD_TARGET_WARM_RESET 0x0017
> #define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E
> #define MBOX_CMD_GET_FW_STATUS 0x001F
> #define MBOX_CMD_SET_ISNS_SERVICE 0x0021
> diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h
> b/drivers/scsi/qla4xxx/ql4_glbl.h
> index a3608e0..b403a17 100644
> --- a/drivers/scsi/qla4xxx/ql4_glbl.h
> +++ b/drivers/scsi/qla4xxx/ql4_glbl.h
> @@ -27,6 +27,8 @@ int qla4xxx_relogin_device(struct
> scsi_qla_host * ha,
> struct ddb_entry * ddb_entry);
> 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,
> + struct ddb_entry * ddb_entry);
> int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
> uint32_t offset, uint32_t len);
> int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
> diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c
> b/drivers/scsi/qla4xxx/ql4_mbx.c
> index 35cd73c..c577d79 100644
> --- a/drivers/scsi/qla4xxx/ql4_mbx.c
> +++ b/drivers/scsi/qla4xxx/ql4_mbx.c
> @@ -713,6 +713,45 @@ int qla4xxx_reset_lun(struct
> scsi_qla_host * ha, struct ddb_entry * ddb_entry,
> return status;
> }
>
> +/**
> + * qla4xxx_reset_target - issues target Reset
> + * @ha: Pointer to host adapter structure.
> + * @db_entry: Pointer to device database entry
> + * @un_entry: Pointer to lun entry structure
> + *
> + * This routine performs a TARGET RESET on the specified target.
> + * The caller must ensure that the ddb_entry pointers
> + * are valid before calling this routine.
> + **/
> +int qla4xxx_reset_target(struct scsi_qla_host *ha,
> + struct ddb_entry *ddb_entry)
> +{
> + uint32_t mbox_cmd[MBOX_REG_COUNT];
> + uint32_t mbox_sts[MBOX_REG_COUNT];
> + int status = QLA_SUCCESS;
> +
> + DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no,
> + ddb_entry->os_target_id));
> +
> + /*
> + * Send target reset command to ISP, so that the ISP
> will return all
> + * outstanding requests with RESET status
> + */
> + memset(&mbox_cmd, 0, sizeof(mbox_cmd));
> + memset(&mbox_sts, 0, sizeof(mbox_sts));
> +
> + mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET;
> + mbox_cmd[1] = ddb_entry->fw_ddb_index;
> + mbox_cmd[5] = 0x01; /* Immediate Command Enable */
> +
> + qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
> + &mbox_sts[0]);
> + if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
> + mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
> + status = QLA_ERROR;
> +
> + return status;
> +}
>
> int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
> uint32_t offset, uint32_t len)
> diff --git a/drivers/scsi/qla4xxx/ql4_os.c
> b/drivers/scsi/qla4xxx/ql4_os.c
> index f55b9f7..05e6991 100644
> --- a/drivers/scsi/qla4xxx/ql4_os.c
> +++ b/drivers/scsi/qla4xxx/ql4_os.c
> @@ -73,6 +73,7 @@ static void
> qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
> static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
> void (*done) (struct scsi_cmnd *));
> 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);
> static int qla4xxx_slave_alloc(struct scsi_device *device);
> static int qla4xxx_slave_configure(struct scsi_device *device);
> @@ -85,6 +86,7 @@ static struct scsi_host_template
> qla4xxx_driver_template = {
> .queuecommand = qla4xxx_queuecommand,
>
> .eh_device_reset_handler = qla4xxx_eh_device_reset,
> + .eh_target_reset_handler = qla4xxx_eh_target_reset,
> .eh_host_reset_handler = qla4xxx_eh_host_reset,
>
> .slave_configure = qla4xxx_slave_configure,
> @@ -1506,7 +1508,7 @@ static int
> qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
> }
>
> /**
> - * qla4xxx_eh_wait_for_active_target_commands - wait for
> active cmds to finish.
> + * qla4xxx_eh_wait_for_commands - wait for active cmds to finish.
> * @ha: pointer to to HBA
> * @t: target id
> * @l: lun id
> @@ -1514,20 +1516,22 @@ static int
> qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
> * This function waits for all outstanding commands to a lun
> to complete. It
> * returns 0 if all pending commands are returned and 1 otherwise.
> **/
> -static int qla4xxx_eh_wait_for_active_target_commands(struct
> scsi_qla_host *ha,
> - int t, int l)
> +static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha,
> + struct scsi_target *stgt,
> + struct scsi_device *sdev)
> {
> int cnt;
> int status = 0;
> struct scsi_cmnd *cmd;
>
> /*
> - * Waiting for all commands for the designated target
> in the active
> - * array
> + * Waiting for all commands for the designated target or dev
> + * in the active array
> */
> for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
> cmd = scsi_host_find_tag(ha->host, cnt);
> - if (cmd && cmd->device->id == t &&
> cmd->device->lun == l) {
> + if (cmd && stgt == scsi_target(cmd->device) &&
> + (!sdev || sdev == cmd->device)) {
> if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
> status++;
> break;
> @@ -1580,9 +1584,8 @@ static int
> qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
> * for the device.
> */
> if (cmd->device->host->shost_state == SHOST_RECOVERY) {
> - if (qla4xxx_eh_wait_for_active_target_commands(ha,
> -
> cmd->device->id,
> -
> cmd->device->lun)){
> + if (qla4xxx_eh_wait_for_commands(ha,
> scsi_target(cmd->device),
> + cmd->device)) {
> dev_info(&ha->pdev->dev,
> "DEVICE RESET FAILED - waiting for "
> "commands.\n");
> @@ -1603,6 +1606,59 @@ eh_dev_reset_done:
> }
>
> /**
> + * qla4xxx_eh_target_reset - callback for target reset.
> + * @cmd: Pointer to Linux's SCSI command structure
> + *
> + * This routine is called by the Linux OS to reset the target.
> + **/
> +static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
> +{
> + struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
> + struct ddb_entry *ddb_entry = cmd->device->hostdata;
> + int stat;
> +
> + if (!ddb_entry)
> + return FAILED;
> +
> + starget_printk(KERN_INFO, scsi_target(cmd->device),
> + "WARM TARGET RESET ISSUED.\n");
> +
> + DEBUG2(printk(KERN_INFO
> + "scsi%ld: TARGET_DEVICE_RESET cmd=%p
> jiffies = 0x%lx, "
> + "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
> + ha->host_no, cmd, jiffies,
> cmd->timeout_per_command / HZ,
> + ha->dpc_flags, cmd->result, cmd->allowed));
> +
> + stat = qla4xxx_reset_target(ha, ddb_entry);
> + if (stat != QLA_SUCCESS) {
> + starget_printk(KERN_INFO, scsi_target(cmd->device),
> + "WARM TARGET RESET FAILED.\n");
> + return FAILED;
> + }
> +
> + /* Send marker. */
> + ha->marker_needed = 1;
> +
> + /*
> + * If we are coming down the EH path, wait for all
> commands to complete
> + * for the target
> + */
> + if (cmd->device->host->shost_state == SHOST_RECOVERY) {
> + if (qla4xxx_eh_wait_for_commands(ha,
> scsi_target(cmd->device),
> + NULL)) {
> + starget_printk(KERN_INFO,
> scsi_target(cmd->device),
> + "WARM TARGET DEVICE
> RESET FAILED - "
> + "waiting for commands.\n");
> + return FAILED;
> + }
> + }
> +
> + starget_printk(KERN_INFO, scsi_target(cmd->device),
> + "WARM TARGET RESET SUCCEEDED.\n");
> + return SUCCESS;
> +}
> +
> +/**
> * qla4xxx_eh_host_reset - kernel callback
> * @cmd: Pointer to Linux's SCSI command structure
> *
> --
> 1.5.1.2
Acked-by: David Somayajulu <david.somayajulu@qlogic.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] scsi error: add target reset eh handler
2007-12-19 4:11 ` [PATCH 1/2] scsi error: add target reset eh handler michaelc
2007-12-19 4:11 ` [PATCH 2/2] qla4xxx: Add target reset functionality michaelc
@ 2007-12-21 21:36 ` James Bottomley
2007-12-27 3:21 ` Mike Christie
1 sibling, 1 reply; 6+ messages in thread
From: James Bottomley @ 2007-12-21 21:36 UTC (permalink / raw)
To: michaelc; +Cc: linux-scsi
On Tue, 2007-12-18 at 22:11 -0600, michaelc@cs.wisc.edu wrote:
> From: Mike Christie <michaelc@cs.wisc.edu>
>
> Drivers like qla4xxx and bnx2i (and it looks like some fcp drivers too),
> want to be able to send a lun reset in the eh device handler and then a
> target reset in some other handler. The old linux-iscsi driver, which did
> the host per session like open-iscsi did the target reset in the host reset,
> because the scsi command accounting that scsi_error.c does worked out
> nicely for software iscsi, but does not work for hardware iscsi well.
>
> This patch adds a eh_target_reset_handler any driver can use to send
> a target reset.
>
> The next patch will hook qla4xxx into it, and patches for iscsi_tcp/iser
> and bnx2i will follow later when bnx2i is closer to getting merged.
We sort of have a mapping problem here. In the old ways of the error
handler, since it was based on SPI and SCSI-2, when it said "device
reset" what it actually meant was target reset, since that was the only
message the SPI bus could send. It was only in the later SCSI-3
standard that a LUN reset came along. So, most resent implementations
(even FC ones) send a target reset for this function.
So ... where I'm going is that I'm not averse to adding a target reset
(it has been suggested before), but then we'll have to clean up a lot of
other drivers. Alternatively, you could just plumb target reset in to
the qla2xxx where device reset now is.
What do people think?
James
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] scsi error: add target reset eh handler
2007-12-21 21:36 ` [PATCH 1/2] scsi error: add target reset eh handler James Bottomley
@ 2007-12-27 3:21 ` Mike Christie
0 siblings, 0 replies; 6+ messages in thread
From: Mike Christie @ 2007-12-27 3:21 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi
James Bottomley wrote:
> On Tue, 2007-12-18 at 22:11 -0600, michaelc@cs.wisc.edu wrote:
>> From: Mike Christie <michaelc@cs.wisc.edu>
>>
>> Drivers like qla4xxx and bnx2i (and it looks like some fcp drivers too),
>> want to be able to send a lun reset in the eh device handler and then a
>> target reset in some other handler. The old linux-iscsi driver, which did
>> the host per session like open-iscsi did the target reset in the host reset,
>> because the scsi command accounting that scsi_error.c does worked out
>> nicely for software iscsi, but does not work for hardware iscsi well.
>>
>> This patch adds a eh_target_reset_handler any driver can use to send
>> a target reset.
>>
>> The next patch will hook qla4xxx into it, and patches for iscsi_tcp/iser
>> and bnx2i will follow later when bnx2i is closer to getting merged.
>
> We sort of have a mapping problem here. In the old ways of the error
> handler, since it was based on SPI and SCSI-2, when it said "device
> reset" what it actually meant was target reset, since that was the only
> message the SPI bus could send. It was only in the later SCSI-3
> standard that a LUN reset came along. So, most resent implementations
> (even FC ones) send a target reset for this function.
Ah that is what I thought someone told me a while back, but it confused
the heck out of me, because while I was looking at the code I saw that
scsi_eh_bus_device_reset only cleans up the commands for one scsi_device
and only reports one device as reset (sets was_reset and expecting_cc_ua
to one), so it looks perfect to send a logical unit reset from.
>
> So ... where I'm going is that I'm not averse to adding a target reset
> (it has been suggested before), but then we'll have to clean up a lot of
> other drivers. Alternatively, you could just plumb target reset in to
> the qla2xxx where device reset now is.
>
Doing the target reset in the the device reset handler just does not
seem nice. scsi_error.c's scsi_eh_bus_device_reset() only calls
scsi_eh_finish_cmd on the commands for one scsi_device. And the
eh_device_reset_handler gets called for every device on the target, so
the driver has to either remember that it just sent a target reset for
another device on the same target or just send a target reset every time
the device handler is called. qla4xxx also already sends a logical unit
reset on the device reset callback.
Do we have to clean up all the drivers in one shot while adding the
target reset callback or can we add the callback and have driver writers
convert when they are ready like was done with the old and new driver
loading (scsi_host_template->detect/release vs
pci_device->probe/remove)? Some drivers like qla2xxx look trivial, but
for other more difficult drivers I hate changing driver eh paths for hw
I do not have, because it is difficult to get users to test that code
path well. With my patch the device reset handler does not change
behavior, so if a driver sends a target reset from there it has already
added some LLD level hacks to handle the issues I mention above and will
be fine. I can port drivers if you want me to though.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2007-12-27 3:21 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-19 4:11 RFC: add target reset handler to scsi_error.c michaelc
2007-12-19 4:11 ` [PATCH 1/2] scsi error: add target reset eh handler michaelc
2007-12-19 4:11 ` [PATCH 2/2] qla4xxx: Add target reset functionality michaelc
2007-12-21 21:26 ` David Somayajulu
2007-12-21 21:36 ` [PATCH 1/2] scsi error: add target reset eh handler James Bottomley
2007-12-27 3:21 ` Mike Christie
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox