Skip to contentSkip to conversation

Advanced TCA SCSI / FC Disk Hotswap revision 0.92

PATCH New Steven Dake 1 participant 1 message Oct 25, 2002

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

PATCH 1/1 Advanced TCA SCSI / FC Disk Hotswap revision 0.92

Attached is an update of the Advanced TCA disk hotswap driver to provide disk hotswap support for the Linux Kernel 2.5.44. Hotswap targets include both SCSI and FibreChannel. Note this support is generic in that it will work in a typical PC system with SCSI or FibreChannel disks.

The patch includes support for the QLA adaptor but this adaptor is not included in the standard linux kernel. If you havn't patched your kernel with this driver, just ignore the patch for the qla adaptor to still gain all functionality except for hotswap using that adaptor for WWN identifiers.

As always, the latest Advanced TCA hotswap patches (including scsi disk hotswap) can be found:

http://www.sourceforge.net/projects/atca-hotswap

Changes from kernel 2.5.44 0.90 to 0.91 release:
-----------------------------------------------------------------
* Dumped custom ramfs and integrated with driverfs under bus/scsi/hotswap_commads (suggested by several people)
* changed read_file to _show and write_file to _store while also changing symantics
* switched lun/id and lun/wwn ordering to id/lun and wwn/lun (pointed as an error by Michael Anderson)
* spinlocks changed to semaphores to fix lock held during sleep in function scsi_eh_bus_device_reset (pointed as an error by Patrick Mansfield)

Thanks for looking at the patch...
-steve

MAINTAINERS +6 -0
diff -uNr linux-2.5.44-qla/MAINTAINERS linux-2.5.44-scsi-hotswap/MAINTAINERS
@@ -1418,6 +1418,12 @@
 W:	http://www.kernel.dk
 S:	Maintained
 
+SCSI HOTSWAP DRIVER
+P:	Steven Dake
+M:	[email protected]
+L:	[email protected]
+S:	Maintained
+
 SCSI SG DRIVER
 P:	Doug Gilbert
 M:	[email protected]
drivers/scsi/Config.help +11 -0
diff -uNr linux-2.5.44-qla/drivers/scsi/Config.help linux-2.5.44-scsi-hotswap/drivers/scsi/Config.help
@@ -34,6 +34,17 @@
   is located on a SCSI disk. In this case, do not compile the driver
   for your SCSI host adapter (below) as a module either.
 
+CONFIG_SCSIFCHOTSWAP
+ If you want to support the ability to include the hotswap FibreChannel
+ and SCSI driver, please say yes here.  Hotswap can then be executed
+ through a ramfs interface which provides better error reporting.
+
+ Further, this interface supports insertion and removal by WWN for
+ FibreChannel drivers which support this feature.
+
+ The only FibreChannel driver that supports this feature is Qlogic V6
+ with a specific support patch.
+
 CONFIG_SD_EXTRA_DEVS
   This controls the amount of additional space allocated in tables for
   drivers that are loaded as modules after the kernel is booted.  In
drivers/scsi/Config.in +1 -0
diff -uNr linux-2.5.44-qla/drivers/scsi/Config.in linux-2.5.44-scsi-hotswap/drivers/scsi/Config.in
@@ -1,5 +1,6 @@
 comment 'SCSI support type (disk, tape, CD-ROM)'
 
+dep_tristate '  SCSI hotswap support' CONFIG_SCSIFCHOTSWAP $CONFIG_SCSI
 dep_tristate '  SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
 
 if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
drivers/scsi/Makefile +1 -0
diff -uNr linux-2.5.44-qla/drivers/scsi/Makefile linux-2.5.44-scsi-hotswap/drivers/scsi/Makefile
@@ -117,6 +117,7 @@
 
 obj-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi/
 
+obj-$(CONFIG_SCSIFCHOTSWAP)	+= hotswap.o
 obj-$(CONFIG_CHR_DEV_ST)	+= st.o
 obj-$(CONFIG_CHR_DEV_OSST)	+= osst.o
 obj-$(CONFIG_BLK_DEV_SD)	+= sd_mod.o
drivers/scsi/hosts.c +1 -0
diff -uNr linux-2.5.44-qla/drivers/scsi/hosts.c linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.c
@@ -371,6 +371,7 @@
 	scsi_hosts_registered++;
 
 	spin_lock_init(&shost->default_lock);
+	sema_init (&shost->host_queue_sema, 1);
 	scsi_assign_lock(shost, &shost->default_lock);
 	atomic_set(&shost->host_active,0);
 
drivers/scsi/hosts.h +7 -0
diff -uNr linux-2.5.44-qla/drivers/scsi/hosts.h linux-2.5.44-scsi-hotswap/drivers/scsi/hosts.h
@@ -264,6 +264,12 @@
      */
     int (* bios_param)(Disk *, struct block_device *, int []);
 
+	/*
+	 * Used to determine the id to send the inquiry command to during
+	 * hot additions of FibreChannel targets
+	 */
+	int (*get_scsi_info_from_wwn)(int mode, unsigned long long wwn, int *host, int *channel, int *lun, int *id);
+
     /*
      * This determines if we will use a non-interrupt driven
      * or an interrupt driven scheme,  It is set to the maximum number
@@ -374,6 +380,7 @@
      */
     struct list_head      sh_list;
     Scsi_Device           * host_queue;
+    struct semaphore	  host_queue_sema;
     struct list_head	  all_scsi_hosts;
     struct list_head	  my_devices;
 
drivers/scsi/hotswap.c +921 -0

921 lines not on this page · raw message

Binary files linux-2.5.44-qla/drivers/scsi/qla2xxx/.qla2x00.c.swp and linux-2.5.44-scsi-hotswap/drivers/scsi/qla2xxx/.qla2x00.c.swp differ Binary files linux-2.5.44-qla/drivers/scsi/qla2xxx/.qla2x00.h.swp and linux-2.5.44-scsi-hotswap/drivers/scsi/qla2xxx/.qla2x00.h.swp differ

drivers/scsi/qla2xxx/qla2x00.c +76 -0

94 lines not on this page · raw message

drivers/scsi/scsi.c +39 -0
diff -uNr linux-2.5.44-qla/drivers/scsi/scsi.c linux-2.5.44-scsi-hotswap/drivers/scsi/scsi.c
@@ -413,6 +413,9 @@
 				 * allow us to more easily figure out whether we should
 				 * do anything here or not.
 				 */
+
+				down (&host->host_queue_sema);
+
 				for (SDpnt = host->host_queue;
 				     SDpnt;
 				     SDpnt = SDpnt->next) {
@@ -430,6 +433,9 @@
                                                 break;
                                         }
 				}
+
+				up (&host->host_queue_sema);
+
 				if (SDpnt) {
 					/*
 					 * Some other device in this cluster is busy.
@@ -1694,6 +1700,8 @@
 		len += size;
 		pos = begin + len;
 #endif
+		down (&HBA_ptr->host_queue_sema);
+
 		for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
 			proc_print_scsidevice(scd, buffer, &size, len);
 			len += size;
@@ -1706,6 +1714,8 @@
 			if (pos > offset + length)
 				goto stop_output;
 		}
+
+		up (&HBA_ptr->host_queue_sema);
 	}
 
 stop_output:
@@ -1864,6 +1874,8 @@
 		if (!HBA_ptr)
 			goto out;
 
+		down (&HBA_ptr->host_queue_sema);
+
 		for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
 			if ((scd->channel == channel
 			     && scd->id == id
@@ -1872,6 +1884,8 @@
 			}
 		}
 
+		up (&HBA_ptr->host_queue_sema);
+
 		err = -ENOSYS;
 		if (scd)
 			goto out;	/* We do not yet support unplugging */
@@ -1910,6 +1924,8 @@
 		if (!HBA_ptr)
 			goto out;
 
+		down (&HBA_ptr->host_queue_sema);
+
 		for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
 			if ((scd->channel == channel
 			     && scd->id == id
@@ -1918,6 +1934,8 @@
 			}
 		}
 
+		up (&HBA_ptr->host_queue_sema);
+
 		if (scd == NULL)
 			goto out;	/* there is no such device attached */
 
@@ -1951,9 +1969,14 @@
 			if (scd->prev != NULL)
 				scd->prev->next = scd->next;
 
+			down (&HBA_ptr->host_queue_sema);
+
 			if (HBA_ptr->host_queue == scd) {
 				HBA_ptr->host_queue = scd->next;
 			}
+
+			up (&HBA_ptr->host_queue_sema);
+
 			blk_cleanup_queue(&scd->request_queue);
 			if (scd->inquiry)
 				kfree(scd->inquiry);
@@ -1997,11 +2020,15 @@
 
 	for (shpnt = scsi_host_get_next(NULL); shpnt;
 	     shpnt = scsi_host_get_next(shpnt)) {
+		down (&shpnt->host_queue_sema);
+
 		for (SDpnt = shpnt->host_queue; SDpnt;
 		     SDpnt = SDpnt->next) {
 			if (tpnt->detect)
 				SDpnt->attached += (*tpnt->detect) (SDpnt);
 		}
+
+		up (&shpnt->host_queue_sema);
 	}
 
 	/*
@@ -2017,6 +2044,8 @@
 	 */
 	for (shpnt = scsi_host_get_next(NULL); shpnt;
 	     shpnt = scsi_host_get_next(shpnt)) {
+		down (&shpnt->host_queue_sema);
+
 		for (SDpnt = shpnt->host_queue; SDpnt;
 		     SDpnt = SDpnt->next) {
 			if (tpnt->attach)
@@ -2032,6 +2061,8 @@
 					out_of_space = 1;
 			}
 		}
+
+		up (&shpnt->host_queue_sema);
 	}
 
 	/*
@@ -2068,6 +2099,8 @@
 
 	for (shpnt = scsi_host_get_next(NULL); shpnt;
 	     shpnt = scsi_host_get_next(shpnt)) {
+		spin_lock (&shpnt->host_queue_sema);
+
 		for (SDpnt = shpnt->host_queue; SDpnt;
 		     SDpnt = SDpnt->next) {
 			if (tpnt->detach)
@@ -2084,6 +2117,8 @@
 				scsi_release_commandblocks(SDpnt);
 			}
 		}
+
+		up (&shpnt->host_queue_sema);
 	}
 	/*
 	 * Extract the template from the linked list.
@@ -2154,6 +2189,8 @@
 	for (shpnt = scsi_host_get_next(NULL); shpnt;
 	     shpnt = scsi_host_get_next(shpnt)) {
 		printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n");
+		down (&shpnt->host_queue_sema);
+
 		for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
 			for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
 				/*  (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x      */
@@ -2185,6 +2222,8 @@
 				       SCpnt->result);
 			}
 		}
+
+		up (&shpnt->host_queue_sema);
 	}
 #endif	/* CONFIG_SCSI_LOGGING */ /* } */
 }
drivers/scsi/scsi_error.c +21 -0
diff -uNr linux-2.5.44-qla/drivers/scsi/scsi_error.c linux-2.5.44-scsi-hotswap/drivers/scsi/scsi_error.c
@@ -202,6 +202,8 @@
 	int devices_failed = 0;
 
 
+	down (&shost->host_queue_sema);
+
 	for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
 		for (scmd = sc_list; scmd; scmd = scmd->bh_next) {
 			if (scmd->device == sdev) {
@@ -227,6 +229,8 @@
 		}
 	}
 
+	up (&shost->host_queue_sema);
+
 	SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d"
 					  " devices require eh work\n",
 				  total_failures, devices_failed));
@@ -247,6 +251,8 @@
 	Scsi_Device *sdev;
 	Scsi_Cmnd *scmd;
 
+	down (&shost->host_queue_sema);
+
 	for (found = 0, sdev = shost->host_queue; sdev; sdev = sdev->next) {
 		for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
 			if (scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) {
@@ -283,6 +289,8 @@
 		}
 	}
 
+	up (&shost->host_queue_sema);
+
 	SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(*sc_list, shost));
 
 	if (shost->host_failed != found)
@@ -962,6 +970,8 @@
 
 	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Trying BDR\n", __FUNCTION__));
 
+	down (&shost->host_queue_sema);
+
 	for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
 		for (scmd = sc_todo; scmd; scmd = scmd->bh_next)
 			if ((scmd->device == sdev) &&
@@ -985,6 +995,7 @@
 							scsi_eh_finish_cmd(scmd, shost);
 					}
 	}
+	up (&shost->host_queue_sema);
 
 	return shost->host_failed;
 }
@@ -1016,11 +1027,15 @@
 		/*
 		 * Mark all affected devices to expect a unit attention.
 		 */
+		down (&scmd->host->host_queue_sema);
+
 		for (sdev = scmd->host->host_queue; sdev; sdev = sdev->next)
 			if (scmd->channel == sdev->channel) {
 				sdev->was_reset = 1;
 				sdev->expecting_cc_ua = 1;
 			}
+
+		up (&scmd->host->host_queue_sema);
 	}
 	return rtn;
 }
@@ -1052,11 +1067,13 @@
 		/*
 		 * Mark all affected devices to expect a unit attention.
 		 */
+		down (&scmd->host->host_queue_sema);
 		for (sdev = scmd->host->host_queue; sdev; sdev = sdev->next)
 			if (scmd->channel == sdev->channel) {
 				sdev->was_reset = 1;
 				sdev->expecting_cc_ua = 1;
 			}
+		up (&scmd->host->host_queue_sema);
 	}
 	return rtn;
 }
@@ -1474,7 +1491,9 @@
 	 * now that error recovery is done, we will need to ensure that these
 	 * requests are started.
 	 */
+	down (&shost->host_queue_sema);
 	spin_lock_irqsave(shost->host_lock, flags);
+
 	for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
 		request_queue_t *q = &sdev->request_queue;
 
@@ -1487,7 +1506,9 @@
 
 		q->request_fn(q);
 	}
+
 	spin_unlock_irqrestore(shost->host_lock, flags);
+	up (&shost->host_queue_sema);
 }
 
 /**
drivers/scsi/scsi_lib.c +16 -0
diff -uNr linux-2.5.44-qla/drivers/scsi/scsi_lib.c linux-2.5.44-scsi-hotswap/drivers/scsi/scsi_lib.c
@@ -261,6 +261,8 @@
 	if (SDpnt->single_lun && blk_queue_empty(q) && SDpnt->device_busy ==0) {
 		request_queue_t *q;
 
+		down (&SHpnt->host_queue_sema);
+
 		for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
 			if (((SHpnt->can_queue > 0)
 			     && (SHpnt->host_busy >= SHpnt->can_queue))
@@ -273,6 +275,8 @@
 			q = &SDpnt->request_queue;
 			q->request_fn(q);
 		}
+
+		up (&SHpnt->host_queue_sema);
 	}
 
 	/*
@@ -285,6 +289,7 @@
 	 */
 	all_clear = 1;
 	if (SHpnt->some_device_starved) {
+		down (&SHpnt->host_queue_sema);
 		for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
 			request_queue_t *q;
 			if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue))
@@ -299,6 +304,7 @@
 			q->request_fn(q);
 			all_clear = 0;
 		}
+		up (&SHpnt->host_queue_sema);
 		if (SDpnt == NULL && all_clear) {
 			SHpnt->some_device_starved = 0;
 		}
@@ -1038,8 +1044,13 @@
 
 	SHpnt->host_self_blocked = FALSE;
 	/* Now that we are unblocked, try to start the queues. */
+
+	down (&SHpnt->host_queue_sema);
+
 	for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next)
 		scsi_queue_next_request(&SDloop->request_queue, NULL);
+
+	up (&SHpnt->host_queue_sema);
 }
 
 /*
@@ -1066,12 +1077,17 @@
 void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel)
 {
 	Scsi_Device *SDloop;
+
+	down (&SHpnt->host_queue_sema);
+
 	for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) {
 		if (channel == SDloop->channel) {
 			SDloop->was_reset = 1;
 			SDloop->expecting_cc_ua = 1;
 		}
 	}
+
+	up (&SHpnt->host_queue_sema);
 }
 
 /*
drivers/scsi/scsi_scan.c +9 -1
diff -uNr linux-2.5.44-qla/drivers/scsi/scsi_scan.c linux-2.5.44-scsi-hotswap/drivers/scsi/scsi_scan.c
@@ -530,6 +530,8 @@
 		/*
 		 * Add it to the end of the shost->host_queue list.
 		 */
+		down (&shost->host_queue_sema);
+
 		if (shost->host_queue != NULL) {
 			sdev->prev = shost->host_queue;
 			while (sdev->prev->next != NULL)
@@ -538,6 +540,8 @@
 		} else
 			shost->host_queue = sdev;
 
+		up (&shost->host_queue_sema);
+
 	}
 	return (sdev);
 }
@@ -554,8 +558,12 @@
 {
 	if (sdev->prev != NULL)
 		sdev->prev->next = sdev->next;
-	else
+	else {
+		down (&sdev->host->host_queue_sema);
 		sdev->host->host_queue = sdev->next;
+		up (&sdev->host->host_queue_sema);
+	}
+
 	if (sdev->next != NULL)
 		sdev->next->prev = sdev->prev;
 
include/linux/scsi_hotswap.h +84 -0

84 lines not on this page · raw message