[SCSI] advansys: Sort out irq number mess

The interrupt number was being stored in 4-5 different places, each with
its own type, rules and usage.  Fix this by keeping an unsigned int in
the struct asc_board, and filling it in from the bus probe functions
(since it's different for each of the four bus types).  In order to do
this, we have to allocate the Scsi_Host in the bus probe functions too.
Then we can return an error from advansys_board_found, which requires
a little rearranging of code (and removing of the err_code variable).
Move the Wide Board flag setting into the PCI bus probe function.

Split the AscGetChipIRQ function into three functions (one for each bus
type that needs it) and add some commentary to explain what's going on.
Also get rid of the AscSetChipIRQ function as we only ever set the
interrupt number to the same value it already had.

Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index a5bb4e4..e2bd4c9 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -461,23 +461,13 @@
 /*
  * Error code values are set in ASC_DVC_VAR  'err_code'.
  */
-#define ASC_IERR_WRITE_EEPROM         0x0001
 #define ASC_IERR_MCODE_CHKSUM         0x0002
 #define ASC_IERR_SET_PC_ADDR          0x0004
 #define ASC_IERR_START_STOP_CHIP      0x0008
-#define ASC_IERR_IRQ_NO               0x0010
-#define ASC_IERR_SET_IRQ_NO           0x0020
-#define ASC_IERR_CHIP_VERSION         0x0040
 #define ASC_IERR_SET_SCSI_ID          0x0080
-#define ASC_IERR_GET_PHY_ADDR         0x0100
 #define ASC_IERR_BAD_SIGNATURE        0x0200
 #define ASC_IERR_NO_BUS_TYPE          0x0400
-#define ASC_IERR_SCAM                 0x0800
-#define ASC_IERR_SET_SDTR             0x1000
-#define ASC_IERR_RW_LRAM              0x8000
 
-#define ASC_MAX_IRQ_NO  15
-#define ASC_MIN_IRQ_NO  10
 #define ASC_DEF_MAX_TOTAL_QNG   (0xF0)
 #define ASC_MIN_TAG_Q_PER_DVC   (0x04)
 #define ASC_MIN_FREE_Q        (0x02)
@@ -605,7 +595,6 @@
 	uchar max_total_qng;
 	uchar cur_total_qng;
 	uchar in_critical_cnt;
-	uchar irq_no;
 	uchar last_q_shortage;
 	ushort init_state;
 	uchar cur_dvc_qng[ASC_MAX_TID + 1];
@@ -1711,11 +1700,9 @@
 /*
  * Error code values are set in ADV_DVC_VAR 'err_code'.
  */
-#define ASC_IERR_WRITE_EEPROM       0x0001	/* write EEPROM error */
 #define ASC_IERR_MCODE_CHKSUM       0x0002	/* micro code check sum error */
 #define ASC_IERR_NO_CARRIER         0x0004	/* No more carrier memory. */
 #define ASC_IERR_START_STOP_CHIP    0x0008	/* start/stop chip failed */
-#define ASC_IERR_CHIP_VERSION       0x0040	/* wrong chip version */
 #define ASC_IERR_SET_SCSI_ID        0x0080	/* set SCSI ID failed */
 #define ASC_IERR_HVD_DEVICE         0x0100	/* HVD attached to LVD connector. */
 #define ASC_IERR_BAD_SIGNATURE      0x0200	/* signature not found */
@@ -1919,7 +1906,6 @@
 	uchar scsi_reset_wait;	/* delay in seconds after scsi bus reset */
 	uchar chip_no;		/* should be assigned by caller */
 	uchar max_host_qng;	/* maximum number of Q'ed command allowed */
-	uchar irq_no;		/* IRQ number */
 	ushort no_scam;		/* scam_tolerant of EEPROM */
 	struct asc_board *drv_ptr;	/* driver pointer to private structure */
 	uchar chip_scsi_id;	/* chip SCSI target ID */
@@ -2501,6 +2487,7 @@
 	struct device *dev;
 	int id;			/* Board Id */
 	uint flags;		/* Board flags */
+	unsigned int irq;
 	union {
 		ASC_DVC_VAR asc_dvc_var;	/* Narrow board */
 		ADV_DVC_VAR adv_dvc_var;	/* Wide board */
@@ -2573,7 +2560,7 @@
 	       s->host_busy, s->host_no, (unsigned)s->last_reset);
 
 	printk(" base 0x%lx, io_port 0x%lx, irq 0x%x,\n",
-	       (ulong)s->base, (ulong)s->io_port, s->irq);
+	       (ulong)s->base, (ulong)s->io_port, boardp->irq);
 
 	printk(" dma_channel %d, this_id %d, can_queue %d,\n",
 	       s->dma_channel, s->this_id, s->can_queue);
