patch-2.4.5 linux/drivers/scsi/aic7xxx/aic7xxx_linux.c

Next file: linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
Previous file: linux/drivers/scsi/aic7xxx/aic7xxx_inline.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC7xxx device driver for Linux.
  *
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#54 $
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#66 $
  *
  * Copyright (c) 1994 John Aycock
  *   The University of Calgary Department of Computer Science.
@@ -112,6 +112,7 @@
  *  8: SMP friendliness has been improved
  *
  */
+
 #include <linux/config.h>
 
 /*
@@ -158,8 +159,8 @@
  * The scsi error recovery code performs its own bus settle
  * delay handling for error recovery actions.
  */
-#ifdef CONFIG_AIC7XXX_RESET_DELAY
-#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
+#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS
+#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS
 #else
 #define AIC7XXX_RESET_DELAY 5000
 #endif
@@ -479,45 +480,48 @@
 
 #endif
 
-static void ahc_handle_scsi_status(struct ahc_softc *,
-				   struct ahc_linux_device *, struct scb *);
-static void ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd);
-static void ahc_sem_timeout(u_long arg);
-static void ahc_release_sim_queue(u_long arg);
-static int aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
-static void aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc);
-static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
-				       Scsi_Device *scsi_devs);
-static void aic7xxx_device_queue_depth(struct ahc_softc *ahc,
-				       Scsi_Device *device);
-static struct ahc_linux_target*	ahc_alloc_target(struct ahc_softc *,
-						 u_int, u_int);
-static void			ahc_free_target(struct ahc_softc *ahc,
-						struct ahc_linux_target *targ);
-static struct ahc_linux_device*	ahc_alloc_device(struct ahc_softc *,
-						 struct ahc_linux_target *,
-						 u_int);
-static void			ahc_free_device(struct ahc_softc *ahc,
-						struct ahc_linux_device *dev);
-static void ahc_run_device_queue(struct ahc_softc *ahc,
-				 struct ahc_linux_device *dev);
-static void ahc_setup_tag_info(char *p, char *end);
-static int ahc_next_unit(void);
+static void ahc_linux_handle_scsi_status(struct ahc_softc *,
+					 struct ahc_linux_device *,
+					 struct scb *);
+static void ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd);
+static void ahc_linux_sem_timeout(u_long arg);
+static void ahc_linux_freeze_sim_queue(struct ahc_softc *ahc);
+static void ahc_linux_release_sim_queue(u_long arg);
+static int  ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
+static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
+static void ahc_linux_select_queue_depth(struct Scsi_Host *host,
+					 Scsi_Device *scsi_devs);
+static void ahc_linux_device_queue_depth(struct ahc_softc *ahc,
+					 Scsi_Device *device);
+static struct ahc_linux_target*	ahc_linux_alloc_target(struct ahc_softc*,
+						       u_int, u_int);
+static void			ahc_linux_free_target(struct ahc_softc*,
+						      struct ahc_linux_target*);
+static struct ahc_linux_device*	ahc_linux_alloc_device(struct ahc_softc*,
+						       struct ahc_linux_target*,
+						       u_int);
+static void			ahc_linux_free_device(struct ahc_softc*,
+						      struct ahc_linux_device*);
+static void ahc_linux_run_device_queue(struct ahc_softc*,
+				       struct ahc_linux_device*);
+static void ahc_linux_setup_tag_info(char *p, char *end);
+static int ahc_linux_next_unit(void);
+static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf);
 
 static __inline struct ahc_linux_device*
-		     ahc_get_device(struct ahc_softc *ahc, u_int channel,
-				    u_int target, u_int lun, int /*alloc*/);
-static __inline void ahc_queue_cmd_complete(struct ahc_softc *ahc,
-					    Scsi_Cmnd *cmd);
-static __inline void ahc_run_complete_queue(struct ahc_softc *ahc,
-					    struct ahc_cmd *acmd);
-static __inline void ahc_check_device_queue(struct ahc_softc *ahc,
-					  struct ahc_linux_device *dev);
-static __inline void ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd);
-static __inline void ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb);
+		     ahc_linux_get_device(struct ahc_softc *ahc, u_int channel,
+					  u_int target, u_int lun, int alloc);
+static __inline void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc,
+						  Scsi_Cmnd *cmd);
+static __inline void ahc_linux_run_complete_queue(struct ahc_softc *ahc,
+						  struct ahc_cmd *acmd);
+static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc,
+						  struct ahc_linux_device *dev);
+static __inline void ahc_linux_sniff_command(struct ahc_softc*, Scsi_Cmnd*);
+static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
 
 static __inline struct ahc_linux_device*
-ahc_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
+ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
 	       u_int lun, int alloc)
 {
 	struct ahc_linux_target *targ;
@@ -530,7 +534,7 @@
 	targ = ahc->platform_data->targets[target_offset];
 	if (targ == NULL) {
 		if (alloc != 0) {
-			targ = ahc_alloc_target(ahc, channel, target);
+			targ = ahc_linux_alloc_target(ahc, channel, target);
 			if (targ == NULL)
 				return (NULL);
 		} else
@@ -538,17 +542,17 @@
 	}
 	dev = targ->devices[lun];
 	if (dev == NULL && alloc != 0)
-		dev = ahc_alloc_device(ahc, targ, lun);
+		dev = ahc_linux_alloc_device(ahc, targ, lun);
 	return (dev);
 }
 
 static __inline void
