summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/advansys.c387
1 files changed, 189 insertions, 198 deletions
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index a5bb4e416bea..e2bd4c9e7c22 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -461,23 +461,13 @@ typedef struct asc_risc_sg_list_q {
 /*
  * 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 @@ typedef struct asc_dvc_var {
 	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 @@ typedef struct adveep_38C1600_config {
 /*
  * 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 @@ typedef struct adv_dvc_var {
 	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 @@ typedef struct asc_board {
 	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 @@ static void asc_prt_scsi_host(struct Scsi_Host *s)
 	       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 @@ static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
 	       (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 @@ static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
 	       (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 @@ static const char *advansys_info(struct Scsi_Host *shost)
 				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 @@ static const char *advansys_info(struct Scsi_Host *shost)
 				"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 @@ static const char *advansys_info(struct Scsi_Host *shost)
 		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 @@ AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
 	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 @@ static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
 		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 @@ static int __devinit AscInitSetConfig(struct pci_dev *pdev, asc_board_t *boardp)
 	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 void advansys_wide_free_mem(asc_board_t *boardp)
 	}
 }
 
-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;
-
-	/*
-	 * 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;
+	int share_irq, warn_code, ret;
 
-	/* 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(int iop, struct device *dev, int bus_type)
 			    ("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 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
 	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 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
 #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 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
 		 * 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 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
 		 * 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 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
 #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 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
 	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 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
 	if (boardp->ioremap_addr)
 		iounmap(boardp->ioremap_addr);
  err_shost:
-	scsi_host_put(shost);
-	return NULL;
+	return ret;
 }
 
 /*
@@ -14426,7 +14295,7 @@ static int advansys_release(struct Scsi_Host *shost)
 	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 @@ static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
 	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 @@ static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
 	}
 	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 @@ static struct isa_driver advansys_isa_driver = {
 	},
 };
 
+/*
+ * 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 @@ static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
 	}
 	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 eisa_scsi_data {
 	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 @@ static int __devinit advansys_eisa_probe(struct device *dev)
 
 	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 @@ static int __devinit advansys_eisa_probe(struct device *dev)
 		 * 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;
 		}
-	}
 
-	if (err) {
-		kfree(data);
-	} else {
-		dev_set_drvdata(dev, data);
+		scsi_host_put(shost);
+ release_region:
+		release_region(ioport, ASC_IOADR_GAP);
+		break;
 	}
 
+	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 @@ advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	int err, ioport;
 	struct Scsi_Host *shost;
+	struct asc_board *board;
 
 	err = pci_enable_device(pdev);
 	if (err)
@@ -14677,20 +14651,37 @@ advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	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);