@@ -2651,7 +2638,7 @@
 	       (unsigned)h->init_state, (unsigned)h->no_scam,
 	       (unsigned)h->pci_fix_asyn_xfer);
 
-	printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
+	printk(" cfg 0x%lx\n", (ulong)h->cfg);
 }
 
 /*
@@ -2749,9 +2736,8 @@
 	       (ulong)h->isr_callback, (unsigned)h->sdtr_able,
 	       (unsigned)h->wdtr_able);
 
-	printk("  start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
-	       (unsigned)h->start_motor,
-	       (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
+	printk("  start_motor 0x%x, scsi_reset_wait 0x%x\n",
+	       (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
 
 	printk("  max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
 	       (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
@@ -2958,7 +2944,7 @@
 				ASC_VERSION, busname,
 				(ulong)shost->io_port,
 				(ulong)shost->io_port + ASC_IOADR_GAP - 1,
-				shost->irq, shost->dma_channel);
+				boardp->irq, shost->dma_channel);
 		} else {
 			if (asc_dvc_varp->bus_type & ASC_IS_VL) {
 				busname = "VL";
@@ -2981,7 +2967,7 @@
 				"AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
 				ASC_VERSION, busname, (ulong)shost->io_port,
 				(ulong)shost->io_port + ASC_IOADR_GAP - 1,
-				shost->irq);
+				boardp->irq);
 		}
 	} else {
 		/*
@@ -3002,7 +2988,7 @@
 		sprintf(info,
 			"AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
 			ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
-			(ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, shost->irq);
+			(ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, boardp->irq);
 	}
 	BUG_ON(strlen(info) >= ASC_INFO_SIZE);
 	ASC_DBG(1, "advansys_info: end\n");
@@ -11479,77 +11465,6 @@
 	return AscGetChipVerNo(iop_base);
 }
 
-static void __devinit AscToggleIRQAct(PortAddr iop_base)
-{
-	AscSetChipStatus(iop_base, CIW_IRQ_ACT);
-	AscSetChipStatus(iop_base, 0);
-	return;
-}
-
-static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
-{
-	ushort cfg_lsw;
-	uchar chip_irq;
-
-	if ((bus_type & ASC_IS_EISA) != 0) {
-		cfg_lsw = AscGetEisaChipCfg(iop_base);
-		chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
-		if ((chip_irq == 13) || (chip_irq > 15)) {
-			return (0);
-		}
-		return (chip_irq);
-	}
-	if ((bus_type & ASC_IS_VL) != 0) {
-		cfg_lsw = AscGetChipCfgLsw(iop_base);
-		chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
-		if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
-			return (0);
-		}
-		return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
-	}
-	cfg_lsw = AscGetChipCfgLsw(iop_base);
-	chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
-	if (chip_irq == 3)
-		chip_irq += (uchar)2;
-	return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
-}
-
-static uchar __devinit
-AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
-{
-	ushort cfg_lsw;
-
-	if ((bus_type & ASC_IS_VL) != 0) {
-		if (irq_no != 0) {
-			if ((irq_no < ASC_MIN_IRQ_NO)
-			    || (irq_no > ASC_MAX_IRQ_NO)) {
-				irq_no = 0;
-			} else {
-				irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
-			}
-		}
-		cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
-		cfg_lsw |= (ushort)0x0010;
-		AscSetChipCfgLsw(iop_base, cfg_lsw);
-		AscToggleIRQAct(iop_base);
-		cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
-		cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
-		AscSetChipCfgLsw(iop_base, cfg_lsw);
-		AscToggleIRQAct(iop_base);
-		return (AscGetChipIRQ(iop_base, bus_type));
-	}
-	if ((bus_type & (ASC_IS_ISA)) != 0) {
-		if (irq_no == 15)
-			irq_no -= (uchar)2;
-		irq_no -= (uchar)ASC_MIN_IRQ_NO;
-		cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
-		cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
-		AscSetChipCfgLsw(iop_base, cfg_lsw);
-		return (AscGetChipIRQ(iop_base, bus_type));
-	}
-	return (0);
-}
-
 #ifdef CONFIG_ISA
 static void __devinit AscEnableIsaDma(uchar dma_channel)
 {
@@ -12157,9 +12072,6 @@
 		eep_config->disc_enable = eep_config->use_cmd_qng;
 		warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
 	}
-	if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
-		asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
-	}
 	ASC_EEP_SET_CHIP_ID(eep_config,
 			    ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
 	asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
@@ -12276,12 +12188,6 @@
 	if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
 		warn_code |= ASC_WARN_AUTO_CONFIG;
 	}
-	if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
-		if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
-		    != asc_dvc->irq_no) {
-			asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
-		}
-	}
 #ifdef CONFIG_PCI
 	if (asc_dvc->bus_type & ASC_IS_PCI) {
 		cfg_msw &= 0xFFC0;
@@ -13879,49 +13785,19 @@
 	}
 }
 
-static struct Scsi_Host *__devinit
-advansys_board_found(int iop, struct device *dev, int bus_type)
+static int __devinit advansys_board_found(struct Scsi_Host *shost,
+					  unsigned int iop, int bus_type)
 {
-	struct Scsi_Host *shost;
-	struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
+	struct pci_dev *pdev;
 	asc_board_t *boardp;
 	ASC_DVC_VAR *asc_dvc_varp = NULL;
 	ADV_DVC_VAR *adv_dvc_varp = NULL;
-	int share_irq;
-	int warn_code, err_code;
-	int ret;
+	int share_irq, warn_code, ret;
 
-	/*
-	 * Register the adapter, get its configuration, and
-	 * initialize it.
-	 */
-	ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
-	shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
-	if (!shost)
-		return NULL;
-
-	/* Initialize private per board data */
 	boardp = ASC_BOARDP(shost);
