109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21d084d20SOndrej Zary /* 31d084d20SOndrej Zary * Driver for Adaptec AHA-1542 SCSI host adapters 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1992 Tommy Thorn 61da177e4SLinus Torvalds * Copyright (C) 1993, 1994, 1995 Eric Youngdale 71d084d20SOndrej Zary * Copyright (C) 2015 Ondrej Zary 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #include <linux/module.h> 111da177e4SLinus Torvalds #include <linux/interrupt.h> 121da177e4SLinus Torvalds #include <linux/kernel.h> 131da177e4SLinus Torvalds #include <linux/types.h> 141da177e4SLinus Torvalds #include <linux/string.h> 151da177e4SLinus Torvalds #include <linux/delay.h> 161da177e4SLinus Torvalds #include <linux/init.h> 171da177e4SLinus Torvalds #include <linux/spinlock.h> 18643a7c43SOndrej Zary #include <linux/isa.h> 19643a7c43SOndrej Zary #include <linux/pnp.h> 205a0e3ad6STejun Heo #include <linux/slab.h> 21954a9fd7SOndrej Zary #include <linux/io.h> 221da177e4SLinus Torvalds #include <asm/dma.h> 23954a9fd7SOndrej Zary #include <scsi/scsi_cmnd.h> 24954a9fd7SOndrej Zary #include <scsi/scsi_device.h> 251da177e4SLinus Torvalds #include <scsi/scsi_host.h> 261da177e4SLinus Torvalds #include "aha1542.h" 271da177e4SLinus Torvalds 28f71429abSOndrej Zary #define MAXBOARDS 4 291da177e4SLinus Torvalds 30f71429abSOndrej Zary static bool isapnp = 1; 311da177e4SLinus Torvalds module_param(isapnp, bool, 0); 32f71429abSOndrej Zary MODULE_PARM_DESC(isapnp, "enable PnP support (default=1)"); 33f71429abSOndrej Zary 34f71429abSOndrej Zary static int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 }; 3588f06b76SDavid Howells module_param_hw_array(io, int, ioport, NULL, 0); 36f71429abSOndrej Zary MODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)"); 37f71429abSOndrej Zary 38f71429abSOndrej Zary /* time AHA spends on the AT-bus during data transfer */ 39f71429abSOndrej Zary static int bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */ 40f71429abSOndrej Zary module_param_array(bus_on, int, NULL, 0); 41f71429abSOndrej Zary MODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])"); 42f71429abSOndrej Zary 43f71429abSOndrej Zary /* time AHA spends off the bus (not to monopolize it) during data transfer */ 44f71429abSOndrej Zary static int bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */ 45f71429abSOndrej Zary module_param_array(bus_off, int, NULL, 0); 46f71429abSOndrej Zary MODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])"); 47f71429abSOndrej Zary 48f71429abSOndrej Zary /* default is jumper selected (J1 on 1542A), factory default = 5 MB/s */ 49f71429abSOndrej Zary static int dma_speed[MAXBOARDS] = { -1, -1, -1, -1 }; 50f71429abSOndrej Zary module_param_array(dma_speed, int, NULL, 0); 51f71429abSOndrej Zary MODULE_PARM_DESC(dma_speed, "DMA speed [MB/s] (5,6,7,8,10, default=-1 [by jumper])"); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds #define BIOS_TRANSLATION_6432 1 /* Default case these days */ 541da177e4SLinus Torvalds #define BIOS_TRANSLATION_25563 2 /* Big disk case */ 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds struct aha1542_hostdata { 571da177e4SLinus Torvalds /* This will effectively start both of them at the first mailbox */ 581da177e4SLinus Torvalds int bios_translation; /* Mapping bios uses - for compatibility */ 591da177e4SLinus Torvalds int aha1542_last_mbi_used; 601da177e4SLinus Torvalds int aha1542_last_mbo_used; 6155b28f9fSOndrej Zary struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES]; 621794ef2bSChristoph Hellwig struct mailbox *mb; 631794ef2bSChristoph Hellwig dma_addr_t mb_handle; 641794ef2bSChristoph Hellwig struct ccb *ccb; 651794ef2bSChristoph Hellwig dma_addr_t ccb_handle; 661794ef2bSChristoph Hellwig }; 671794ef2bSChristoph Hellwig 681794ef2bSChristoph Hellwig struct aha1542_cmd { 691794ef2bSChristoph Hellwig struct chain *chain; 701794ef2bSChristoph Hellwig dma_addr_t chain_handle; 711da177e4SLinus Torvalds }; 721da177e4SLinus Torvalds 73f1bbef63SOndrej Zary static inline void aha1542_intr_reset(u16 base) 74f1bbef63SOndrej Zary { 75f1bbef63SOndrej Zary outb(IRST, CONTROL(base)); 76f1bbef63SOndrej Zary } 771da177e4SLinus Torvalds 782093bfa1SOndrej Zary static inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout) 792093bfa1SOndrej Zary { 802093bfa1SOndrej Zary bool delayed = true; 812093bfa1SOndrej Zary 822093bfa1SOndrej Zary if (timeout == 0) { 832093bfa1SOndrej Zary timeout = 3000000; 842093bfa1SOndrej Zary delayed = false; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 872093bfa1SOndrej Zary while (1) { 882093bfa1SOndrej Zary u8 bits = inb(port) & mask; 892093bfa1SOndrej Zary if ((bits & allof) == allof && ((bits & noneof) == 0)) 902093bfa1SOndrej Zary break; 912093bfa1SOndrej Zary if (delayed) 922093bfa1SOndrej Zary mdelay(1); 932093bfa1SOndrej Zary if (--timeout == 0) 942093bfa1SOndrej Zary return false; 952093bfa1SOndrej Zary } 962093bfa1SOndrej Zary 972093bfa1SOndrej Zary return true; 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 100cad2fc72SOndrej Zary static int aha1542_outb(unsigned int base, u8 val) 1011da177e4SLinus Torvalds { 1022906b3ceSOndrej Zary if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) 1030c2b6481SOndrej Zary return 1; 104cad2fc72SOndrej Zary outb(val, DATA(base)); 105eef77801SOndrej Zary 1061da177e4SLinus Torvalds return 0; 1071da177e4SLinus Torvalds } 1080c2b6481SOndrej Zary 109cad2fc72SOndrej Zary static int aha1542_out(unsigned int base, u8 *buf, int len) 1100c2b6481SOndrej Zary { 1111da177e4SLinus Torvalds while (len--) { 1121b0224b0SOndrej Zary if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) 1131da177e4SLinus Torvalds return 1; 114cad2fc72SOndrej Zary outb(*buf++, DATA(base)); 1150c2b6481SOndrej Zary } 11623e6940aSOndrej Zary if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0)) 11723e6940aSOndrej Zary return 1; 1180c2b6481SOndrej Zary 1190c2b6481SOndrej Zary return 0; 1200c2b6481SOndrej Zary } 1211da177e4SLinus Torvalds 122*e4da5febSSergey Shtylyov /* 123*e4da5febSSergey Shtylyov * Only used at boot time, so we do not need to worry about latency as much 124*e4da5febSSergey Shtylyov * here 125*e4da5febSSergey Shtylyov */ 1261da177e4SLinus Torvalds 127cad2fc72SOndrej Zary static int aha1542_in(unsigned int base, u8 *buf, int len, int timeout) 1281da177e4SLinus Torvalds { 1291da177e4SLinus Torvalds while (len--) { 1301b0224b0SOndrej Zary if (!wait_mask(STATUS(base), DF, DF, 0, timeout)) 1311da177e4SLinus Torvalds return 1; 132cad2fc72SOndrej Zary *buf++ = inb(DATA(base)); 133a13b3722SOndrej Zary } 134a13b3722SOndrej Zary return 0; 135a13b3722SOndrej Zary } 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds static int makecode(unsigned hosterr, unsigned scsierr) 1381da177e4SLinus Torvalds { 1391da177e4SLinus Torvalds switch (hosterr) { 1401da177e4SLinus Torvalds case 0x0: 1411da177e4SLinus Torvalds case 0xa: /* Linked command complete without error and linked normally */ 1421da177e4SLinus Torvalds case 0xb: /* Linked command complete without error, interrupt generated */ 1431da177e4SLinus Torvalds hosterr = 0; 1441da177e4SLinus Torvalds break; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds case 0x11: /* Selection time out-The initiator selection or target 147*e4da5febSSergey Shtylyov * reselection was not complete within the SCSI Time out period 148*e4da5febSSergey Shtylyov */ 1491da177e4SLinus Torvalds hosterr = DID_TIME_OUT; 1501da177e4SLinus Torvalds break; 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds case 0x12: /* Data overrun/underrun-The target attempted to transfer more data 153*e4da5febSSergey Shtylyov * than was allocated by the Data Length field or the sum of the 154*e4da5febSSergey Shtylyov * Scatter / Gather Data Length fields. 155*e4da5febSSergey Shtylyov */ 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was 160*e4da5febSSergey Shtylyov * invalid. This usually indicates a software failure. 161*e4da5febSSergey Shtylyov */ 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. 164*e4da5febSSergey Shtylyov * This usually indicates a software failure. 165*e4da5febSSergey Shtylyov */ 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set 168*e4da5febSSergey Shtylyov * of linked CCB's does not specify the same logical unit number as 169*e4da5febSSergey Shtylyov * the first. 170*e4da5febSSergey Shtylyov */ 1711da177e4SLinus Torvalds case 0x18: /* Invalid Target Direction received from Host-The direction of a 172*e4da5febSSergey Shtylyov * Target Mode CCB was invalid. 173*e4da5febSSergey Shtylyov */ 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was 176*e4da5febSSergey Shtylyov * received to service data transfer between the same target LUN 177*e4da5febSSergey Shtylyov * and initiator SCSI ID in the same direction. 178*e4da5febSSergey Shtylyov */ 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero 181*e4da5febSSergey Shtylyov * length segment or invalid segment list boundaries was received. 182*e4da5febSSergey Shtylyov * A CCB parameter was invalid. 183*e4da5febSSergey Shtylyov */ 184fde1fb8aSOndrej Zary #ifdef DEBUG 185fde1fb8aSOndrej Zary printk("Aha1542: %x %x\n", hosterr, scsierr); 186fde1fb8aSOndrej Zary #endif 1871da177e4SLinus Torvalds hosterr = DID_ERROR; /* Couldn't find any better */ 1881da177e4SLinus Torvalds break; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus 191*e4da5febSSergey Shtylyov * phase sequence was requested by the target. The host adapter 192*e4da5febSSergey Shtylyov * will generate a SCSI Reset Condition, notifying the host with 193*e4da5febSSergey Shtylyov * a SCRD interrupt 194*e4da5febSSergey Shtylyov */ 1951da177e4SLinus Torvalds hosterr = DID_RESET; 1961da177e4SLinus Torvalds break; 1971da177e4SLinus Torvalds default: 1981da177e4SLinus Torvalds printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr); 1991da177e4SLinus Torvalds break; 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds return scsierr | (hosterr << 16); 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds 20468ea9de3SOndrej Zary static int aha1542_test_port(struct Scsi_Host *sh) 2051da177e4SLinus Torvalds { 206cb5b570cSOndrej Zary u8 inquiry_result[4]; 207cad2fc72SOndrej Zary int i; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds /* Quick and dirty test for presence of the card. */ 21068ea9de3SOndrej Zary if (inb(STATUS(sh->io_port)) == 0xff) 2111da177e4SLinus Torvalds return 0; 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */ 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds /* In case some other card was probing here, reset interrupts */ 21668ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ 2171da177e4SLinus Torvalds 21868ea9de3SOndrej Zary outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port)); 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds mdelay(20); /* Wait a little bit for things to settle down. */ 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds /* Expect INIT and IDLE, any of the others are bad */ 22368ea9de3SOndrej Zary if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) 224a13b3722SOndrej Zary return 0; 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /* Shouldn't have generated any interrupts during reset */ 22768ea9de3SOndrej Zary if (inb(INTRFLAGS(sh->io_port)) & INTRMASK) 228a13b3722SOndrej Zary return 0; 2291da177e4SLinus Torvalds 230*e4da5febSSergey Shtylyov /* 231*e4da5febSSergey Shtylyov * Perform a host adapter inquiry instead so we do not need to set 232*e4da5febSSergey Shtylyov * up the mailboxes ahead of time 233*e4da5febSSergey Shtylyov */ 2341da177e4SLinus Torvalds 23568ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_INQUIRY); 2361da177e4SLinus Torvalds 237cad2fc72SOndrej Zary for (i = 0; i < 4; i++) { 23868ea9de3SOndrej Zary if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0)) 239a13b3722SOndrej Zary return 0; 24068ea9de3SOndrej Zary inquiry_result[i] = inb(DATA(sh->io_port)); 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds /* Reading port should reset DF */ 24468ea9de3SOndrej Zary if (inb(STATUS(sh->io_port)) & DF) 245a13b3722SOndrej Zary return 0; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds /* When HACC, command is completed, and we're though testing */ 24868ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0)) 249a13b3722SOndrej Zary return 0; 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds /* Clear interrupts */ 25268ea9de3SOndrej Zary outb(IRST, CONTROL(sh->io_port)); 2531da177e4SLinus Torvalds 254bdebe224SOndrej Zary return 1; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571794ef2bSChristoph Hellwig static void aha1542_free_cmd(struct scsi_cmnd *cmd) 2581794ef2bSChristoph Hellwig { 2591794ef2bSChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 2601794ef2bSChristoph Hellwig struct device *dev = cmd->device->host->dma_dev; 2611794ef2bSChristoph Hellwig size_t len = scsi_sg_count(cmd) * sizeof(struct chain); 2621794ef2bSChristoph Hellwig 2631794ef2bSChristoph Hellwig if (acmd->chain) { 2641794ef2bSChristoph Hellwig dma_unmap_single(dev, acmd->chain_handle, len, DMA_TO_DEVICE); 2651794ef2bSChristoph Hellwig kfree(acmd->chain); 2661794ef2bSChristoph Hellwig } 2671794ef2bSChristoph Hellwig 2681794ef2bSChristoph Hellwig acmd->chain = NULL; 2691794ef2bSChristoph Hellwig scsi_dma_unmap(cmd); 2701794ef2bSChristoph Hellwig } 2711794ef2bSChristoph Hellwig 2721b0224b0SOndrej Zary static irqreturn_t aha1542_interrupt(int irq, void *dev_id) 2731da177e4SLinus Torvalds { 2741b0224b0SOndrej Zary struct Scsi_Host *sh = dev_id; 275c2532f68SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 27655b28f9fSOndrej Zary void (*my_done)(struct scsi_cmnd *) = NULL; 2771da177e4SLinus Torvalds int errstatus, mbi, mbo, mbistatus; 2781da177e4SLinus Torvalds int number_serviced; 2791da177e4SLinus Torvalds unsigned long flags; 28055b28f9fSOndrej Zary struct scsi_cmnd *tmp_cmd; 2811da177e4SLinus Torvalds int flag; 282e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 283e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds #ifdef DEBUG 2861da177e4SLinus Torvalds { 287c2532f68SOndrej Zary flag = inb(INTRFLAGS(sh->io_port)); 2882906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: "); 2891da177e4SLinus Torvalds if (!(flag & ANYINTR)) 2901da177e4SLinus Torvalds printk("no interrupt?"); 2911da177e4SLinus Torvalds if (flag & MBIF) 2921da177e4SLinus Torvalds printk("MBIF "); 2931da177e4SLinus Torvalds if (flag & MBOA) 2941da177e4SLinus Torvalds printk("MBOF "); 2951da177e4SLinus Torvalds if (flag & HACC) 2961da177e4SLinus Torvalds printk("HACC "); 2971da177e4SLinus Torvalds if (flag & SCRD) 2981da177e4SLinus Torvalds printk("SCRD "); 299c2532f68SOndrej Zary printk("status %02x\n", inb(STATUS(sh->io_port))); 3001da177e4SLinus Torvalds }; 3011da177e4SLinus Torvalds #endif 3021da177e4SLinus Torvalds number_serviced = 0; 3031da177e4SLinus Torvalds 3041b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 3051b0224b0SOndrej Zary while (1) { 306c2532f68SOndrej Zary flag = inb(INTRFLAGS(sh->io_port)); 3071da177e4SLinus Torvalds 308*e4da5febSSergey Shtylyov /* 309*e4da5febSSergey Shtylyov * Check for unusual interrupts. If any of these happen, we should 310*e4da5febSSergey Shtylyov * probably do something special, but for now just printing a message 311*e4da5febSSergey Shtylyov * is sufficient. A SCSI reset detected is something that we really 312*e4da5febSSergey Shtylyov * need to deal with in some way. 313*e4da5febSSergey Shtylyov */ 3141da177e4SLinus Torvalds if (flag & ~MBIF) { 3151da177e4SLinus Torvalds if (flag & MBOA) 3161da177e4SLinus Torvalds printk("MBOF "); 3171da177e4SLinus Torvalds if (flag & HACC) 3181da177e4SLinus Torvalds printk("HACC "); 319dfd7c991SOndrej Zary if (flag & SCRD) 3201da177e4SLinus Torvalds printk("SCRD "); 3211da177e4SLinus Torvalds } 322c2532f68SOndrej Zary aha1542_intr_reset(sh->io_port); 3231da177e4SLinus Torvalds 324e98878f7SOndrej Zary mbi = aha1542->aha1542_last_mbi_used + 1; 3251da177e4SLinus Torvalds if (mbi >= 2 * AHA1542_MAILBOXES) 3261da177e4SLinus Torvalds mbi = AHA1542_MAILBOXES; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds do { 3291da177e4SLinus Torvalds if (mb[mbi].status != 0) 3301da177e4SLinus Torvalds break; 3311da177e4SLinus Torvalds mbi++; 3321da177e4SLinus Torvalds if (mbi >= 2 * AHA1542_MAILBOXES) 3331da177e4SLinus Torvalds mbi = AHA1542_MAILBOXES; 334e98878f7SOndrej Zary } while (mbi != aha1542->aha1542_last_mbi_used); 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds if (mb[mbi].status == 0) { 3371b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 3381da177e4SLinus Torvalds /* Hmm, no mail. Must have read it the last time around */ 339dfd7c991SOndrej Zary if (!number_serviced) 3402906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n"); 3411b0224b0SOndrej Zary return IRQ_HANDLED; 3421da177e4SLinus Torvalds }; 3431da177e4SLinus Torvalds 344492ca4daSJames Bottomley mbo = (scsi2int(mb[mbi].ccbptr) - (unsigned long)aha1542->ccb_handle) / sizeof(struct ccb); 3451da177e4SLinus Torvalds mbistatus = mb[mbi].status; 3461da177e4SLinus Torvalds mb[mbi].status = 0; 347e98878f7SOndrej Zary aha1542->aha1542_last_mbi_used = mbi; 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds #ifdef DEBUG 3501da177e4SLinus Torvalds if (ccb[mbo].tarstat | ccb[mbo].hastat) 3512906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n", 3521da177e4SLinus Torvalds ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status); 3531da177e4SLinus Torvalds #endif 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds if (mbistatus == 3) 3561da177e4SLinus Torvalds continue; /* Aborted command not found */ 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds #ifdef DEBUG 3592906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi); 3601da177e4SLinus Torvalds #endif 3611da177e4SLinus Torvalds 36255b28f9fSOndrej Zary tmp_cmd = aha1542->int_cmds[mbo]; 3631da177e4SLinus Torvalds 36455b28f9fSOndrej Zary if (!tmp_cmd || !tmp_cmd->scsi_done) { 3651b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 3662906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n"); 3672906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat, 3681da177e4SLinus Torvalds ccb[mbo].hastat, ccb[mbo].idlun, mbo); 3691b0224b0SOndrej Zary return IRQ_HANDLED; 3701da177e4SLinus Torvalds } 37155b28f9fSOndrej Zary my_done = tmp_cmd->scsi_done; 3721794ef2bSChristoph Hellwig aha1542_free_cmd(tmp_cmd); 373*e4da5febSSergey Shtylyov /* 374*e4da5febSSergey Shtylyov * Fetch the sense data, and tuck it away, in the required slot. The 375*e4da5febSSergey Shtylyov * Adaptec automatically fetches it, and there is no guarantee that 376*e4da5febSSergey Shtylyov * we will still have it in the cdb when we come back 377*e4da5febSSergey Shtylyov */ 3781da177e4SLinus Torvalds if (ccb[mbo].tarstat == 2) 37955b28f9fSOndrej Zary memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], 380b80ca4f7SFUJITA Tomonori SCSI_SENSE_BUFFERSIZE); 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds /* is there mail :-) */ 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds /* more error checking left out here */ 3861da177e4SLinus Torvalds if (mbistatus != 1) 3871da177e4SLinus Torvalds /* This is surely wrong, but I don't know what's right */ 3881da177e4SLinus Torvalds errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); 3891da177e4SLinus Torvalds else 3901da177e4SLinus Torvalds errstatus = 0; 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds #ifdef DEBUG 3931da177e4SLinus Torvalds if (errstatus) 3942906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus, 3951da177e4SLinus Torvalds ccb[mbo].hastat, ccb[mbo].tarstat); 3966ddc8cf4SOndrej Zary if (ccb[mbo].tarstat == 2) 3976ddc8cf4SOndrej Zary print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12); 398fde1fb8aSOndrej Zary if (errstatus) 399fde1fb8aSOndrej Zary printk("aha1542_intr_handle: returning %6x\n", errstatus); 400fde1fb8aSOndrej Zary #endif 40155b28f9fSOndrej Zary tmp_cmd->result = errstatus; 40255b28f9fSOndrej Zary aha1542->int_cmds[mbo] = NULL; /* This effectively frees up the mailbox slot, as 403*e4da5febSSergey Shtylyov * far as queuecommand is concerned 404*e4da5febSSergey Shtylyov */ 40555b28f9fSOndrej Zary my_done(tmp_cmd); 4061da177e4SLinus Torvalds number_serviced++; 4071da177e4SLinus Torvalds }; 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds 4101b0224b0SOndrej Zary static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) 41109a44833SOndrej Zary { 4121794ef2bSChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 4132906b3ceSOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 414cb5b570cSOndrej Zary u8 direction; 41555b28f9fSOndrej Zary u8 target = cmd->device->id; 41655b28f9fSOndrej Zary u8 lun = cmd->device->lun; 4171da177e4SLinus Torvalds unsigned long flags; 41855b28f9fSOndrej Zary int bufflen = scsi_bufflen(cmd); 4198c08a621SOndrej Zary int mbo, sg_count; 420e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 421e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 4221da177e4SLinus Torvalds 42355b28f9fSOndrej Zary if (*cmd->cmnd == REQUEST_SENSE) { 4241da177e4SLinus Torvalds /* Don't do the command - we have the sense data already */ 42555b28f9fSOndrej Zary cmd->result = 0; 4261b0224b0SOndrej Zary cmd->scsi_done(cmd); 4271da177e4SLinus Torvalds return 0; 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds #ifdef DEBUG 430764a0c7eSOndrej Zary { 431764a0c7eSOndrej Zary int i = -1; 43255b28f9fSOndrej Zary if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10) 43355b28f9fSOndrej Zary i = xscsi2int(cmd->cmnd + 2); 43455b28f9fSOndrej Zary else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6) 43555b28f9fSOndrej Zary i = scsi2int(cmd->cmnd + 2); 436764a0c7eSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d", 437764a0c7eSOndrej Zary target, *cmd->cmnd, i, bufflen); 4386ddc8cf4SOndrej Zary print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len); 439764a0c7eSOndrej Zary } 4401da177e4SLinus Torvalds #endif 4411794ef2bSChristoph Hellwig sg_count = scsi_dma_map(cmd); 4421794ef2bSChristoph Hellwig if (sg_count) { 4431794ef2bSChristoph Hellwig size_t len = sg_count * sizeof(struct chain); 4441794ef2bSChristoph Hellwig 4451794ef2bSChristoph Hellwig acmd->chain = kmalloc(len, GFP_DMA); 4461794ef2bSChristoph Hellwig if (!acmd->chain) 4471794ef2bSChristoph Hellwig goto out_unmap; 4481794ef2bSChristoph Hellwig acmd->chain_handle = dma_map_single(sh->dma_dev, acmd->chain, 4491794ef2bSChristoph Hellwig len, DMA_TO_DEVICE); 4501794ef2bSChristoph Hellwig if (dma_mapping_error(sh->dma_dev, acmd->chain_handle)) 4511794ef2bSChristoph Hellwig goto out_free_chain; 4528c08a621SOndrej Zary } 4538c08a621SOndrej Zary 454*e4da5febSSergey Shtylyov /* 455*e4da5febSSergey Shtylyov * Use the outgoing mailboxes in a round-robin fashion, because this 456*e4da5febSSergey Shtylyov * is how the host adapter will scan for them 457*e4da5febSSergey Shtylyov */ 4581da177e4SLinus Torvalds 4591b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 460e98878f7SOndrej Zary mbo = aha1542->aha1542_last_mbo_used + 1; 4611da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 4621da177e4SLinus Torvalds mbo = 0; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds do { 46555b28f9fSOndrej Zary if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) 4661da177e4SLinus Torvalds break; 4671da177e4SLinus Torvalds mbo++; 4681da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 4691da177e4SLinus Torvalds mbo = 0; 470e98878f7SOndrej Zary } while (mbo != aha1542->aha1542_last_mbo_used); 4711da177e4SLinus Torvalds 47255b28f9fSOndrej Zary if (mb[mbo].status || aha1542->int_cmds[mbo]) 4731da177e4SLinus Torvalds panic("Unable to find empty mailbox for aha1542.\n"); 4741da177e4SLinus Torvalds 47555b28f9fSOndrej Zary aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from 476*e4da5febSSergey Shtylyov * screwing with this cdb. 477*e4da5febSSergey Shtylyov */ 4781da177e4SLinus Torvalds 479e98878f7SOndrej Zary aha1542->aha1542_last_mbo_used = mbo; 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds #ifdef DEBUG 4821b0224b0SOndrej Zary shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done); 4831da177e4SLinus Torvalds #endif 4841da177e4SLinus Torvalds 4851794ef2bSChristoph Hellwig /* This gets trashed for some reason */ 4861794ef2bSChristoph Hellwig any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds memset(&ccb[mbo], 0, sizeof(struct ccb)); 4891da177e4SLinus Torvalds 49055b28f9fSOndrej Zary ccb[mbo].cdblen = cmd->cmd_len; 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds direction = 0; 49355b28f9fSOndrej Zary if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6) 4941da177e4SLinus Torvalds direction = 8; 49555b28f9fSOndrej Zary else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6) 4961da177e4SLinus Torvalds direction = 16; 4971da177e4SLinus Torvalds 49855b28f9fSOndrej Zary memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen); 4991da177e4SLinus Torvalds 500fc3fdfccSBoaz Harrosh if (bufflen) { 50151cf2249SJens Axboe struct scatterlist *sg; 5028c08a621SOndrej Zary int i; 5036ddc8cf4SOndrej Zary 5041da177e4SLinus Torvalds ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ 50555b28f9fSOndrej Zary scsi_for_each_sg(cmd, sg, sg_count, i) { 5061794ef2bSChristoph Hellwig any2scsi(acmd->chain[i].dataptr, sg_dma_address(sg)); 5071794ef2bSChristoph Hellwig any2scsi(acmd->chain[i].datalen, sg_dma_len(sg)); 5081da177e4SLinus Torvalds }; 509fc3fdfccSBoaz Harrosh any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); 5101794ef2bSChristoph Hellwig any2scsi(ccb[mbo].dataptr, acmd->chain_handle); 5111da177e4SLinus Torvalds #ifdef DEBUG 5121794ef2bSChristoph Hellwig shost_printk(KERN_DEBUG, sh, "cptr %p: ", acmd->chain); 5131794ef2bSChristoph Hellwig print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, acmd->chain, 18); 5141da177e4SLinus Torvalds #endif 5151da177e4SLinus Torvalds } else { 5161da177e4SLinus Torvalds ccb[mbo].op = 0; /* SCSI Initiator Command */ 517fc3fdfccSBoaz Harrosh any2scsi(ccb[mbo].datalen, 0); 518fc3fdfccSBoaz Harrosh any2scsi(ccb[mbo].dataptr, 0); 5191da177e4SLinus Torvalds }; 5201da177e4SLinus Torvalds ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */ 5211da177e4SLinus Torvalds ccb[mbo].rsalen = 16; 5221da177e4SLinus Torvalds ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; 5231da177e4SLinus Torvalds ccb[mbo].commlinkid = 0; 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds #ifdef DEBUG 5266ddc8cf4SOndrej Zary print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10); 527fde1fb8aSOndrej Zary printk("aha1542_queuecommand: now waiting for interrupt "); 528fde1fb8aSOndrej Zary #endif 5291da177e4SLinus Torvalds mb[mbo].status = 1; 53055b28f9fSOndrej Zary aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI); 5311b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds return 0; 5341794ef2bSChristoph Hellwig out_free_chain: 5351794ef2bSChristoph Hellwig kfree(acmd->chain); 5361794ef2bSChristoph Hellwig acmd->chain = NULL; 5371794ef2bSChristoph Hellwig out_unmap: 5381794ef2bSChristoph Hellwig scsi_dma_unmap(cmd); 5391794ef2bSChristoph Hellwig return SCSI_MLQUEUE_HOST_BUSY; 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds 5421da177e4SLinus Torvalds /* Initialize mailboxes */ 54368ea9de3SOndrej Zary static void setup_mailboxes(struct Scsi_Host *sh) 5441da177e4SLinus Torvalds { 545c2532f68SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 546cad2fc72SOndrej Zary u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; 5471794ef2bSChristoph Hellwig int i; 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds for (i = 0; i < AHA1542_MAILBOXES; i++) { 5501794ef2bSChristoph Hellwig aha1542->mb[i].status = 0; 5511794ef2bSChristoph Hellwig any2scsi(aha1542->mb[i].ccbptr, 5521794ef2bSChristoph Hellwig aha1542->ccb_handle + i * sizeof(struct ccb)); 5531794ef2bSChristoph Hellwig aha1542->mb[AHA1542_MAILBOXES + i].status = 0; 5541da177e4SLinus Torvalds }; 55568ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ 5561794ef2bSChristoph Hellwig any2scsi(mb_cmd + 2, aha1542->mb_handle); 55768ea9de3SOndrej Zary if (aha1542_out(sh->io_port, mb_cmd, 5)) 5582906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n"); 55968ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 5601da177e4SLinus Torvalds } 5611da177e4SLinus Torvalds 56268ea9de3SOndrej Zary static int aha1542_getconfig(struct Scsi_Host *sh) 5631da177e4SLinus Torvalds { 564cb5b570cSOndrej Zary u8 inquiry_result[3]; 5651da177e4SLinus Torvalds int i; 56668ea9de3SOndrej Zary i = inb(STATUS(sh->io_port)); 5671da177e4SLinus Torvalds if (i & DF) { 56868ea9de3SOndrej Zary i = inb(DATA(sh->io_port)); 5691da177e4SLinus Torvalds }; 57068ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_RETCONF); 57168ea9de3SOndrej Zary aha1542_in(sh->io_port, inquiry_result, 3, 0); 57268ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) 5732906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "error querying board settings\n"); 57468ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 5751da177e4SLinus Torvalds switch (inquiry_result[0]) { 5761da177e4SLinus Torvalds case 0x80: 57768ea9de3SOndrej Zary sh->dma_channel = 7; 5781da177e4SLinus Torvalds break; 5791da177e4SLinus Torvalds case 0x40: 58068ea9de3SOndrej Zary sh->dma_channel = 6; 5811da177e4SLinus Torvalds break; 5821da177e4SLinus Torvalds case 0x20: 58368ea9de3SOndrej Zary sh->dma_channel = 5; 5841da177e4SLinus Torvalds break; 5851da177e4SLinus Torvalds case 0x01: 58668ea9de3SOndrej Zary sh->dma_channel = 0; 5871da177e4SLinus Torvalds break; 5881da177e4SLinus Torvalds case 0: 589*e4da5febSSergey Shtylyov /* 590*e4da5febSSergey Shtylyov * This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel. 591*e4da5febSSergey Shtylyov * Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. 592*e4da5febSSergey Shtylyov */ 59368ea9de3SOndrej Zary sh->dma_channel = 0xFF; 5941da177e4SLinus Torvalds break; 5951da177e4SLinus Torvalds default: 5962906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n"); 5971da177e4SLinus Torvalds return -1; 5981da177e4SLinus Torvalds }; 5991da177e4SLinus Torvalds switch (inquiry_result[1]) { 6001da177e4SLinus Torvalds case 0x40: 60168ea9de3SOndrej Zary sh->irq = 15; 6021da177e4SLinus Torvalds break; 6031da177e4SLinus Torvalds case 0x20: 60468ea9de3SOndrej Zary sh->irq = 14; 6051da177e4SLinus Torvalds break; 6061da177e4SLinus Torvalds case 0x8: 60768ea9de3SOndrej Zary sh->irq = 12; 6081da177e4SLinus Torvalds break; 6091da177e4SLinus Torvalds case 0x4: 61068ea9de3SOndrej Zary sh->irq = 11; 6111da177e4SLinus Torvalds break; 6121da177e4SLinus Torvalds case 0x2: 61368ea9de3SOndrej Zary sh->irq = 10; 6141da177e4SLinus Torvalds break; 6151da177e4SLinus Torvalds case 0x1: 61668ea9de3SOndrej Zary sh->irq = 9; 6171da177e4SLinus Torvalds break; 6181da177e4SLinus Torvalds default: 6192906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n"); 6201da177e4SLinus Torvalds return -1; 6211da177e4SLinus Torvalds }; 62268ea9de3SOndrej Zary sh->this_id = inquiry_result[2] & 7; 6231da177e4SLinus Torvalds return 0; 6241da177e4SLinus Torvalds } 6251da177e4SLinus Torvalds 626*e4da5febSSergey Shtylyov /* 627*e4da5febSSergey Shtylyov * This function should only be called for 1542C boards - we can detect 628*e4da5febSSergey Shtylyov * the special firmware settings and unlock the board 629*e4da5febSSergey Shtylyov */ 6301da177e4SLinus Torvalds 63168ea9de3SOndrej Zary static int aha1542_mbenable(struct Scsi_Host *sh) 6321da177e4SLinus Torvalds { 633cb5b570cSOndrej Zary static u8 mbenable_cmd[3]; 634cb5b570cSOndrej Zary static u8 mbenable_result[2]; 6351da177e4SLinus Torvalds int retval; 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds retval = BIOS_TRANSLATION_6432; 6381da177e4SLinus Torvalds 63968ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_EXTBIOS); 64068ea9de3SOndrej Zary if (aha1542_in(sh->io_port, mbenable_result, 2, 100)) 6411da177e4SLinus Torvalds return retval; 64268ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100)) 6432093bfa1SOndrej Zary goto fail; 64468ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds if ((mbenable_result[0] & 0x08) || mbenable_result[1]) { 6471da177e4SLinus Torvalds mbenable_cmd[0] = CMD_MBENABLE; 6481da177e4SLinus Torvalds mbenable_cmd[1] = 0; 6491da177e4SLinus Torvalds mbenable_cmd[2] = mbenable_result[1]; 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03)) 6521da177e4SLinus Torvalds retval = BIOS_TRANSLATION_25563; 6531da177e4SLinus Torvalds 65468ea9de3SOndrej Zary if (aha1542_out(sh->io_port, mbenable_cmd, 3)) 6552093bfa1SOndrej Zary goto fail; 6561da177e4SLinus Torvalds }; 6571da177e4SLinus Torvalds while (0) { 6581da177e4SLinus Torvalds fail: 6592906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Mailbox init failed\n"); 6601da177e4SLinus Torvalds } 66168ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6621da177e4SLinus Torvalds return retval; 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds /* Query the board to find out if it is a 1542 or a 1740, or whatever. */ 66668ea9de3SOndrej Zary static int aha1542_query(struct Scsi_Host *sh) 6671da177e4SLinus Torvalds { 66868ea9de3SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 669cb5b570cSOndrej Zary u8 inquiry_result[4]; 6701da177e4SLinus Torvalds int i; 67168ea9de3SOndrej Zary i = inb(STATUS(sh->io_port)); 6721da177e4SLinus Torvalds if (i & DF) { 67368ea9de3SOndrej Zary i = inb(DATA(sh->io_port)); 6741da177e4SLinus Torvalds }; 67568ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_INQUIRY); 67668ea9de3SOndrej Zary aha1542_in(sh->io_port, inquiry_result, 4, 0); 67768ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) 6782906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "error querying card type\n"); 67968ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6801da177e4SLinus Torvalds 68168ea9de3SOndrej Zary aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */ 6821da177e4SLinus Torvalds 683*e4da5febSSergey Shtylyov /* 684*e4da5febSSergey Shtylyov * For an AHA1740 series board, we ignore the board since there is a 685*e4da5febSSergey Shtylyov * hardware bug which can lead to wrong blocks being returned if the board 686*e4da5febSSergey Shtylyov * is operating in the 1542 emulation mode. Since there is an extended mode 687*e4da5febSSergey Shtylyov * driver, we simply ignore the board and let the 1740 driver pick it up. 6881da177e4SLinus Torvalds */ 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds if (inquiry_result[0] == 0x43) { 6912906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n"); 6921da177e4SLinus Torvalds return 1; 6931da177e4SLinus Torvalds }; 6941da177e4SLinus Torvalds 695*e4da5febSSergey Shtylyov /* 696*e4da5febSSergey Shtylyov * Always call this - boards that do not support extended bios translation 697*e4da5febSSergey Shtylyov * will ignore the command, and we will set the proper default 698*e4da5febSSergey Shtylyov */ 6991da177e4SLinus Torvalds 70068ea9de3SOndrej Zary aha1542->bios_translation = aha1542_mbenable(sh); 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds return 0; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds 705f71429abSOndrej Zary static u8 dma_speed_hw(int dma_speed) 7061da177e4SLinus Torvalds { 707f71429abSOndrej Zary switch (dma_speed) { 7081da177e4SLinus Torvalds case 5: 709f71429abSOndrej Zary return 0x00; 7101da177e4SLinus Torvalds case 6: 711f71429abSOndrej Zary return 0x04; 7121da177e4SLinus Torvalds case 7: 713f71429abSOndrej Zary return 0x01; 7141da177e4SLinus Torvalds case 8: 715f71429abSOndrej Zary return 0x02; 7161da177e4SLinus Torvalds case 10: 717f71429abSOndrej Zary return 0x03; 7181da177e4SLinus Torvalds } 7191da177e4SLinus Torvalds 720f71429abSOndrej Zary return 0xff; /* invalid */ 7211da177e4SLinus Torvalds } 7221da177e4SLinus Torvalds 723b847fd0dSOndrej Zary /* Set the Bus on/off-times as not to ruin floppy performance */ 72437d607bdSOndrej Zary static void aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed) 725b847fd0dSOndrej Zary { 72637d607bdSOndrej Zary if (bus_on > 0) { 72737d607bdSOndrej Zary u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) }; 728b847fd0dSOndrej Zary 72937d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 73037d607bdSOndrej Zary if (aha1542_out(sh->io_port, oncmd, 2)) 731b847fd0dSOndrej Zary goto fail; 732f71429abSOndrej Zary } 733f71429abSOndrej Zary 73437d607bdSOndrej Zary if (bus_off > 0) { 73537d607bdSOndrej Zary u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) }; 736f71429abSOndrej Zary 73737d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 73837d607bdSOndrej Zary if (aha1542_out(sh->io_port, offcmd, 2)) 739b847fd0dSOndrej Zary goto fail; 740f71429abSOndrej Zary } 741f71429abSOndrej Zary 74237d607bdSOndrej Zary if (dma_speed_hw(dma_speed) != 0xff) { 74337d607bdSOndrej Zary u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) }; 744f71429abSOndrej Zary 74537d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 74637d607bdSOndrej Zary if (aha1542_out(sh->io_port, dmacmd, 2)) 747b847fd0dSOndrej Zary goto fail; 748b847fd0dSOndrej Zary } 74937d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 750b847fd0dSOndrej Zary return; 751b847fd0dSOndrej Zary fail: 7522906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n"); 75337d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 754b847fd0dSOndrej Zary } 755b847fd0dSOndrej Zary 7561da177e4SLinus Torvalds /* return non-zero on detection */ 757643a7c43SOndrej Zary static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx) 7581da177e4SLinus Torvalds { 759f71429abSOndrej Zary unsigned int base_io = io[indx]; 760c2532f68SOndrej Zary struct Scsi_Host *sh; 761e98878f7SOndrej Zary struct aha1542_hostdata *aha1542; 7622906b3ceSOndrej Zary char dma_info[] = "no DMA"; 7631da177e4SLinus Torvalds 7643a70c006SOndrej Zary if (base_io == 0) 765643a7c43SOndrej Zary return NULL; 7661da177e4SLinus Torvalds 7673a70c006SOndrej Zary if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542")) 7683a70c006SOndrej Zary return NULL; 7693a70c006SOndrej Zary 770c2532f68SOndrej Zary sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata)); 771c2532f68SOndrej Zary if (!sh) 7723a70c006SOndrej Zary goto release; 773c2532f68SOndrej Zary aha1542 = shost_priv(sh); 7743a70c006SOndrej Zary 77568ea9de3SOndrej Zary sh->unique_id = base_io; 77668ea9de3SOndrej Zary sh->io_port = base_io; 77768ea9de3SOndrej Zary sh->n_io_port = AHA1542_REGION_SIZE; 77868ea9de3SOndrej Zary aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1; 77968ea9de3SOndrej Zary aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1; 78068ea9de3SOndrej Zary 78168ea9de3SOndrej Zary if (!aha1542_test_port(sh)) 7823a70c006SOndrej Zary goto unregister; 7831da177e4SLinus Torvalds 78437d607bdSOndrej Zary aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]); 78568ea9de3SOndrej Zary if (aha1542_query(sh)) 7863a70c006SOndrej Zary goto unregister; 78768ea9de3SOndrej Zary if (aha1542_getconfig(sh) == -1) 7881da177e4SLinus Torvalds goto unregister; 7891da177e4SLinus Torvalds 790c2532f68SOndrej Zary if (sh->dma_channel != 0xFF) 7912906b3ceSOndrej Zary snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel); 7922906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n", 7932906b3ceSOndrej Zary sh->this_id, base_io, sh->irq, dma_info); 7943a70c006SOndrej Zary if (aha1542->bios_translation == BIOS_TRANSLATION_25563) 7952906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Using extended bios translation\n"); 7961da177e4SLinus Torvalds 7971794ef2bSChristoph Hellwig if (dma_set_mask_and_coherent(pdev, DMA_BIT_MASK(24)) < 0) 7981794ef2bSChristoph Hellwig goto unregister; 7991794ef2bSChristoph Hellwig 8001794ef2bSChristoph Hellwig aha1542->mb = dma_alloc_coherent(pdev, 8011794ef2bSChristoph Hellwig AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), 8021794ef2bSChristoph Hellwig &aha1542->mb_handle, GFP_KERNEL); 8031794ef2bSChristoph Hellwig if (!aha1542->mb) 8041794ef2bSChristoph Hellwig goto unregister; 8051794ef2bSChristoph Hellwig 8061794ef2bSChristoph Hellwig aha1542->ccb = dma_alloc_coherent(pdev, 8071794ef2bSChristoph Hellwig AHA1542_MAILBOXES * sizeof(struct ccb), 8081794ef2bSChristoph Hellwig &aha1542->ccb_handle, GFP_KERNEL); 8091794ef2bSChristoph Hellwig if (!aha1542->ccb) 8101794ef2bSChristoph Hellwig goto free_mb; 8111794ef2bSChristoph Hellwig 81268ea9de3SOndrej Zary setup_mailboxes(sh); 8131da177e4SLinus Torvalds 8141b0224b0SOndrej Zary if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) { 8152906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n"); 8161794ef2bSChristoph Hellwig goto free_ccb; 8171da177e4SLinus Torvalds } 818c2532f68SOndrej Zary if (sh->dma_channel != 0xFF) { 819c2532f68SOndrej Zary if (request_dma(sh->dma_channel, "aha1542")) { 8202906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n"); 8213a70c006SOndrej Zary goto free_irq; 8221da177e4SLinus Torvalds } 823c2532f68SOndrej Zary if (sh->dma_channel == 0 || sh->dma_channel >= 5) { 824c2532f68SOndrej Zary set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE); 825c2532f68SOndrej Zary enable_dma(sh->dma_channel); 8261da177e4SLinus Torvalds } 8271da177e4SLinus Torvalds } 82887c4d7bcSJeff Garzik 829c2532f68SOndrej Zary if (scsi_add_host(sh, pdev)) 8303a70c006SOndrej Zary goto free_dma; 8311da177e4SLinus Torvalds 832c2532f68SOndrej Zary scsi_scan_host(sh); 8331da177e4SLinus Torvalds 834c2532f68SOndrej Zary return sh; 8351794ef2bSChristoph Hellwig 8363a70c006SOndrej Zary free_dma: 837c2532f68SOndrej Zary if (sh->dma_channel != 0xff) 838c2532f68SOndrej Zary free_dma(sh->dma_channel); 8393a70c006SOndrej Zary free_irq: 840c2532f68SOndrej Zary free_irq(sh->irq, sh); 8411794ef2bSChristoph Hellwig free_ccb: 8421794ef2bSChristoph Hellwig dma_free_coherent(pdev, AHA1542_MAILBOXES * sizeof(struct ccb), 8431794ef2bSChristoph Hellwig aha1542->ccb, aha1542->ccb_handle); 8441794ef2bSChristoph Hellwig free_mb: 8451794ef2bSChristoph Hellwig dma_free_coherent(pdev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), 8461794ef2bSChristoph Hellwig aha1542->mb, aha1542->mb_handle); 8471da177e4SLinus Torvalds unregister: 848c2532f68SOndrej Zary scsi_host_put(sh); 8493a70c006SOndrej Zary release: 8503a70c006SOndrej Zary release_region(base_io, AHA1542_REGION_SIZE); 8511da177e4SLinus Torvalds 852643a7c43SOndrej Zary return NULL; 8531da177e4SLinus Torvalds } 8541da177e4SLinus Torvalds 855c2532f68SOndrej Zary static int aha1542_release(struct Scsi_Host *sh) 8561da177e4SLinus Torvalds { 8571794ef2bSChristoph Hellwig struct aha1542_hostdata *aha1542 = shost_priv(sh); 8581794ef2bSChristoph Hellwig struct device *dev = sh->dma_dev; 8591794ef2bSChristoph Hellwig 860c2532f68SOndrej Zary scsi_remove_host(sh); 861c2532f68SOndrej Zary if (sh->dma_channel != 0xff) 862c2532f68SOndrej Zary free_dma(sh->dma_channel); 8631794ef2bSChristoph Hellwig dma_free_coherent(dev, AHA1542_MAILBOXES * sizeof(struct ccb), 8641794ef2bSChristoph Hellwig aha1542->ccb, aha1542->ccb_handle); 8651794ef2bSChristoph Hellwig dma_free_coherent(dev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), 8661794ef2bSChristoph Hellwig aha1542->mb, aha1542->mb_handle); 867c2532f68SOndrej Zary if (sh->irq) 868c2532f68SOndrej Zary free_irq(sh->irq, sh); 869c2532f68SOndrej Zary if (sh->io_port && sh->n_io_port) 870c2532f68SOndrej Zary release_region(sh->io_port, sh->n_io_port); 871c2532f68SOndrej Zary scsi_host_put(sh); 8721da177e4SLinus Torvalds return 0; 8731da177e4SLinus Torvalds } 8741da177e4SLinus Torvalds 8751da177e4SLinus Torvalds 8761da177e4SLinus Torvalds /* 8771da177e4SLinus Torvalds * This is a device reset. This is handled by sending a special command 8781da177e4SLinus Torvalds * to the device. 8791da177e4SLinus Torvalds */ 88055b28f9fSOndrej Zary static int aha1542_dev_reset(struct scsi_cmnd *cmd) 8811da177e4SLinus Torvalds { 8821b0224b0SOndrej Zary struct Scsi_Host *sh = cmd->device->host; 8831b0224b0SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 8841da177e4SLinus Torvalds unsigned long flags; 885e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 88655b28f9fSOndrej Zary u8 target = cmd->device->id; 88755b28f9fSOndrej Zary u8 lun = cmd->device->lun; 8881da177e4SLinus Torvalds int mbo; 889e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 8901da177e4SLinus Torvalds 8911b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 892e98878f7SOndrej Zary mbo = aha1542->aha1542_last_mbo_used + 1; 8931da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 8941da177e4SLinus Torvalds mbo = 0; 8951da177e4SLinus Torvalds 8961da177e4SLinus Torvalds do { 89755b28f9fSOndrej Zary if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) 8981da177e4SLinus Torvalds break; 8991da177e4SLinus Torvalds mbo++; 9001da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 9011da177e4SLinus Torvalds mbo = 0; 902e98878f7SOndrej Zary } while (mbo != aha1542->aha1542_last_mbo_used); 9031da177e4SLinus Torvalds 90455b28f9fSOndrej Zary if (mb[mbo].status || aha1542->int_cmds[mbo]) 9051da177e4SLinus Torvalds panic("Unable to find empty mailbox for aha1542.\n"); 9061da177e4SLinus Torvalds 90755b28f9fSOndrej Zary aha1542->int_cmds[mbo] = cmd; /* This will effectively 908*e4da5febSSergey Shtylyov * prevent someone else from 909*e4da5febSSergey Shtylyov * screwing with this cdb. 910*e4da5febSSergey Shtylyov */ 9111da177e4SLinus Torvalds 912e98878f7SOndrej Zary aha1542->aha1542_last_mbo_used = mbo; 9131da177e4SLinus Torvalds 9141794ef2bSChristoph Hellwig /* This gets trashed for some reason */ 9151794ef2bSChristoph Hellwig any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds memset(&ccb[mbo], 0, sizeof(struct ccb)); 9181da177e4SLinus Torvalds 9191da177e4SLinus Torvalds ccb[mbo].op = 0x81; /* BUS DEVICE RESET */ 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */ 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; 9241da177e4SLinus Torvalds ccb[mbo].commlinkid = 0; 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds /* 9271da177e4SLinus Torvalds * Now tell the 1542 to flush all pending commands for this 9281da177e4SLinus Torvalds * target 9291da177e4SLinus Torvalds */ 9301b0224b0SOndrej Zary aha1542_outb(sh->io_port, CMD_START_SCSI); 9311b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 9321da177e4SLinus Torvalds 93355b28f9fSOndrej Zary scmd_printk(KERN_WARNING, cmd, 934017560fcSJeff Garzik "Trying device reset for target\n"); 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds return SUCCESS; 9371da177e4SLinus Torvalds } 9381da177e4SLinus Torvalds 93955b28f9fSOndrej Zary static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd) 9401da177e4SLinus Torvalds { 9411b0224b0SOndrej Zary struct Scsi_Host *sh = cmd->device->host; 9421b0224b0SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 9431b0224b0SOndrej Zary unsigned long flags; 9441da177e4SLinus Torvalds int i; 9451da177e4SLinus Torvalds 9461b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 9471da177e4SLinus Torvalds /* 9481da177e4SLinus Torvalds * This does a scsi reset for all devices on the bus. 9491da177e4SLinus Torvalds * In principle, we could also reset the 1542 - should 9501da177e4SLinus Torvalds * we do this? Try this first, and we can add that later 9511da177e4SLinus Torvalds * if it turns out to be useful. 9521da177e4SLinus Torvalds */ 95355b28f9fSOndrej Zary outb(reset_cmd, CONTROL(cmd->device->host->io_port)); 9541da177e4SLinus Torvalds 95555b28f9fSOndrej Zary if (!wait_mask(STATUS(cmd->device->host->io_port), 9567061dec4SOndrej Zary STATMASK, IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) { 9571b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 958a13b3722SOndrej Zary return FAILED; 959a13b3722SOndrej Zary } 9601b0224b0SOndrej Zary 9611da177e4SLinus Torvalds /* 9621da177e4SLinus Torvalds * We need to do this too before the 1542 can interact with 9638537cba8SOndrej Zary * us again after host reset. 9641da177e4SLinus Torvalds */ 9658537cba8SOndrej Zary if (reset_cmd & HRST) 96668ea9de3SOndrej Zary setup_mailboxes(cmd->device->host); 9671b0224b0SOndrej Zary 9681da177e4SLinus Torvalds /* 9691da177e4SLinus Torvalds * Now try to pick up the pieces. For all pending commands, 9701da177e4SLinus Torvalds * free any internal data structures, and basically clear things 9711da177e4SLinus Torvalds * out. We do not try and restart any commands or anything - 9721da177e4SLinus Torvalds * the strategy handler takes care of that crap. 9731da177e4SLinus Torvalds */ 9742906b3ceSOndrej Zary shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no); 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds for (i = 0; i < AHA1542_MAILBOXES; i++) { 97755b28f9fSOndrej Zary if (aha1542->int_cmds[i] != NULL) { 97855b28f9fSOndrej Zary struct scsi_cmnd *tmp_cmd; 97955b28f9fSOndrej Zary tmp_cmd = aha1542->int_cmds[i]; 9801da177e4SLinus Torvalds 98155b28f9fSOndrej Zary if (tmp_cmd->device->soft_reset) { 9821da177e4SLinus Torvalds /* 9831da177e4SLinus Torvalds * If this device implements the soft reset option, 9841da177e4SLinus Torvalds * then it is still holding onto the command, and 9851da177e4SLinus Torvalds * may yet complete it. In this case, we don't 9861da177e4SLinus Torvalds * flush the data. 9871da177e4SLinus Torvalds */ 9881da177e4SLinus Torvalds continue; 9891da177e4SLinus Torvalds } 9901794ef2bSChristoph Hellwig aha1542_free_cmd(tmp_cmd); 99155b28f9fSOndrej Zary aha1542->int_cmds[i] = NULL; 992e98878f7SOndrej Zary aha1542->mb[i].status = 0; 9931da177e4SLinus Torvalds } 9941da177e4SLinus Torvalds } 9951da177e4SLinus Torvalds 9961b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 9971da177e4SLinus Torvalds return SUCCESS; 9981da177e4SLinus Torvalds } 9991da177e4SLinus Torvalds 100055b28f9fSOndrej Zary static int aha1542_bus_reset(struct scsi_cmnd *cmd) 10018537cba8SOndrej Zary { 100255b28f9fSOndrej Zary return aha1542_reset(cmd, SCRST); 10038537cba8SOndrej Zary } 10048537cba8SOndrej Zary 100555b28f9fSOndrej Zary static int aha1542_host_reset(struct scsi_cmnd *cmd) 10068537cba8SOndrej Zary { 100755b28f9fSOndrej Zary return aha1542_reset(cmd, HRST | SCRST); 10088537cba8SOndrej Zary } 10098537cba8SOndrej Zary 10101da177e4SLinus Torvalds static int aha1542_biosparam(struct scsi_device *sdev, 101117787a09SOndrej Zary struct block_device *bdev, sector_t capacity, int geom[]) 10121da177e4SLinus Torvalds { 1013e98878f7SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sdev->host); 10141da177e4SLinus Torvalds 101517787a09SOndrej Zary if (capacity >= 0x200000 && 101617787a09SOndrej Zary aha1542->bios_translation == BIOS_TRANSLATION_25563) { 10171da177e4SLinus Torvalds /* Please verify that this is the same as what DOS returns */ 101817787a09SOndrej Zary geom[0] = 255; /* heads */ 101917787a09SOndrej Zary geom[1] = 63; /* sectors */ 10201da177e4SLinus Torvalds } else { 102117787a09SOndrej Zary geom[0] = 64; /* heads */ 102217787a09SOndrej Zary geom[1] = 32; /* sectors */ 10231da177e4SLinus Torvalds } 102417787a09SOndrej Zary geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */ 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds return 0; 10271da177e4SLinus Torvalds } 10281da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 10291da177e4SLinus Torvalds 1030d0be4a7dSChristoph Hellwig static struct scsi_host_template driver_template = { 1031643a7c43SOndrej Zary .module = THIS_MODULE, 10321da177e4SLinus Torvalds .proc_name = "aha1542", 10331da177e4SLinus Torvalds .name = "Adaptec 1542", 10341794ef2bSChristoph Hellwig .cmd_size = sizeof(struct aha1542_cmd), 10351da177e4SLinus Torvalds .queuecommand = aha1542_queuecommand, 10361da177e4SLinus Torvalds .eh_device_reset_handler= aha1542_dev_reset, 10371da177e4SLinus Torvalds .eh_bus_reset_handler = aha1542_bus_reset, 10381da177e4SLinus Torvalds .eh_host_reset_handler = aha1542_host_reset, 10391da177e4SLinus Torvalds .bios_param = aha1542_biosparam, 10401da177e4SLinus Torvalds .can_queue = AHA1542_MAILBOXES, 10411da177e4SLinus Torvalds .this_id = 7, 104210be6250SOndrej Zary .sg_tablesize = 16, 10431da177e4SLinus Torvalds .unchecked_isa_dma = 1, 10441da177e4SLinus Torvalds }; 1045643a7c43SOndrej Zary 1046643a7c43SOndrej Zary static int aha1542_isa_match(struct device *pdev, unsigned int ndev) 1047643a7c43SOndrej Zary { 1048643a7c43SOndrej Zary struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev); 1049643a7c43SOndrej Zary 1050643a7c43SOndrej Zary if (!sh) 1051643a7c43SOndrej Zary return 0; 1052643a7c43SOndrej Zary 1053643a7c43SOndrej Zary dev_set_drvdata(pdev, sh); 1054643a7c43SOndrej Zary return 1; 1055643a7c43SOndrej Zary } 1056643a7c43SOndrej Zary 1057643a7c43SOndrej Zary static int aha1542_isa_remove(struct device *pdev, 1058643a7c43SOndrej Zary unsigned int ndev) 1059643a7c43SOndrej Zary { 1060643a7c43SOndrej Zary aha1542_release(dev_get_drvdata(pdev)); 1061643a7c43SOndrej Zary dev_set_drvdata(pdev, NULL); 1062643a7c43SOndrej Zary return 0; 1063643a7c43SOndrej Zary } 1064643a7c43SOndrej Zary 1065643a7c43SOndrej Zary static struct isa_driver aha1542_isa_driver = { 1066643a7c43SOndrej Zary .match = aha1542_isa_match, 1067643a7c43SOndrej Zary .remove = aha1542_isa_remove, 1068643a7c43SOndrej Zary .driver = { 1069643a7c43SOndrej Zary .name = "aha1542" 1070643a7c43SOndrej Zary }, 1071643a7c43SOndrej Zary }; 1072643a7c43SOndrej Zary static int isa_registered; 1073643a7c43SOndrej Zary 1074643a7c43SOndrej Zary #ifdef CONFIG_PNP 107578453a31SArvind Yadav static const struct pnp_device_id aha1542_pnp_ids[] = { 1076643a7c43SOndrej Zary { .id = "ADP1542" }, 1077643a7c43SOndrej Zary { .id = "" } 1078643a7c43SOndrej Zary }; 1079643a7c43SOndrej Zary MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids); 1080643a7c43SOndrej Zary 1081643a7c43SOndrej Zary static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id) 1082643a7c43SOndrej Zary { 1083643a7c43SOndrej Zary int indx; 1084643a7c43SOndrej Zary struct Scsi_Host *sh; 1085643a7c43SOndrej Zary 1086f71429abSOndrej Zary for (indx = 0; indx < ARRAY_SIZE(io); indx++) { 1087f71429abSOndrej Zary if (io[indx]) 1088643a7c43SOndrej Zary continue; 1089643a7c43SOndrej Zary 1090643a7c43SOndrej Zary if (pnp_activate_dev(pdev) < 0) 1091643a7c43SOndrej Zary continue; 1092643a7c43SOndrej Zary 1093f71429abSOndrej Zary io[indx] = pnp_port_start(pdev, 0); 1094643a7c43SOndrej Zary 1095*e4da5febSSergey Shtylyov /* 1096*e4da5febSSergey Shtylyov * The card can be queried for its DMA, we have 1097*e4da5febSSergey Shtylyov * the DMA set up that is enough 1098*e4da5febSSergey Shtylyov */ 1099643a7c43SOndrej Zary 11002906b3ceSOndrej Zary dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]); 1101643a7c43SOndrej Zary } 1102643a7c43SOndrej Zary 1103643a7c43SOndrej Zary sh = aha1542_hw_init(&driver_template, &pdev->dev, indx); 1104643a7c43SOndrej Zary if (!sh) 1105643a7c43SOndrej Zary return -ENODEV; 1106643a7c43SOndrej Zary 1107643a7c43SOndrej Zary pnp_set_drvdata(pdev, sh); 1108643a7c43SOndrej Zary return 0; 1109643a7c43SOndrej Zary } 1110643a7c43SOndrej Zary 1111643a7c43SOndrej Zary static void aha1542_pnp_remove(struct pnp_dev *pdev) 1112643a7c43SOndrej Zary { 1113643a7c43SOndrej Zary aha1542_release(pnp_get_drvdata(pdev)); 1114643a7c43SOndrej Zary pnp_set_drvdata(pdev, NULL); 1115643a7c43SOndrej Zary } 1116643a7c43SOndrej Zary 1117643a7c43SOndrej Zary static struct pnp_driver aha1542_pnp_driver = { 1118643a7c43SOndrej Zary .name = "aha1542", 1119643a7c43SOndrej Zary .id_table = aha1542_pnp_ids, 1120643a7c43SOndrej Zary .probe = aha1542_pnp_probe, 1121643a7c43SOndrej Zary .remove = aha1542_pnp_remove, 1122643a7c43SOndrej Zary }; 1123643a7c43SOndrej Zary static int pnp_registered; 1124643a7c43SOndrej Zary #endif /* CONFIG_PNP */ 1125643a7c43SOndrej Zary 1126643a7c43SOndrej Zary static int __init aha1542_init(void) 1127643a7c43SOndrej Zary { 1128643a7c43SOndrej Zary int ret = 0; 1129643a7c43SOndrej Zary 1130643a7c43SOndrej Zary #ifdef CONFIG_PNP 1131643a7c43SOndrej Zary if (isapnp) { 1132643a7c43SOndrej Zary ret = pnp_register_driver(&aha1542_pnp_driver); 1133643a7c43SOndrej Zary if (!ret) 1134643a7c43SOndrej Zary pnp_registered = 1; 1135643a7c43SOndrej Zary } 1136643a7c43SOndrej Zary #endif 1137643a7c43SOndrej Zary ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS); 1138643a7c43SOndrej Zary if (!ret) 1139643a7c43SOndrej Zary isa_registered = 1; 1140643a7c43SOndrej Zary 1141643a7c43SOndrej Zary #ifdef CONFIG_PNP 1142643a7c43SOndrej Zary if (pnp_registered) 1143643a7c43SOndrej Zary ret = 0; 1144643a7c43SOndrej Zary #endif 1145643a7c43SOndrej Zary if (isa_registered) 1146643a7c43SOndrej Zary ret = 0; 1147643a7c43SOndrej Zary 1148643a7c43SOndrej Zary return ret; 1149643a7c43SOndrej Zary } 1150643a7c43SOndrej Zary 1151643a7c43SOndrej Zary static void __exit aha1542_exit(void) 1152643a7c43SOndrej Zary { 1153643a7c43SOndrej Zary #ifdef CONFIG_PNP 1154643a7c43SOndrej Zary if (pnp_registered) 1155643a7c43SOndrej Zary pnp_unregister_driver(&aha1542_pnp_driver); 1156643a7c43SOndrej Zary #endif 1157643a7c43SOndrej Zary if (isa_registered) 1158643a7c43SOndrej Zary isa_unregister_driver(&aha1542_isa_driver); 1159643a7c43SOndrej Zary } 1160643a7c43SOndrej Zary 1161643a7c43SOndrej Zary module_init(aha1542_init); 1162643a7c43SOndrej Zary module_exit(aha1542_exit); 1163