Skip to contentSkip to conversation

RFC: add target reset handler to scsi_error.c

PATCH In review [email protected] 3 participants 6 messages Dec 19, 2007 – Dec 27, 2007

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

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.

#1 lore raw

PATCH 1/2 scsi error: add target reset eh handler

From: Mike Christie <[email protected]>

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.

---
 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(-)
drivers/scsi/scsi_error.c +103 -18
index 169bc59..fb1f5bc 100644
@@ -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;
include/scsi/scsi_eh.h +1 -0
index d21b891..8bfdee8 100644
@@ -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);
 
include/scsi/scsi_host.h +1 -0
index 0fd4746..8bb0644 100644
@@ -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 *);
 
Signature · 1 line
1.5.1.2
#2 lore raw

PATCH 2/2 qla4xxx: Add target reset functionality

From: Mike Christie <[email protected]>

This patch adds target reset functionalty.

---
 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(-)
drivers/scsi/qla4xxx/ql4_fw.h +1 -0
index fe415ec..ed8ee66 100644
@@ -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
drivers/scsi/qla4xxx/ql4_glbl.h +2 -0
index a3608e0..b403a17 100644
@@ -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);
drivers/scsi/qla4xxx/ql4_mbx.c +39 -0
index 35cd73c..c577d79 100644
@@ -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)
drivers/scsi/qla4xxx/ql4_os.c +65 -9

119 lines not on this page · raw message

Signature · 1 line
1.5.1.2
Acked-by on v1 2/2
#3 lore raw

RE: [PATCH 2/2] qla4xxx: Add target reset functionality

Quoted 244 lines · Mike Christie

This patch adds target reset functionalty.

---
 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(-)
drivers/scsi/qla4xxx/ql4_fw.h +1 -0
index fe415ec..ed8ee66 100644
@@ -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
drivers/scsi/qla4xxx/ql4_glbl.h +2 -0
index a3608e0..b403a17 100644
@@ -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,
drivers/scsi/qla4xxx/ql4_glbl.h +0 -0
 		      uint32_t offset, uint32_t len);
 int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
drivers/scsi/qla4xxx/ql4_mbx.c +22 -0
index 35cd73c..c577d79 100644
@@ -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

drivers/scsi/qla4xxx/ql4_mbx.c +17 -0
+	 * 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)
drivers/scsi/qla4xxx/ql4_os.c +1 -0
index f55b9f7..05e6991 100644
@@ -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);

drivers/scsi/qla4xxx/ql4_os.c +1 -0
@@ -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,
 
drivers/scsi/qla4xxx/ql4_os.c +0 -1
 	.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

drivers/scsi/qla4xxx/ql4_os.c +0 -0
@@ -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,

drivers/scsi/qla4xxx/ql4_os.c +3 -2
-						 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

drivers/scsi/qla4xxx/ql4_os.c +2 -2
-	 * 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) {

drivers/scsi/qla4xxx/ql4_os.c +3 -3
+		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),

drivers/scsi/qla4xxx/ql4_os.c +20 -0
+						 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, "

drivers/scsi/qla4xxx/ql4_os.c +2 -0
+		      "to=%x,dpc_flags=%lx, status=%x allowed=%d\n",
+		      ha->host_no, cmd, jiffies, 

cmd->timeout_per_command / HZ,

drivers/scsi/qla4xxx/ql4_os.c +14 -0
+		      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

drivers/scsi/qla4xxx/ql4_os.c +4 -0
+	 * for the target
+	 */
+	if (cmd->device->host->shost_state == SHOST_RECOVERY) {
+		if (qla4xxx_eh_wait_for_commands(ha, 

scsi_target(cmd->device),

drivers/scsi/qla4xxx/ql4_os.c +2 -0
+						 NULL)) {
+			starget_printk(KERN_INFO, 

scsi_target(cmd->device),

drivers/scsi/qla4xxx/ql4_os.c +1 -0
+				       "WARM TARGET DEVICE 

RESET FAILED - "

drivers/scsi/qla4xxx/ql4_os.c +11 -0
+				       "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
  *
Signature · 1 line
1.5.1.2
maintainer
#4 lore raw

Re: [PATCH 1/2] scsi error: add target reset eh handler

In reply to [email protected]
Quoted 9 lines · On Tue, 2007-12-18 at 22:11 -0600, [email protected] wrote:

From: Mike Christie <[email protected]>

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.

Quoted 5 lines

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

#5 lore raw

Re: [PATCH 1/2] scsi error: add target reset eh handler

Quoted 16 lines · James Bottomley
Quoted 9 lines · On Tue, 2007-12-18 at 22:11 -0600, [email protected] wrote:

From: Mike Christie <[email protected]>

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.

Quoted 5 lines

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.

Quoted 6 lines

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.

Quoted 6 lines

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.