patch-2.4.22 linux-2.4.22/drivers/scsi/aic7xxx/aic7770_osm.c

Next file: linux-2.4.22/drivers/scsi/aic7xxx/aic79xx.h
Previous file: linux-2.4.22/drivers/scsi/aic7xxx/aic7770.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/scsi/aic7xxx/aic7770_osm.c linux-2.4.22/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -1,7 +1,7 @@
 /*
  * Linux driver attachment glue for aic7770 based controllers.
  *
- * Copyright (c) 2000-2001 Adaptec Inc.
+ * Copyright (c) 2000-2003 Adaptec Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,33 +36,102 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#11 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#14 $
  */
 
 #include "aic7xxx_osm.h"
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <linux/device.h>
+#include <linux/eisa.h>
+
+#define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@')  /* Bits 26-30 */
+#define EISA_MFCTR_CHAR1(ID) (char)(((ID>>21) & 0x1F) | '@')  /* Bits 21-25 */
+#define EISA_MFCTR_CHAR2(ID) (char)(((ID>>16) & 0x1F) | '@')  /* Bits 16-20 */
+#define EISA_PRODUCT_ID(ID)  (short)((ID>>4)  & 0xFFF)        /* Bits  4-15 */
+#define EISA_REVISION_ID(ID) (uint8_t)(ID & 0x0F)             /* Bits  0-3  */
+
+static int aic7770_eisa_dev_probe(struct device *dev);
+static int aic7770_eisa_dev_remove(struct device *dev);
+static struct eisa_driver aic7770_driver = {
+	.driver = {
+		.name   = "aic7xxx",
+		.probe  = aic7770_eisa_dev_probe,
+		.remove = aic7770_eisa_dev_remove,
+	}
+};
+
+typedef  struct device *aic7770_dev_t;
+#else
 #define MINSLOT			1
 #define NUMSLOTS		16
 #define IDOFFSET		0x80
 
-int
-aic7770_linux_probe(Scsi_Host_Template *template)
+typedef void *aic7770_dev_t;
+#endif
+
+static int aic7770_linux_config(struct aic7770_identity *entry,
+				aic7770_dev_t dev, u_int eisaBase);
+
+void
+ahc_linux_eisa_init(void)
 {
-#if defined(__i386__) || defined(__alpha__)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	struct eisa_device_id *eid;
+	struct aic7770_identity *id;
+	int i;
+
+	if (aic7xxx_probe_eisa_vl == 0)
+		return;
+
+	/*
+	 * Linux requires the EISA IDs to be specified in
+	 * the EISA ID string format.  Perform the conversion
+	 * and setup a table with a NUL terminal entry.
+	 */
+	aic7770_driver.id_table = malloc(sizeof(struct eisa_device_id) *
+					 (ahc_num_aic7770_devs + 1),
+					 M_DEVBUF, M_NOWAIT);
+	if (aic7770_driver.id_table == NULL)
+		return;
+
+	for (eid = (struct eisa_device_id *)aic7770_driver.id_table,
+	     id = aic7770_ident_table, i = 0;
+	     i < ahc_num_aic7770_devs; eid++, id++, i++) {
+
+		sprintf(eid->sig, "%c%c%c%03X%01X",
+			EISA_MFCTR_CHAR0(id->full_id),
+			EISA_MFCTR_CHAR1(id->full_id),
+			EISA_MFCTR_CHAR2(id->full_id),
+			EISA_PRODUCT_ID(id->full_id),
+			EISA_REVISION_ID(id->full_id));
+		eid->driver_data = i;
+	}
+	eid->sig[0] = 0;
+
+	eisa_driver_register(&aic7770_driver);
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) */
 	struct aic7770_identity *entry;
-	struct ahc_softc *ahc;
-	int i, slot;
-	int eisaBase;
-	int found;
+	u_int  slot;
+	u_int  eisaBase;
+	u_int  i;
+
+	if (aic7xxx_probe_eisa_vl == 0)
+		return;
 
 	eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET;
-	found = 0;
 	for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) {
 		uint32_t eisa_id;
 		size_t	 id_size;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 		if (check_region(eisaBase, AHC_EISA_IOSIZE) != 0)
 			continue;
+		request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx");
+#else
+		if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") == 0)
+			continue;
+#endif
 
 		eisa_id = 0;
 		id_size = sizeof(eisa_id);
@@ -72,49 +141,69 @@
 			eisa_id |= inb(eisaBase + IDOFFSET + i)
 				   << ((id_size-i-1) * 8);
 		}