-ahc_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
 {
 	/*
 	 * Typically, the complete queue has very few entries
 	 * queued to it before the queue is emptied by
-	 * ahc_run_complete_queue, so sorting the entries
+	 * ahc_linux_run_complete_queue, so sorting the entries
 	 * by generation number should be inexpensive.
 	 * We perform the sort so that commands that complete
 	 * with an error are retuned in the order origionally
@@ -584,7 +588,7 @@
 }
 
 static __inline void
-ahc_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd)
+ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd)
 {	
 	u_long done_flags;
 
@@ -601,7 +605,8 @@
 }
 
 static __inline void
-ahc_check_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+ahc_linux_check_device_queue(struct ahc_softc *ahc,
+			     struct ahc_linux_device *dev)
 {
 	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0
 	 && dev->active == 0) {
@@ -613,11 +618,11 @@
 	 || dev->openings == 0 || dev->qfrozen != 0)
 		return;
 
-	ahc_run_device_queue(ahc, dev);
+	ahc_linux_run_device_queue(ahc, dev);
 }
 
 static __inline void
-ahc_run_device_queues(struct ahc_softc *ahc)
+ahc_linux_run_device_queues(struct ahc_softc *ahc)
 {
 	struct ahc_linux_device *dev;
 
@@ -626,25 +631,25 @@
 	    && (dev = LIST_FIRST(&ahc->platform_data->device_runq)) != NULL) {
 		LIST_REMOVE(dev, links);
 		dev->flags &= ~AHC_DEV_ON_RUN_LIST;
-		ahc_check_device_queue(ahc, dev);
+		ahc_linux_check_device_queue(ahc, dev);
 	}
 }
 
 static __inline void
-ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+ahc_linux_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
 {
 	/*
 	 * Determine whether we care to filter
 	 * information out of this command.  If so,
-	 * pass it on to ahc_filter_command() for more
+	 * pass it on to ahc_linux_filter_command() for more
 	 * heavy weight processing.
 	 */
 	if (cmd->cmnd[0] == INQUIRY)
-		ahc_filter_command(ahc, cmd);
+		ahc_linux_filter_command(ahc, cmd);
 }
 
 static __inline void
-ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
+ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
 {
 	Scsi_Cmnd *cmd;
 
@@ -662,6 +667,24 @@
 				 scsi_to_pci_dma_dir(cmd->sc_data_direction));
 }
 
+/************************ Shutdown/halt/reboot hook ***************************/
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+static struct notifier_block ahc_linux_notifier = {
+	ahc_linux_halt, NULL, 0
+};
+
+static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf)
+{
+	struct ahc_softc *ahc;
+
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+		ahc_shutdown(ahc);
+	}
+	return (NOTIFY_OK);
+}
+
 /******************************** Macros **************************************/
 #define BUILD_SCSIID(ahc, cmd)						\
 	((((cmd)->target << TID_SHIFT) & TID)				\
@@ -820,6 +843,9 @@
 	/* Still equal.  Sort by BIOS address, ioport, or bus/slot/func. */
 	switch (rvalue) {
 	case AHC_PCI:
+	{
+		char primary_channel;
+
 		value = ahc_get_pci_bus(lahc->dev_softc)
 		      - ahc_get_pci_bus(rahc->dev_softc);
 		if (value != 0)
@@ -828,19 +854,18 @@
 		      - ahc_get_pci_slot(rahc->dev_softc);
 		if (value != 0)
 			break;
-		value = ahc_get_pci_function(lahc->dev_softc)
-		      - ahc_get_pci_function(rahc->dev_softc);
 		/*
 		 * On multi-function devices, the user can choose
 		 * to have function 1 probed before function 0.
-		 * Function 0 is the only one that will have
-		 * CHANNEL_B_PRIMARY set.
+		 * Give whichever channel is the primary channel
+		 * the lowest priority.
 		 */
-		if (value < 0
-		 && (lahc->flags & AHC_CHANNEL_B_PRIMARY) != 0)
-			/* Swap the two */
-			value = -value;
+		primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A';
+		value = 1;
+		if (lahc->channel == primary_channel)
+			value = -1;
 		break;
+	}
 	case AHC_EISA:
 		if ((rahc->flags & AHC_BIOS_ENABLED) != 0) {
 			value = lahc->platform_data->bios_address
@@ -857,7 +882,7 @@
 }
 
 static void
-ahc_setup_tag_info(char *p, char *end)
+ahc_linux_setup_tag_info(char *p, char *end)
 {
 	char	*base;
 	char	*tok;
@@ -865,7 +890,7 @@
 	char	*tok_end2;
 	int      i;
 	int      instance;
-	int	 device;
+	int	 targ;
 	int	 done;
 	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
 
@@ -873,7 +898,7 @@
 		return;
 
 	instance = -1;
-	device = -1;
+	targ = -1;
 	done = FALSE;
 	base = p;
 	/* Forward us just past the ':' */
@@ -886,13 +911,13 @@
 		case '{':
 			if (instance == -1)
 				instance = 0;
-			else if (device == -1)
-				device = 0;
+			else if (targ == -1)
+				targ = 0;
 			tok++;
 			break;
 		case '}':
-			if (device != -1)
-				device = -1;
+			if (targ != -1)
+				targ = -1;
 			else if (instance != -1)
 				instance = -1;
 			tok++;
@@ -901,11 +926,11 @@
 		case '.':
 			if (instance == -1)
 				done = TRUE;
-			else if (device >= 0)
-				device++;
+			else if (targ >= 0)
+				targ++;
 			else if (instance >= 0)
 				instance++;
-			if ((device >= AHC_NUM_TARGETS) ||
+			if ((targ >= AHC_NUM_TARGETS) ||
 			    (instance >= NUM_ELEMENTS(aic7xxx_tag_info)))
 				done = TRUE;
 			tok++;
@@ -926,11 +951,12 @@
 					done = FALSE;
 				}
 			}
-			if ((instance >= 0) && (device >= 0) &&
-			    (instance < NUM_ELEMENTS(aic7xxx_tag_info)) &&
-			    (device < AHC_NUM_TARGETS))
-				aic7xxx_tag_info[instance].tag_commands[device] =
+			if ((instance >= 0) && (targ >= 0)
+			 && (instance < NUM_ELEMENTS(aic7xxx_tag_info))
+			 && (targ < AHC_NUM_TARGETS)) {
+				aic7xxx_tag_info[instance].tag_commands[targ] =
 				    simple_strtoul(tok, NULL, 0) & 0xff;
+			}
 			tok = tok_end;
 			break;
 		}
@@ -980,7 +1006,7 @@
 				continue;
 
 			if (strncmp(p, "tag_info", n) == 0) {
-				ahc_setup_tag_info(p + n, end);
+				ahc_linux_setup_tag_info(p + n, end);
 			} else if (p[n] == ':') {
 				*(options[i].flag) =
 				    simple_strtoul(p + n + 1, NULL, 0);
@@ -989,8 +1015,10 @@
 			} else {
 				*(options[i].flag) = ~(*(options[i].flag));
 			}
+			break;
 		}
 	}