-	memset(boardp, 0, sizeof(asc_board_t));
 	boardp->id = asc_board_count++;
 	spin_lock_init(&boardp->lock);
-	boardp->dev = dev;
-
-	/*
-	 * Handle both narrow and wide boards.
-	 *
-	 * If a Wide board was detected, set the board structure
-	 * wide board flag. Set-up the board structure based on
-	 * the board type.
-	 */
-#ifdef CONFIG_PCI
-	if (bus_type == ASC_IS_PCI &&
-	    (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
-	     pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
-	     pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
-		boardp->flags |= ASC_IS_WIDE_BOARD;
-	}
-#endif /* CONFIG_PCI */
+	pdev = (bus_type == ASC_IS_PCI) ? to_pci_dev(boardp->dev) : NULL;
 
 	if (ASC_NARROW_BOARD(boardp)) {
 		ASC_DBG(1, "advansys_board_found: narrow board\n");
@@ -13956,6 +13832,7 @@
 			    ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
 			     boardp->id, pci_resource_start(pdev, 1),
 			     boardp->asc_n_io_port);
+			ret = -ENODEV;
 			goto err_shost;
 		}
 		adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
@@ -13984,6 +13861,7 @@
 	if (!boardp->prtbuf) {
 		ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
 			   "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
+		ret = -ENOMEM;
 		goto err_unmap;
 	}
 #endif /* CONFIG_PROC_FS */
@@ -14010,7 +13888,6 @@
 #endif /* CONFIG_ISA */
 #ifdef CONFIG_PCI
 		case ASC_IS_PCI:
-			shost->irq = asc_dvc_varp->irq_no = pdev->irq;
 			shost->unchecked_isa_dma = FALSE;
 			share_irq = IRQF_SHARED;
 			break;
@@ -14031,23 +13908,22 @@
 		 * referenced only use the bit-wise AND operator "&".
 		 */
 		ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