+		release_region(eisaBase, AHC_EISA_IOSIZE);
 		if (eisa_id & 0x80000000)
 			continue;  /* no EISA card in slot */
 
 		entry = aic7770_find_device(eisa_id);
-		if (entry != NULL) {
-			char	 buf[80];
-			char	*name;
-			int	 error;
-
-			/*
-			 * Allocate a softc for this card and
-			 * set it up for attachment by our
-			 * common detect routine.
-			 */
-			sprintf(buf, "ahc_eisa:%d", slot);
-			name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
-			if (name == NULL)
-				break;
-			strcpy(name, buf);
-			ahc = ahc_alloc(template, name);
-			if (ahc == NULL) {
-				/*
-				 * If we can't allocate this one,
-				 * chances are we won't be able to
-				 * allocate future card structures.
-				 */
-				break;
-			}
-			error = aic7770_config(ahc, entry, eisaBase);
-			if (error != 0) {
-				ahc->bsh.ioport = 0;
-				ahc_free(ahc);
-				continue;
-			}
-			found++;
-		}
+		if (entry != NULL)
+			aic7770_linux_config(entry, NULL, eisaBase);
+	}
+#endif
+}
+
+void
+ahc_linux_eisa_exit(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	if (aic7xxx_probe_eisa_vl == 0)
+		return;
+
+	if (aic7770_driver.id_table != NULL) {
+		eisa_driver_unregister(&aic7770_driver);
+		free(aic7770_driver.id_table, M_DEVBUF);
 	}
-	return (found);
-#else
-	return (0);
 #endif
 }
 
+static int
+aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev,
+		     u_int eisaBase)
+{
+	struct	ahc_softc *ahc;
+	char	buf[80];
+	char   *name;
+	int	error;
+
+	/*
+	 * Allocate a softc for this card and
+	 * set it up for attachment by our
+	 * common detect routine.
+	 */
+	sprintf(buf, "ahc_eisa:%d", eisaBase >> 12);
+	name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	if (name == NULL)
+		return (ENOMEM);
+	strcpy(name, buf);
+	ahc = ahc_alloc(&aic7xxx_driver_template, name);
+	if (ahc == NULL) {
+		free(name, M_DEVBUF);
+		return (ENOMEM);
+	}
+	error = aic7770_config(ahc, entry, eisaBase);
+	if (error != 0) {
+		ahc->bsh.ioport = 0;
+		ahc_free(ahc);
+		return (error);
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	dev->driver_data = (void *)ahc;
+	if (aic7xxx_detect_complete)
+		error = ahc_linux_register_host(ahc, &aic7xxx_driver_template);
+#endif
+	return (error);
+}
+
 int
 aic7770_map_registers(struct ahc_softc *ahc, u_int port)
 {
@@ -122,6 +211,8 @@
 	 * Lock out other contenders for our i/o space.
 	 */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+	if (check_region(port, AHC_EISA_IOSIZE) != 0)
+		return (ENOMEM);
 	request_region(port, AHC_EISA_IOSIZE, "aic7xxx");
 #else
 	if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0)
@@ -148,3 +239,41 @@
 	
 	return (-error);
 }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int
+aic7770_eisa_dev_probe(struct device *dev)
+{
+	struct eisa_device *edev;
+
+	edev = to_eisa_device(dev);
+	return (aic7770_linux_config(aic7770_ident_table + edev->id.driver_data,
+				    dev, edev->base_addr+AHC_EISA_SLOT_OFFSET));
+}
+
+static int
+aic7770_eisa_dev_remove(struct device *dev)
+{
+	struct ahc_softc *ahc;
+	u_long l;
+
+	/*
+	 * We should be able to just perform
+	 * the free directly, but check our
+	 * list for extra sanity.
+	 */
+	ahc_list_lock(&l);
+	ahc = ahc_find_softc((struct ahc_softc *)dev->driver_data);
+	if (ahc != NULL) {
+		u_long s;
+
+		ahc_lock(ahc, &s);
+		ahc_intr_enable(ahc, FALSE);
+		ahc_unlock(ahc, &s);
+		ahc_free(ahc);
+	}
+	ahc_list_unlock(&l);
+
+	return (0);
+}
+#endif

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