summaryrefslogtreecommitdiff
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);