-		err_code = AscInitGetConfig(boardp);
+		ret = AscInitGetConfig(boardp) ? -ENODEV : 0;
 	} else {
 #ifdef CONFIG_PCI
 		/*
 		 * For Wide boards set PCI information before calling
 		 * AdvInitGetConfig().
 		 */
-		shost->irq = adv_dvc_varp->irq_no = pdev->irq;
 		shost->unchecked_isa_dma = FALSE;
 		share_irq = IRQF_SHARED;
 		ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
 
-		err_code = AdvInitGetConfig(pdev, boardp);
+		ret = AdvInitGetConfig(pdev, boardp) ? -ENODEV : 0;
 #endif /* CONFIG_PCI */
 	}
 
-	if (err_code != 0)
+	if (ret)
 		goto err_free_proc;
 
 	/*
@@ -14091,17 +13967,9 @@
 		 * Modify board configuration.
 		 */
 		ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
-		err_code = AscInitSetConfig(pdev, boardp);
-		if (err_code)
+		ret = AscInitSetConfig(pdev, boardp) ? -ENODEV : 0;
+		if (ret)
 			goto err_free_proc;
-
-		/*
-		 * Finish initializing the 'Scsi_Host' structure.
-		 */
-		/* AscInitSetConfig() will set the IRQ for non-PCI boards. */
-		if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
-			shost->irq = asc_dvc_varp->irq_no;
-		}
 	} else {
 		ADVEEP_3550_CONFIG *ep_3550;
 		ADVEEP_38C0800_CONFIG *ep_38C0800;
@@ -14346,24 +14214,24 @@
 #endif /* CONFIG_ISA */
 
 	/* Register IRQ Number. */
-	ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
+	ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", boardp->irq);
 
-	ret = request_irq(shost->irq, advansys_interrupt, share_irq,
+	ret = request_irq(boardp->irq, advansys_interrupt, share_irq,
 			  DRV_NAME, shost);
 
 	if (ret) {
 		if (ret == -EBUSY) {
 			ASC_PRINT2
 			    ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
-			     boardp->id, shost->irq);
+			     boardp->id, boardp->irq);
 		} else if (ret == -EINVAL) {
 			ASC_PRINT2
 			    ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
-			     boardp->id, shost->irq);
+			     boardp->id, boardp->irq);
 		} else {
 			ASC_PRINT3
 			    ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
-			     boardp->id, shost->irq, ret);
+			     boardp->id, boardp->irq, ret);
 		}
 		goto err_free_dma;
 	}
@@ -14374,33 +14242,35 @@
 	if (ASC_NARROW_BOARD(boardp)) {
 		ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
 		warn_code = AscInitAsc1000Driver(asc_dvc_varp);
-		err_code = asc_dvc_varp->err_code;
 
-		if (warn_code || err_code) {
-			ASC_PRINT4
-			    ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
-			     boardp->id,
-			     asc_dvc_varp->init_state, warn_code, err_code);
+		if (warn_code || asc_dvc_varp->err_code) {
+			ASC_PRINT4("advansys_board_found: board %d error: "
+				   "init_state 0x%x, warn 0x%x, error 0x%x\n",
+				   boardp->id, asc_dvc_varp->init_state,
+				   warn_code, asc_dvc_varp->err_code);
+			if (asc_dvc_varp->err_code)
+				ret = -ENODEV;
 		}
 	} else {
-		err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
+		if (advansys_wide_init_chip(boardp, adv_dvc_varp))
+			ret = -ENODEV;
 	}
 
-	if (err_code != 0)
+	if (ret)
 		goto err_free_wide_mem;
 
 	ASC_DBG_PRT_SCSI_HOST(2, shost);
 
-	ret = scsi_add_host(shost, dev);
+	ret = scsi_add_host(shost, boardp->dev);
 	if (ret)
 		goto err_free_wide_mem;
 
 	scsi_scan_host(shost);
-	return shost;
+	return 0;
 
  err_free_wide_mem:
 	advansys_wide_free_mem(boardp);
-	free_irq(shost->irq, shost);
+	free_irq(boardp->irq, shost);
  err_free_dma:
 	if (shost->dma_channel != NO_ISA_DMA)
 		free_dma(shost->dma_channel);
@@ -14410,8 +14280,7 @@
 	if (boardp->ioremap_addr)
 		iounmap(boardp->ioremap_addr);
  err_shost:
-	scsi_host_put(shost);
-	return NULL;
+	return ret;
 }
 
 /*
@@ -14426,7 +14295,7 @@
 	ASC_DBG(1, "advansys_release: begin\n");
 	scsi_remove_host(shost);
 	boardp = ASC_BOARDP(shost);
-	free_irq(shost->irq, shost);
+	free_irq(boardp->irq, shost);
 	if (shost->dma_channel != NO_ISA_DMA) {
 		ASC_DBG(1, "advansys_release: free_dma()\n");
 		free_dma(shost->dma_channel);
@@ -14448,10 +14317,28 @@
 	0x0210, 0x0230, 0x0250, 0x0330
 };
 
+/*
+ * The ISA IRQ number is found in bits 2 and 3 of the CfgLsw.  It decodes as:
+ * 00: 10
+ * 01: 11
+ * 10: 12
+ * 11: 15
+ */
+static unsigned int __devinit advansys_isa_irq_no(PortAddr iop_base)
+{
+	unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
+	unsigned int chip_irq = ((cfg_lsw >> 2) & 0x03) + 10;
+	if (chip_irq == 13)
+		chip_irq = 15;
+	return chip_irq;
+}
+
 static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
 {
+	int err = -ENODEV;
 	PortAddr iop_base = _asc_def_iop_base[id];
 	struct Scsi_Host *shost;
+	struct asc_board *board;
 
 	if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
 		ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
@@ -14460,20 +14347,31 @@
 	}
 	ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
 	if (!AscFindSignature(iop_base))
-		goto nodev;
+		goto release_region;
 	if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
-		goto nodev;
+		goto release_region;
 
-	shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
+	err = -ENOMEM;
+	shost = scsi_host_alloc(&advansys_template, sizeof(*board));
 	if (!shost)
-		goto nodev;
+		goto release_region;
+
+	board = ASC_BOARDP(shost);
+	board->irq = advansys_isa_irq_no(iop_base);
+	board->dev = dev;
+
+	err = advansys_board_found(shost, iop_base, ASC_IS_ISA);
+	if (err)
+		goto free_host;
 
 	dev_set_drvdata(dev, shost);
 	return 0;
 
- nodev:
+ free_host:
+	scsi_host_put(shost);
+ release_region:
 	release_region(iop_base, ASC_IOADR_GAP);
-	return -ENODEV;
+	return err;
 }
 
 static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
@@ -14493,10 +14391,32 @@
 	},
 };
 
+/*
+ * The VLB IRQ number is found in bits 2 to 4 of the CfgLsw.  It decodes as:
+ * 000: invalid
+ * 001: 10
+ * 010: 11
+ * 011: 12
+ * 100: invalid
+ * 101: 14
+ * 110: 15
+ * 111: invalid
+ */
+static unsigned int __devinit advansys_vlb_irq_no(PortAddr iop_base)
+{
+	unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
+	unsigned int chip_irq = ((cfg_lsw >> 2) & 0x07) + 9;
+	if ((chip_irq < 10) || (chip_irq == 13) || (chip_irq > 15))
+		return 0;
+	return chip_irq;
+}
+
 static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
 {
+	int err = -ENODEV;
 	PortAddr iop_base = _asc_def_iop_base[id];
 	struct Scsi_Host *shost;
+	struct asc_board *board;
 
 	if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
 		ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
@@ -14505,23 +14425,34 @@
 	}
 	ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
 	if (!AscFindSignature(iop_base))
-		goto nodev;
+		goto release_region;
 	/*
 	 * I don't think this condition can actually happen, but the old
 	 * driver did it, and the chances of finding a VLB setup in 2007
 	 * to do testing with is slight to none.
 	 */
 	if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
-		goto nodev;
+		goto release_region;
 
-	shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
+	err = -ENOMEM;
+	shost = scsi_host_alloc(&advansys_template, sizeof(*board));
 	if (!shost)
-		goto nodev;
+		goto release_region;
+
+	board = ASC_BOARDP(shost);
+	board->irq = advansys_vlb_irq_no(iop_base);
+	board->dev = dev;
+
+	err = advansys_board_found(shost, iop_base, ASC_IS_VL);
+	if (err)
+		goto free_host;
 
 	dev_set_drvdata(dev, shost);
 	return 0;
 
- nodev:
+ free_host:
+	scsi_host_put(shost);
+ release_region:
 	release_region(iop_base, ASC_IOADR_GAP);
 	return -ENODEV;
 }
@@ -14551,9 +14482,29 @@
 	struct Scsi_Host *host[2];
 };
 
+/*
+ * The EISA IRQ number is found in bits 8 to 10 of the CfgLsw.  It decodes as:
+ * 000: 10
+ * 001: 11
+ * 010: 12
+ * 011: invalid
+ * 100: 14
+ * 101: 15
+ * 110: invalid
+ * 111: invalid
+ */
+static unsigned int __devinit advansys_eisa_irq_no(struct eisa_device *edev)
+{
+	unsigned short cfg_lsw = inw(edev->base_addr + 0xc86);
+	unsigned int chip_irq = ((cfg_lsw >> 8) & 0x07) + 10;
+	if ((chip_irq == 13) || (chip_irq > 15))
+		return 0;
+	return chip_irq;
+}
+
 static int __devinit advansys_eisa_probe(struct device *dev)
 {
-	int i, ioport;
+	int i, ioport, irq = 0;
 	int err;
 	struct eisa_device *edev = to_eisa_device(dev);
 	struct eisa_scsi_data *data;
@@ -14566,6 +14517,8 @@
 
 	err = -ENODEV;
 	for (i = 0; i < 2; i++, ioport += 0x20) {
+		struct asc_board *board;
+		struct Scsi_Host *shost;
 		if (!request_region(ioport, ASC_IOADR_GAP, DRV_NAME)) {
 			printk(KERN_WARNING "Region %x-%x busy\n", ioport,
 			       ioport + ASC_IOADR_GAP - 1);
@@ -14584,20 +14537,40 @@
 		 * test with.
 		 */
 		inw(ioport + 4);
-		data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
-		if (data->host[i]) {
-			err = 0;
-		} else {
-			release_region(ioport, ASC_IOADR_GAP);
+
+		if (!irq)
+			irq = advansys_eisa_irq_no(edev);
+
+		err = -ENOMEM;
+		shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+		if (!shost)
+			goto release_region;
+
+		board = ASC_BOARDP(shost);
+		board->irq = irq;
+		board->dev = dev;
+
+		err = advansys_board_found(shost, ioport, ASC_IS_EISA);
+		if (!err) {
+			data->host[i] = shost;
+			continue;
 		}
+
+		scsi_host_put(shost);
+ release_region:
+		release_region(ioport, ASC_IOADR_GAP);
+		break;
 	}
 
-	if (err) {
-		kfree(data);
-	} else {
-		dev_set_drvdata(dev, data);
-	}
+	if (err)
+		goto free_data;
+	dev_set_drvdata(dev, data);
+	return 0;
 
+ free_data:
+	kfree(data->host[0]);
+	kfree(data->host[1]);
+	kfree(data);
  fail:
 	return err;
 }
@@ -14667,6 +14640,7 @@
 {
 	int err, ioport;
 	struct Scsi_Host *shost;
+	struct asc_board *board;
 
 	err = pci_enable_device(pdev);
 	if (err)
@@ -14677,20 +14651,37 @@
 	pci_set_master(pdev);
 	advansys_set_latency(pdev);
 
+	err = -ENODEV;
 	if (pci_resource_len(pdev, 0) == 0)
-		goto nodev;
+		goto release_region;
 
 	ioport = pci_resource_start(pdev, 0);
-	shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
 
+	err = -ENOMEM;
+	shost = scsi_host_alloc(&advansys_template, sizeof(*board));
 	if (!shost)
-		goto nodev;
+		goto release_region;
+
+	board = ASC_BOARDP(shost);
+	board->irq = pdev->irq;
+	board->dev = &pdev->dev;
+
+	if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
+	    pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
+	    pdev->device == PCI_DEVICE_ID_38C1600_REV1) {
+		board->flags |= ASC_IS_WIDE_BOARD;
+	}
+
+	err = advansys_board_found(shost, ioport, ASC_IS_PCI);
+	if (err)
+		goto free_host;
 
 	pci_set_drvdata(pdev, shost);
 	return 0;
 
- nodev:
-	err = -ENODEV;
+ free_host:
+	scsi_host_put(shost);
+ release_region:
 	pci_release_regions(pdev);
  disable_device:
 	pci_disable_device(pdev);