[resend] [PATCH 2.6.14-rc1 3/13] ieee1394/sbp2: fixes for hot-unplug and module unloading

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



sbp2:
fixes for deadlocks of the ieee1394 and scsi subsystems and long delays in
futile error recovery attempts when SBP-2 devices are removed or drivers are
unloaded.

 - Complete commands quickly with DID_NO_CONNECT if the 1394 node is gone or if
   the 1394 low-level driver was unloaded.
 - Skip unnecessary work in the eh_abort_handler and eh_device_reset_handler if
   the node or 1394 low-level driver is gone. 
 - Let scsi's high-level shut down gracefully when sbp2 is being unloaded or
   detached from the 1394 unit. A call to scsi_remove_device is added for this
   purpose, which requires us to store a scsi_device pointer.
 - scsi_device pointer is obtained from slave_alloc hook and cleared by
   slave_destroy. This avoids usage of the pointer after the scsi device was
   deleted e.g. by the user via scsi_mod's sysfs interface.

Signed-off-by: Stefan Richter <stefanr@xxxxxxxxxxxxxxxxx>
---

 drivers/ieee1394/sbp2.c |   96 +++++++++++++++++++++++++++++-------------------
 1 files changed, 58 insertions(+), 38 deletions(-)

--- linux-2.6.14-rc1.orig/drivers/ieee1394/sbp2.c	2005-09-13 05:12:09.000000000 +0200
+++ linux-2.6.14-rc1/drivers/ieee1394/sbp2.c	2005-09-17 16:14:30.000000000 +0200
@@ -596,6 +596,14 @@ static void sbp2util_mark_command_comple
 	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
 }
 
+/*
+ * Is scsi_id valid? Is the 1394 node still present?
+ */
+static inline int sbp2util_node_is_available(struct scsi_id_instance_data *scsi_id)
+{
+	return scsi_id && scsi_id->ne && !scsi_id->ne->in_limbo;
+}
+
 
 
 /*********************************************
@@ -631,11 +639,23 @@ static int sbp2_remove(struct device *de
 {
 	struct unit_directory *ud;
 	struct scsi_id_instance_data *scsi_id;
+	struct scsi_device *sdev;
 
 	SBP2_DEBUG("sbp2_remove");
 
 	ud = container_of(dev, struct unit_directory, device);
 	scsi_id = ud->device.driver_data;
+	if (!scsi_id)
+		return 0;
+
+	/* Trigger shutdown functions in scsi's highlevel. */
+	if (scsi_id->scsi_host)
+		scsi_unblock_requests(scsi_id->scsi_host);
+	sdev = scsi_id->sdev;
+	if (sdev) {
+		scsi_id->sdev = NULL;
+		scsi_remove_device(sdev);
+	}
 
 	sbp2_logout_device(scsi_id);
 	sbp2_remove_device(scsi_id);