+	register_reboot_notifier(&ahc_linux_notifier);
 	return 1;
 }
 
@@ -1004,7 +1032,7 @@
  * Try to detect an Adaptec 7XXX controller.
  */
 int
-aic7xxx_detect(Scsi_Host_Template *template)
+ahc_linux_detect(Scsi_Host_Template *template)
 {
 	struct	ahc_softc *ahc;
 	int     found;
@@ -1016,8 +1044,8 @@
 	 */
 	if (offsetof(struct ahc_cmd_internal, end)
 	  > offsetof(struct scsi_cmnd, host_scribble)) {
-		printf("aic7xxx_detect: SCSI data structures changed.\n");
-		printf("aic7xxx_detect: Unable to attach\n");
+		printf("ahc_linux_detect: SCSI data structures changed.\n");
+		printf("ahc_linux_detect: Unable to attach\n");
 		return (0);
 	}
 #ifdef MODULE
@@ -1054,7 +1082,7 @@
 	found = 0;
 	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
 
-		if (aic7xxx_register_host(ahc, template) == 0)
+		if (ahc_linux_register_host(ahc, template) == 0)
 			found++;
 	}
 	aic7xxx_detect_complete++;
@@ -1062,7 +1090,7 @@
 }
 
 int
-aic7xxx_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
+ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
 {
 	char  buf[80];
 	struct Scsi_Host *host;
@@ -1081,12 +1109,13 @@
 	host->can_queue = AHC_MAX_QUEUE;
 	host->cmd_per_lun = 2;
 	host->sg_tablesize = AHC_NSEG;
-	host->select_queue_depths = aic7xxx_select_queue_depth;
+	host->select_queue_depths = ahc_linux_select_queue_depth;
+	/* XXX No way to communicate the ID for multiple channels */
 	host->this_id = ahc->our_id;
 	host->irq = ahc->platform_data->irq;
 	host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8;
 	host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
-	ahc_set_unit(ahc, ahc_next_unit());
+	ahc_set_unit(ahc, ahc_linux_next_unit());
 	sprintf(buf, "scsi%d", host->host_no);
 	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
 	if (new_name != NULL) {
@@ -1094,8 +1123,10 @@
 		ahc_set_name(ahc, new_name);
 	}
 	host->unique_id = ahc->unit;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
 	scsi_set_pci_device(host, ahc->dev_softc);
-	aic7xxx_initialize_scsi_bus(ahc);
+#endif
+	ahc_linux_initialize_scsi_bus(ahc);
 	ahc_unlock(ahc, &s);
 	return (0);
 }
@@ -1107,7 +1138,7 @@
  * scenario.
  */
 static int
-ahc_next_unit()
+ahc_linux_next_unit()
 {
 	struct ahc_softc *ahc;
 	int unit;
@@ -1129,7 +1160,7 @@
  * target.
  */
 void
-aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc)
+ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc)
 {
 	int i;
 	int numtarg;
@@ -1159,7 +1190,7 @@
 	for (; i < numtarg; i++) {
 		struct ahc_devinfo devinfo;
 		struct ahc_initiator_tinfo *tinfo;
-		struct tmode_tstate *tstate;
+		struct ahc_tmode_tstate *tstate;
 		u_int our_id;
 		u_int target_id;
 		char channel;
@@ -1175,20 +1206,27 @@
 		tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
 					    target_id, &tstate);
 		tinfo->goal = tinfo->user;
+		/*
+		 * Don't try negotiations that require PPR messages
+		 * until we successfully retrieve Inquiry data.
+		 */
+		tinfo->goal.ppr_options = 0;
+		if (tinfo->goal.transport_version > SCSI_REV_2)
+			tinfo->goal.transport_version = SCSI_REV_2;
 		ahc_compile_devinfo(&devinfo, our_id, target_id,
 				   CAM_LUN_WILDCARD, channel, ROLE_INITIATOR);
-		ahc_update_target_msg_request(ahc, &devinfo, tinfo,
-					     /*force*/FALSE, /*paused*/FALSE);
+		ahc_update_neg_request(ahc, &devinfo, tstate,
+				       tinfo, /*force*/FALSE);
 	}
 	/* Give the bus some time to recover */
 	if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) {
-		ahc->platform_data->qfrozen++;
+		ahc_linux_freeze_sim_queue(ahc);
 		init_timer(&ahc->platform_data->reset_timer);
 		ahc->platform_data->reset_timer.data = (u_long)ahc;
 		ahc->platform_data->reset_timer.expires =
 		    jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000;
 		ahc->platform_data->reset_timer.function =
-		    ahc_release_sim_queue;
+		    ahc_linux_release_sim_queue;
 		add_timer(&ahc->platform_data->reset_timer);
 	}
 }
@@ -1238,6 +1276,11 @@
 					   0x1000);
 #endif
 		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		/* XXX Need an instance detach in the PCI code */
+		if (ahc->dev_softc != NULL)
+			ahc->dev_softc->driver = NULL;
+#endif
 		free(ahc->platform_data, M_DEVBUF);
 	}
 }
@@ -1252,28 +1295,41 @@
 }
 
 void
-ahc_platform_set_tags(struct ahc_softc *ahc,
-		      struct ahc_devinfo *devinfo, int enable)
+ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		      ahc_queue_alg alg)
 {
 	struct ahc_linux_device *dev;
+	int was_queuing;
+	int now_queuing;
 
-	dev = ahc_get_device(ahc, devinfo->channel - 'A',
-			     devinfo->target,
-			     devinfo->lun, /*alloc*/FALSE);
+	dev = ahc_linux_get_device(ahc, devinfo->channel - 'A',
+				   devinfo->target,
+				   devinfo->lun, /*alloc*/FALSE);
+	was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
+	now_queuing = alg != AHC_QUEUE_NONE;
 	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0
+	 && (was_queuing != now_queuing)
 	 && (dev->active != 0)) {
 		dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY;
 		dev->qfrozen++;
 	}
 
-	if (enable) {
-		/*
-		 * Start out agressively and allow our
-		 * dynamic queue depth algorithm take
-		 * care of the rest.
-		 */
-		dev->maxtags = AHC_MAX_QUEUE;
-		dev->openings = dev->maxtags - dev->active;
+	dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
+	if (now_queuing) {
+
+		if (!was_queuing) {
+			/*
+			 * Start out agressively and allow our
+			 * dynamic queue depth algorithm to take
+			 * care of the rest.
+			 */
+			dev->maxtags = AHC_MAX_QUEUE;
+			dev->openings = dev->maxtags - dev->active;
+		}
+		if (alg == AHC_QUEUE_TAGGED)
+			dev->flags |= AHC_DEV_Q_TAGGED;
+		else
+			dev->flags |= AHC_DEV_Q_BASIC;
 	} else {
 		/* We can only have one opening */
 		dev->maxtags = 0;
@@ -1326,9 +1382,9 @@
 				struct ahc_busyq *busyq;
 				struct ahc_cmd *acmd;
 
-				dev = ahc_get_device(ahc, chan, targ,
-						     clun, /*alloc*/FALSE);
-
+				dev = ahc_linux_get_device(ahc, chan,
+							   targ, clun,
+							   /*alloc*/FALSE);
 				if (dev == NULL)
 					continue;
 
@@ -1341,7 +1397,7 @@
 						     acmd_links.tqe);
 					count++;
 					cmd->result = status << 16;
-					ahc_queue_cmd_complete(ahc, cmd);
+					ahc_linux_queue_cmd_complete(ahc, cmd);
 				}
 			}
 		}
@@ -1355,8 +1411,8 @@
  * off the input host adapter.
  */
 static void
-aic7xxx_select_queue_depth(struct Scsi_Host * host,
-			   Scsi_Device * scsi_devs)
+ahc_linux_select_queue_depth(struct Scsi_Host * host,
+			     Scsi_Device * scsi_devs)
 {
 	Scsi_Device *device;
 	struct	ahc_softc *ahc;
@@ -1368,7 +1424,7 @@
 	scbnum = 0;
 	for (device = scsi_devs; device != NULL; device = device->next) {
 		if (device->host == host) {
-			aic7xxx_device_queue_depth(ahc, device);
+			ahc_linux_device_queue_depth(ahc, device);
 			scbnum += device->queue_depth;
 		}
 	}
@@ -1379,11 +1435,11 @@
  * Determines the queue depth for a given device.
  */
 static void
-aic7xxx_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device)
+ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device)
 {
 	struct	ahc_devinfo devinfo;
 	struct	ahc_initiator_tinfo *targ_info;
-	struct	tmode_tstate *tstate;
+	struct	ahc_tmode_tstate *tstate;
 	uint8_t tags;
 
 	ahc_compile_devinfo(&devinfo,
@@ -1397,7 +1453,7 @@
 
 	tags = 0;
 	if (device->tagged_supported != 0
-	 && (tstate->discenable & devinfo.target_mask) != 0) {
+	 && (ahc->user_discenable & devinfo.target_mask) != 0) {
 		if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) {
 
 			printf("aic7xxx: WARNING, insufficient "
@@ -1418,7 +1474,7 @@
 	}
 	if (tags != 0) {
 		device->queue_depth = tags;
-		ahc_set_tags(ahc, &devinfo, TRUE);
+		ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
 		printf("scsi%d:%d:%d:%d: Tagged Queuing enabled.  Depth %d\n",
 	       	       ahc->platform_data->host->host_no, device->channel,
 		       device->id, device->lun, tags);
@@ -1437,7 +1493,7 @@
  * Queue an SCB to the controller.
  */
 int
-aic7xxx_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
+ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
 {
 	struct	 ahc_softc *ahc;
 	struct	 ahc_linux_device *dev;
@@ -1451,29 +1507,29 @@
 	cmd->scsi_done = scsi_done;
 
 	ahc_lock(ahc, &flags);
-	dev = ahc_get_device(ahc, cmd->channel, cmd->target,
-			     cmd->lun, /*alloc*/TRUE);
+	dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target,
+				   cmd->lun, /*alloc*/TRUE);
 	if (dev == NULL) {
 		ahc_unlock(ahc, &flags);
-		printf("aic7xxx_queue: Unable to allocate device!\n");
+		printf("aic7xxx_linux_queue: Unable to allocate device!\n");
 		return (-ENOMEM);
 	}
 	cmd->result = CAM_REQ_INPROG << 16;
 	TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe);
-	ahc_run_device_queue(ahc, dev);
+	ahc_linux_run_device_queue(ahc, dev);
 	ahc_unlock(ahc, &flags);
 	return (0);
 }
 
 static void
-ahc_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
 {
 	struct	 ahc_cmd *acmd;
 	struct	 scsi_cmnd *cmd;
 	struct	 scb *scb;
 	struct	 hardware_scb *hscb;
 	struct	 ahc_initiator_tinfo *tinfo;
-	struct	 tmode_tstate *tstate;
+	struct	 ahc_tmode_tstate *tstate;
 	uint16_t mask;
 
 	while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL
@@ -1524,19 +1580,26 @@
 					    SCB_GET_OUR_ID(scb),
 					    SCB_GET_TARGET(ahc, scb), &tstate);
 		hscb->scsirate = tinfo->scsirate;
-		hscb->scsioffset = tinfo->current.offset;
+		hscb->scsioffset = tinfo->curr.offset;
 		if ((tstate->ultraenb & mask) != 0)
 			hscb->control |= ULTRAENB;
 
-		if ((tstate->discenable & mask) != 0)
+		if ((ahc->user_discenable & mask) != 0)
 			hscb->control |= DISCENB;
 
-		if ((tstate->tagenable & mask) != 0) {
-			/* XXX What about devices that dislike ordered tags? */
-			if ((dev->num_commands % 256) == 0)
-				hscb->control |= MSG_ORDERED_Q_TAG;
-			else
-				hscb->control |= MSG_SIMPLE_Q_TAG;
+		if ((tstate->auto_negotiate & mask) != 0) {
+			scb->flags |= SCB_AUTO_NEGOTIATE;
+			scb->hscb->control |= MK_MESSAGE;
+		}
+
+		if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) {
+			if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH
+			 && (dev->flags & AHC_DEV_Q_TAGGED) != 0) {
+				hscb->control |= MSG_ORDERED_TASK;
+				dev->commands_since_idle_or_otag = 0;
+			} else {
+				hscb->control |= MSG_SIMPLE_TASK;
+			}
 		}
 
 		hscb->cdb_len = cmd->cmd_len;
@@ -1632,7 +1695,8 @@
 		LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
 		dev->openings--;
 		dev->active++;
-		dev->num_commands++;
+		dev->commands_issued++;
+		dev->commands_since_idle_or_otag++;
 
 		/*
 		 * We only allow one untagged transaction
@@ -1661,7 +1725,7 @@
  * SCSI controller interrupt handler.
  */
 void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs)
+ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct ahc_softc *ahc;
 	struct ahc_cmd *acmd;
@@ -1676,12 +1740,12 @@
 	 * dynamically register one, we'll have to postpone
 	 * that until we get integrated into the kernel.
 	 */
-	ahc_run_device_queues(ahc);
+	ahc_linux_run_device_queues(ahc);
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
 	ahc_unlock(ahc, &flags);
 	if (acmd != NULL)
-		ahc_run_complete_queue(ahc, acmd);
+		ahc_linux_run_complete_queue(ahc, acmd);
 }
 
 void
@@ -1692,11 +1756,11 @@
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
 	if (acmd != NULL)
-		ahc_run_complete_queue(ahc, acmd);
+		ahc_linux_run_complete_queue(ahc, acmd);
 }
 
 static struct ahc_linux_target*
-ahc_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target)
+ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target)
 {
 	struct ahc_linux_target *targ;
 	u_int target_offset;
@@ -1715,7 +1779,7 @@
 }
 
 static void
-ahc_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ)
+ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ)
 {
 	u_int target_offset;
 
@@ -1727,7 +1791,7 @@
 }
 
 static struct ahc_linux_device*
-ahc_alloc_device(struct ahc_softc *ahc,
+ahc_linux_alloc_device(struct ahc_softc *ahc,
 		 struct ahc_linux_target *targ, u_int lun)
 {
 	struct ahc_linux_device *dev;
@@ -1760,7 +1824,7 @@
 }
 
 static void
-ahc_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
 {
 	struct ahc_linux_target *targ;
 
@@ -1769,14 +1833,14 @@
 	free(dev, M_DEVBUF);
 	targ->refcount--;
 	if (targ->refcount == 0)
-		ahc_free_target(ahc, targ);
+		ahc_linux_free_target(ahc, targ);
 }
 
 /*
  * Return a string describing the driver.
  */
 const char *
-aic7xxx_info(struct Scsi_Host *host)
+ahc_linux_info(struct Scsi_Host *host)
 {
 	static char buffer[512];
 	char	ahc_info[256];
@@ -1802,7 +1866,7 @@
 
 void
 ahc_send_async(struct ahc_softc *ahc, char channel,
-	       u_int target, u_int lun, ac_code code)
+	       u_int target, u_int lun, ac_code code, void *arg)
 {
 	switch (code) {
 	case AC_TRANSFER_NEG:
@@ -1811,7 +1875,7 @@
 		struct	ahc_linux_target *targ;
 		struct	info_str info;
 		struct	ahc_initiator_tinfo *tinfo;
-		struct	tmode_tstate *tstate;
+		struct	ahc_tmode_tstate *tstate;
 		int	target_offset;
 
 		info.buffer = buf;
@@ -1827,10 +1891,10 @@
 		 * Don't bother reporting results while
 		 * negotiations are still pending.
 		 */
-		if (tinfo->current.period != tinfo->goal.period
-		 || tinfo->current.width != tinfo->goal.width
-		 || tinfo->current.offset != tinfo->goal.offset
-		 || tinfo->current.ppr_options != tinfo->goal.ppr_options)
+		if (tinfo->curr.period != tinfo->goal.period
+		 || tinfo->curr.width != tinfo->goal.width
+		 || tinfo->curr.offset != tinfo->goal.offset
+		 || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
 			if (bootverbose == 0)
 				break;
 
@@ -1843,24 +1907,24 @@
 			target_offset += 8;
 		targ = ahc->platform_data->targets[target_offset];
 		if (targ != NULL
-		 && tinfo->current.period == targ->last_tinfo.period
-		 && tinfo->current.width == targ->last_tinfo.width
-		 && tinfo->current.offset == targ->last_tinfo.offset
-		 && tinfo->current.ppr_options == targ->last_tinfo.ppr_options)
+		 && tinfo->curr.period == targ->last_tinfo.period
+		 && tinfo->curr.width == targ->last_tinfo.width
+		 && tinfo->curr.offset == targ->last_tinfo.offset
+		 && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options)
 			if (bootverbose == 0)
 				break;
 
-		targ->last_tinfo.period = tinfo->current.period;
-		targ->last_tinfo.width = tinfo->current.width;
-		targ->last_tinfo.offset = tinfo->current.offset;
-		targ->last_tinfo.ppr_options = tinfo->current.ppr_options;
+		targ->last_tinfo.period = tinfo->curr.period;
+		targ->last_tinfo.width = tinfo->curr.width;
+		targ->last_tinfo.offset = tinfo->curr.offset;
+		targ->last_tinfo.ppr_options = tinfo->curr.ppr_options;
 
 		printf("(%s:%c:", ahc_name(ahc), channel);
 		if (target == CAM_TARGET_WILDCARD)
 			printf("*): ");
 		else
 			printf("%d): ", target);
-		ahc_format_transinfo(&info, &tinfo->current);
+		ahc_format_transinfo(&info, &tinfo->curr);
 		if (info.pos < info.length)
 			*info.buffer = '\0';
 		else
@@ -1909,7 +1973,7 @@
 	dev = scb->platform_data->dev;
 	dev->active--;
 	dev->openings++;
-	ahc_unmap_scb(ahc, scb);
+	ahc_linux_unmap_scb(ahc, scb);
 	if (scb->flags & SCB_SENSE) {
 		memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb),
 		       MIN(sizeof(struct scsi_sense_data),
@@ -1928,10 +1992,19 @@
 			ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
 		} else {
 			ahc_set_transaction_status(scb, CAM_REQ_CMP);
-			ahc_sniff_command(ahc, cmd);
+			ahc_linux_sniff_command(ahc, cmd);
 		}
 	} else if (ahc_get_transaction_status(scb) == DID_OK) {
-		ahc_handle_scsi_status(ahc, dev, scb);
+		ahc_linux_handle_scsi_status(ahc, dev, scb);
+	} else if (ahc_get_transaction_status(scb) == DID_NO_CONNECT) {
+		/*
+		 * Should a selection timeout kill the device?
+		 * That depends on whether the selection timeout
+		 * is persistent.  Since we have no guarantee that
+		 * the mid-layer will issue an inquiry for this device
+		 * again, we can't just kill it off.
+		dev->flags |= AHC_DEV_UNCONFIGURED;
+		 */
 	}
 
 	if (dev->openings == 1
@@ -1950,10 +2023,14 @@
 		dev->openings++;
 	}
 
-	if (dev->active == 0
-	 && (dev->flags & AHC_DEV_UNCONFIGURED) != 0)
-		ahc_free_device(ahc, dev);
-	else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
+	if (dev->active == 0)
+		dev->commands_since_idle_or_otag = 0;
+
+	if (TAILQ_EMPTY(&dev->busyq)) {
+		if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0
+		 && dev->active == 0)
+			ahc_linux_free_device(ahc, dev);
+	} else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
 		LIST_INSERT_HEAD(&ahc->platform_data->device_runq, dev, links);
 		dev->flags |= AHC_DEV_ON_RUN_LIST;
 	}
@@ -1964,12 +2041,12 @@
 	}
 
 	ahc_free_scb(ahc, scb);
-	ahc_queue_cmd_complete(ahc, cmd);
+	ahc_linux_queue_cmd_complete(ahc, cmd);
 }
 
 static void
-ahc_handle_scsi_status(struct ahc_softc *ahc,
-		       struct ahc_linux_device *dev, struct scb *scb)
+ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
+			     struct ahc_linux_device *dev, struct scb *scb)
 {
 	/*
 	 * We don't currently trust the mid-layer to
@@ -2050,7 +2127,7 @@
 }
 
 static void
-ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
 {
 	switch (cmd->cmnd[0]) {
 	case INQUIRY:
@@ -2058,8 +2135,9 @@
 		struct	ahc_devinfo devinfo;
 		struct	scsi_inquiry_data *sid;
 		struct	ahc_initiator_tinfo *targ_info;
-		struct	tmode_tstate *tstate;
+		struct	ahc_tmode_tstate *tstate;
 		struct	ahc_syncrate *syncrate;
+		struct	ahc_linux_device *dev;
 		u_int	scsiid;
 		u_int	maxsync;
 		int	minlen;
@@ -2078,15 +2156,20 @@
 		/*
 		 * Determine if this lun actually exists.  If so,
 		 * hold on to its corresponding device structure.
-		 */
+		 * If not, make sure we release the device and
+		 * don't bother processing the rest of this inquiry
+		 * command.
+		 */
+		dev = ahc_linux_get_device(ahc, cmd->channel,
+					   cmd->target, cmd->lun,
+					   /*alloc*/FALSE);
 		if (cmd->request_bufflen >= 1
 		 && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) {
-			struct ahc_linux_device *dev;
 
-			dev = ahc_get_device(ahc, cmd->channel,
-					     cmd->target, cmd->lun,
-					     /*alloc*/FALSE);
 			dev->flags &= ~AHC_DEV_UNCONFIGURED;
+		} else {
+			dev->flags |= AHC_DEV_UNCONFIGURED;
+			break;
 		}
 
 		/*
@@ -2108,17 +2191,17 @@
 		ppr_options = targ_info->user.ppr_options;
 		minlen = offsetof(struct scsi_inquiry_data, version) + 1;
 		if (cmd->request_bufflen >= minlen) {
-			targ_info->current.protocol_version = SID_ANSI_REV(sid);
+			targ_info->curr.protocol_version = SID_ANSI_REV(sid);
 
 			/*
 			 * Only attempt SPI3 once we've verified that
 			 * the device claims to support SPI3 features.
 			 */
-			if (targ_info->current.protocol_version < SCSI_REV_2)
-				targ_info->current.transport_version =
+			if (targ_info->curr.protocol_version < SCSI_REV_2)
+				targ_info->curr.transport_version =
 				    SID_ANSI_REV(sid);
 			else
-				targ_info->current.transport_version =
+				targ_info->curr.transport_version =
 				     SCSI_REV_2;
 		}
 
@@ -2137,18 +2220,26 @@
 			break;
 		}
 		minlen = offsetof(struct scsi_inquiry_data, spi3data) + 1;
-		if (cmd->request_bufflen >= minlen
-		 && (sid->additional_length + 4) >= minlen) {
-			if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0)
+		/*
+		 * This is a kludge to deal with inquiry requests that
+		 * are not large enough for us to pull the spi3 bits.
+		 * In this case, we assume that a device that tells us
+		 * they can provide inquiry data that spans the SPI3
+		 * bits can handle a PPR request.  If the inquiry
+		 * request has sufficient buffer space to cover these
+		 * bits, we check them to see if any ppr options are
+		 * available.
+		 */
+		if ((sid->additional_length + 4) >= minlen) {
+			if (cmd->request_bufflen >= minlen
+			 && (sid->spi3data & SID_SPI_CLOCK_DT) == 0)
 				ppr_options = 0;
 
-			if ((sid->spi3data & SID_SPI_MASK) != 0
-			 && targ_info->current.protocol_version > SCSI_REV_2)
-				targ_info->current.transport_version = 3;
+			if (targ_info->curr.protocol_version > SCSI_REV_2)
+				targ_info->curr.transport_version = 3;
 		} else {
 			ppr_options = 0;
 		}
-
 		ahc_validate_width(ahc, /*tinfo limit*/NULL, &width,
 				   ROLE_UNKNOWN);
 		if ((ahc->features & AHC_ULTRA2) != 0)
@@ -2162,6 +2253,11 @@
 					     &ppr_options, maxsync);
 		ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate,
 				    &offset, width, ROLE_UNKNOWN);
+		if (offset == 0 || period == 0) {
+			period = 0;
+			offset = 0;
+			ppr_options = 0;
+		}
 		/* Apply our filtered user settings. */
 		ahc_set_width(ahc, &devinfo, width,
 			      AHC_TRANS_GOAL, /*paused*/FALSE);
@@ -2171,14 +2267,14 @@
 		break;
 	}
 	default:
-		panic("ahc_filter_command: Unexpected Command type  %x\n",
+		panic("ahc_linux_filter_command: Unexpected Command type  %x\n",
 		      cmd->cmnd[0]);
 		break;
 	}
 }
 
 static void
-ahc_sem_timeout(u_long arg)
+ahc_linux_sem_timeout(u_long arg)
 {
 	struct semaphore *sem;
 
@@ -2187,22 +2283,42 @@
 }
 
 static void
-ahc_release_sim_queue(u_long arg)
+ahc_linux_freeze_sim_queue(struct ahc_softc *ahc)
+{
+	ahc->platform_data->qfrozen++;
+	if (ahc->platform_data->qfrozen == 1)
+		scsi_block_requests(ahc->platform_data->host);
+}
+
+static void
+ahc_linux_release_sim_queue(u_long arg)
 {
 	struct ahc_softc *ahc;
 	u_long s;
+	int    unblock_reqs;
 
 	ahc = (struct ahc_softc *)arg;
+	unblock_reqs = 0;
 	ahc_lock(ahc, &s);
 	if (ahc->platform_data->qfrozen > 0)
 		ahc->platform_data->qfrozen--;
-	if (ahc->platform_data->qfrozen == 0)
-		ahc_run_device_queues(ahc);
+	if (ahc->platform_data->qfrozen == 0) {
+		unblock_reqs = 1;
+		ahc_linux_run_device_queues(ahc);
+	}
 	ahc_unlock(ahc, &s);
+	/*
+	 * There is still a race here.  The mid-layer
+	 * should keep its own freeze count and use
+	 * a bottom half handler to run the queues
+	 * so we can unblock with our own lock held.
+	 */
+	if (unblock_reqs)
+		scsi_unblock_requests(ahc->platform_data->host);
 }
 
 static int
-aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
+ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
 {
 	struct ahc_softc *ahc;
 	struct ahc_cmd *acmd;
@@ -2242,8 +2358,8 @@
 	 * at all, and the system wanted us to just abort the
 	 * command return success.
 	 */
-	dev = ahc_get_device(ahc, cmd->channel, cmd->target,
-			     cmd->lun, /*alloc*/FALSE);
+	dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target,
+				   cmd->lun, /*alloc*/FALSE);
 
 	if (dev == NULL) {
 		/*
@@ -2267,7 +2383,7 @@
 		if (flag == SCB_ABORT) {
 			TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);
 			cmd->result = DID_ABORT << 16;
-			ahc_queue_cmd_complete(ahc, cmd);
+			ahc_linux_queue_cmd_complete(ahc, cmd);
 			retval = SUCCESS;
 			goto done;
 		}
@@ -2315,7 +2431,7 @@
 	ahc->flags |= AHC_ALL_INTERRUPTS;
 	do {
 		ahc_intr(ahc);
-		pause_sequencer(ahc);
+		ahc_pause(ahc);
 		ahc_clear_critical_section(ahc);
 	} while (ahc_inb(ahc, INTSTAT) & INT_PEND);
 	ahc->flags &= ~AHC_ALL_INTERRUPTS;
@@ -2455,7 +2571,7 @@
 	retval = SUCCESS;
 done:
 	if (paused)
-		unpause_sequencer(ahc);
+		ahc_unpause(ahc);
 	if (wait) {
     		struct timer_list timer;
 		int ret;
@@ -2464,7 +2580,7 @@
 		init_timer(&timer);
 		timer.data = (u_long)&ahc->platform_data->eh_sem;
 		timer.expires = jiffies + (5 * HZ);
-		timer.function = ahc_sem_timeout;
+		timer.function = ahc_linux_sem_timeout;
 		add_timer(&timer);
 		printf("Recovery code sleeping\n");
 		down(&ahc->platform_data->eh_sem);
@@ -2476,12 +2592,12 @@
 		}
 		ahc_lock(ahc, &s);
 	}
-	ahc_run_device_queues(ahc);
+	ahc_linux_run_device_queues(ahc);
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
 	ahc_unlock(ahc, &s);
 	if (acmd != NULL)
-		ahc_run_complete_queue(ahc, acmd);
+		ahc_linux_run_complete_queue(ahc, acmd);
 	spin_lock_irq(&io_request_lock);
 	return (retval);
 }
@@ -2490,11 +2606,11 @@
  * Abort the current SCSI command(s).
  */
 int
-aic7xxx_abort(Scsi_Cmnd *cmd)
+ahc_linux_abort(Scsi_Cmnd *cmd)
 {
 	int error;
 
-	error = aic7xxx_queue_recovery_cmd(cmd, SCB_ABORT);
+	error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT);
 	if (error != 0)
 		printf("aic7xxx_abort returns %d\n", error);
 	return (error);
@@ -2504,11 +2620,11 @@
  * Attempt to send a target reset message to the device that timed out.
  */
 int
-aic7xxx_dev_reset(Scsi_Cmnd *cmd)
+ahc_linux_dev_reset(Scsi_Cmnd *cmd)
 {
 	int error;
 
-	error = aic7xxx_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
+	error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
 	if (error != 0)
 		printf("aic7xxx_dev_reset returns %d\n", error);
 	return (error);
@@ -2518,7 +2634,7 @@
  * Reset the SCSI bus.
  */
 int
-aic7xxx_bus_reset(Scsi_Cmnd *cmd)
+ahc_linux_bus_reset(Scsi_Cmnd *cmd)
 {
 	struct ahc_softc *ahc;
 	struct ahc_cmd *acmd;
@@ -2543,7 +2659,7 @@
 		       "%d SCBs aborted.\n", ahc_name(ahc), found);
 
 	if (acmd != NULL)
-		ahc_run_complete_queue(ahc, acmd);
+		ahc_linux_run_complete_queue(ahc, acmd);
 
 	spin_lock_irq(&io_request_lock);
 	return SUCCESS;
@@ -2553,7 +2669,7 @@
  * Return the disk geometry for the given SCSI device.
  */
 int
-aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
+ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
 {
 	int	heads;
 	int	sectors;
@@ -2597,14 +2713,23 @@
  * module.
  */
 int
-aic7xxx_release(struct Scsi_Host * host)
+ahc_linux_release(struct Scsi_Host * host)
 {
 	struct ahc_softc *ahc;
 
 	if (host != NULL) {
+
 		ahc = *(struct ahc_softc **)host->hostdata;
 		ahc_free(ahc);
 	}
+	if (TAILQ_EMPTY(&ahc_tailq)) {
+		unregister_reboot_notifier(&ahc_linux_notifier);
+#ifdef CONFIG_PCI
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		pci_unregister_driver(&aic7xxx_pci_driver);
+#endif
+#endif
+	}
 	return (0);
 }
 
@@ -2626,8 +2751,8 @@
 			for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
 				struct ahc_cmd *acmd;
 
-				dev = ahc_get_device(ahc, channel, target,
-						     lun, /*alloc*/FALSE);
+				dev = ahc_linux_get_device(ahc, channel, target,
+							   lun, /*alloc*/FALSE);
 				if (dev == NULL)
 					continue;
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)