@@ -2473,37 +2493,26 @@ static int sbp2scsi_queuecommand(struct 
 	struct scsi_id_instance_data *scsi_id =
 		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
 	struct sbp2scsi_host_info *hi;
+	int result = DID_NO_CONNECT << 16;
 
 	SBP2_DEBUG("sbp2scsi_queuecommand");
 
-	/*
-	 * If scsi_id is null, it means there is no device in this slot,
-	 * so we should return selection timeout.
-	 */
-	if (!scsi_id) {
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done (SCpnt);
-		return 0;
-	}
+	if (!sbp2util_node_is_available(scsi_id))
+		goto done;
 
 	hi = scsi_id->hi;
 
 	if (!hi) {
 		SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!");
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done (SCpnt);
-		return(0);
+		goto done;
 	}
 
 	/*
 	 * Until we handle multiple luns, just return selection time-out
 	 * to any IO directed at non-zero LUNs
 	 */
-	if (SCpnt->device->lun) {
-		SCpnt->result = DID_NO_CONNECT << 16;
-		done (SCpnt);
-		return(0);
-	}
+	if (SCpnt->device->lun)
+		goto done;
 
 	/*
 	 * Check for request sense command, and handle it here
@@ -2514,7 +2523,7 @@ static int sbp2scsi_queuecommand(struct 
 		memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, SCpnt->request_bufflen);
 		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
 		sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_GOOD, SCpnt, done);
-		return(0);
+		return 0;
 	}
 
 	/*
@@ -2522,9 +2531,8 @@ static int sbp2scsi_queuecommand(struct 
 	 */
 	if (!hpsb_node_entry_valid(scsi_id->ne)) {
 		SBP2_ERR("Bus reset in progress - rejecting command");
-		SCpnt->result = DID_BUS_BUSY << 16;
-		done (SCpnt);
-		return(0);
+		result = DID_BUS_BUSY << 16;
+		goto done;
 	}
 
 	/*
@@ -2535,8 +2543,12 @@ static int sbp2scsi_queuecommand(struct 
 		sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT,
 					  SCpnt, done);
 	}
+	return 0;
 
-	return(0);
+done:
+	SCpnt->result = result;
+	done(SCpnt);
+	return 0;
 }
 
 /*
@@ -2683,14 +2695,27 @@ static void sbp2scsi_complete_command(st
 }
 
 
-static int sbp2scsi_slave_configure (struct scsi_device *sdev)
+static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
 {
-	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
+	((struct scsi_id_instance_data *)sdev->host->hostdata[0])->sdev = sdev;
+	return 0;
+}
+
 
+static int sbp2scsi_slave_configure(struct scsi_device *sdev)
+{
+	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
 	return 0;
 }
 
 
+static void sbp2scsi_slave_destroy(struct scsi_device *sdev)
+{
+	((struct scsi_id_instance_data *)sdev->host->hostdata[0])->sdev = NULL;
+	return;
+}
+
+
 /*
  * Called by scsi stack when something has really gone wrong.  Usually
  * called when a command has timed-out for some reason.
@@ -2705,7 +2730,7 @@ static int sbp2scsi_abort(struct scsi_cm
 	SBP2_ERR("aborting sbp2 command");
 	scsi_print_command(SCpnt);
 
-	if (scsi_id) {
+	if (sbp2util_node_is_available(scsi_id)) {
 
 		/*
 		 * Right now, just return any matching command structures
@@ -2742,31 +2767,24 @@ static int sbp2scsi_abort(struct scsi_cm
 /*
  * Called by scsi stack when something has really gone wrong.
  */
-static int __sbp2scsi_reset(struct scsi_cmnd *SCpnt)
+static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
 {
 	struct scsi_id_instance_data *scsi_id =
 		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
+	unsigned long flags;
 
 	SBP2_ERR("reset requested");
 
-	if (scsi_id) {
+	spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
+
+	if (sbp2util_node_is_available(scsi_id)) {
 		SBP2_ERR("Generating sbp2 fetch agent reset");
 		sbp2_agent_reset(scsi_id, 0);
 	}
 
-	return(SUCCESS);
-}
-
-static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
-{
-	unsigned long flags;
-	int rc;
-
-	spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
-	rc = __sbp2scsi_reset(SCpnt);
 	spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
 
-	return rc;
+	return SUCCESS;
 }
 
 static const char *sbp2scsi_info (struct Scsi_Host *host)
@@ -2817,7 +2835,9 @@ static struct scsi_host_template scsi_dr
 	.eh_device_reset_handler =	sbp2scsi_reset,
 	.eh_bus_reset_handler =		sbp2scsi_reset,
 	.eh_host_reset_handler =	sbp2scsi_reset,
+	.slave_alloc =			sbp2scsi_slave_alloc,
 	.slave_configure =		sbp2scsi_slave_configure,
+	.slave_destroy =		sbp2scsi_slave_destroy,
 	.this_id =			-1,
 	.sg_tablesize =			SG_ALL,
 	.use_clustering =		ENABLE_CLUSTERING,

-
: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux