11d084d20SOndrej Zary /* 21d084d20SOndrej Zary * Driver for Adaptec AHA-1542 SCSI host adapters 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1992 Tommy Thorn 51da177e4SLinus Torvalds * Copyright (C) 1993, 1994, 1995 Eric Youngdale 61d084d20SOndrej Zary * Copyright (C) 2015 Ondrej Zary 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/module.h> 101da177e4SLinus Torvalds #include <linux/interrupt.h> 111da177e4SLinus Torvalds #include <linux/kernel.h> 121da177e4SLinus Torvalds #include <linux/types.h> 131da177e4SLinus Torvalds #include <linux/string.h> 141da177e4SLinus Torvalds #include <linux/delay.h> 151da177e4SLinus Torvalds #include <linux/init.h> 161da177e4SLinus Torvalds #include <linux/spinlock.h> 17643a7c43SOndrej Zary #include <linux/isa.h> 18643a7c43SOndrej Zary #include <linux/pnp.h> 195a0e3ad6STejun Heo #include <linux/slab.h> 20954a9fd7SOndrej Zary #include <linux/io.h> 211da177e4SLinus Torvalds #include <asm/dma.h> 22954a9fd7SOndrej Zary #include <scsi/scsi_cmnd.h> 23954a9fd7SOndrej Zary #include <scsi/scsi_device.h> 241da177e4SLinus Torvalds #include <scsi/scsi_host.h> 251da177e4SLinus Torvalds #include "aha1542.h" 261da177e4SLinus Torvalds 27f71429abSOndrej Zary #define MAXBOARDS 4 281da177e4SLinus Torvalds 29f71429abSOndrej Zary static bool isapnp = 1; 301da177e4SLinus Torvalds module_param(isapnp, bool, 0); 31f71429abSOndrej Zary MODULE_PARM_DESC(isapnp, "enable PnP support (default=1)"); 32f71429abSOndrej Zary 33f71429abSOndrej Zary static int io[MAXBOARDS] = { 0x330, 0x334, 0, 0 }; 34f71429abSOndrej Zary module_param_array(io, int, NULL, 0); 35f71429abSOndrej Zary MODULE_PARM_DESC(io, "base IO address of controller (0x130,0x134,0x230,0x234,0x330,0x334, default=0x330,0x334)"); 36f71429abSOndrej Zary 37f71429abSOndrej Zary /* time AHA spends on the AT-bus during data transfer */ 38f71429abSOndrej Zary static int bus_on[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 11us */ 39f71429abSOndrej Zary module_param_array(bus_on, int, NULL, 0); 40f71429abSOndrej Zary MODULE_PARM_DESC(bus_on, "bus on time [us] (2-15, default=-1 [HW default: 11])"); 41f71429abSOndrej Zary 42f71429abSOndrej Zary /* time AHA spends off the bus (not to monopolize it) during data transfer */ 43f71429abSOndrej Zary static int bus_off[MAXBOARDS] = { -1, -1, -1, -1 }; /* power-on default: 4us */ 44f71429abSOndrej Zary module_param_array(bus_off, int, NULL, 0); 45f71429abSOndrej Zary MODULE_PARM_DESC(bus_off, "bus off time [us] (1-64, default=-1 [HW default: 4])"); 46f71429abSOndrej Zary 47f71429abSOndrej Zary /* default is jumper selected (J1 on 1542A), factory default = 5 MB/s */ 48f71429abSOndrej Zary static int dma_speed[MAXBOARDS] = { -1, -1, -1, -1 }; 49f71429abSOndrej Zary module_param_array(dma_speed, int, NULL, 0); 50f71429abSOndrej Zary MODULE_PARM_DESC(dma_speed, "DMA speed [MB/s] (5,6,7,8,10, default=-1 [by jumper])"); 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds #define BIOS_TRANSLATION_6432 1 /* Default case these days */ 531da177e4SLinus Torvalds #define BIOS_TRANSLATION_25563 2 /* Big disk case */ 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds struct aha1542_hostdata { 561da177e4SLinus Torvalds /* This will effectively start both of them at the first mailbox */ 571da177e4SLinus Torvalds int bios_translation; /* Mapping bios uses - for compatibility */ 581da177e4SLinus Torvalds int aha1542_last_mbi_used; 591da177e4SLinus Torvalds int aha1542_last_mbo_used; 6055b28f9fSOndrej Zary struct scsi_cmnd *int_cmds[AHA1542_MAILBOXES]; 611da177e4SLinus Torvalds struct mailbox mb[2 * AHA1542_MAILBOXES]; 621da177e4SLinus Torvalds struct ccb ccb[AHA1542_MAILBOXES]; 631da177e4SLinus Torvalds }; 641da177e4SLinus Torvalds 65f1bbef63SOndrej Zary static inline void aha1542_intr_reset(u16 base) 66f1bbef63SOndrej Zary { 67f1bbef63SOndrej Zary outb(IRST, CONTROL(base)); 68f1bbef63SOndrej Zary } 691da177e4SLinus Torvalds 702093bfa1SOndrej Zary static inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout) 712093bfa1SOndrej Zary { 722093bfa1SOndrej Zary bool delayed = true; 732093bfa1SOndrej Zary 742093bfa1SOndrej Zary if (timeout == 0) { 752093bfa1SOndrej Zary timeout = 3000000; 762093bfa1SOndrej Zary delayed = false; 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 792093bfa1SOndrej Zary while (1) { 802093bfa1SOndrej Zary u8 bits = inb(port) & mask; 812093bfa1SOndrej Zary if ((bits & allof) == allof && ((bits & noneof) == 0)) 822093bfa1SOndrej Zary break; 832093bfa1SOndrej Zary if (delayed) 842093bfa1SOndrej Zary mdelay(1); 852093bfa1SOndrej Zary if (--timeout == 0) 862093bfa1SOndrej Zary return false; 872093bfa1SOndrej Zary } 882093bfa1SOndrej Zary 892093bfa1SOndrej Zary return true; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 92cad2fc72SOndrej Zary static int aha1542_outb(unsigned int base, u8 val) 931da177e4SLinus Torvalds { 942906b3ceSOndrej Zary if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) 950c2b6481SOndrej Zary return 1; 96cad2fc72SOndrej Zary outb(val, DATA(base)); 97*eef77801SOndrej Zary 981da177e4SLinus Torvalds return 0; 991da177e4SLinus Torvalds } 1000c2b6481SOndrej Zary 101cad2fc72SOndrej Zary static int aha1542_out(unsigned int base, u8 *buf, int len) 1020c2b6481SOndrej Zary { 1031da177e4SLinus Torvalds while (len--) { 1041b0224b0SOndrej Zary if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) 1051da177e4SLinus Torvalds return 1; 106cad2fc72SOndrej Zary outb(*buf++, DATA(base)); 1070c2b6481SOndrej Zary } 10823e6940aSOndrej Zary if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0)) 10923e6940aSOndrej Zary return 1; 1100c2b6481SOndrej Zary 1110c2b6481SOndrej Zary return 0; 1120c2b6481SOndrej Zary } 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds /* Only used at boot time, so we do not need to worry about latency as much 1151da177e4SLinus Torvalds here */ 1161da177e4SLinus Torvalds 117cad2fc72SOndrej Zary static int aha1542_in(unsigned int base, u8 *buf, int len, int timeout) 1181da177e4SLinus Torvalds { 1191da177e4SLinus Torvalds while (len--) { 1201b0224b0SOndrej Zary if (!wait_mask(STATUS(base), DF, DF, 0, timeout)) 1211da177e4SLinus Torvalds return 1; 122cad2fc72SOndrej Zary *buf++ = inb(DATA(base)); 123a13b3722SOndrej Zary } 124a13b3722SOndrej Zary return 0; 125a13b3722SOndrej Zary } 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static int makecode(unsigned hosterr, unsigned scsierr) 1281da177e4SLinus Torvalds { 1291da177e4SLinus Torvalds switch (hosterr) { 1301da177e4SLinus Torvalds case 0x0: 1311da177e4SLinus Torvalds case 0xa: /* Linked command complete without error and linked normally */ 1321da177e4SLinus Torvalds case 0xb: /* Linked command complete without error, interrupt generated */ 1331da177e4SLinus Torvalds hosterr = 0; 1341da177e4SLinus Torvalds break; 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds case 0x11: /* Selection time out-The initiator selection or target 1371da177e4SLinus Torvalds reselection was not complete within the SCSI Time out period */ 1381da177e4SLinus Torvalds hosterr = DID_TIME_OUT; 1391da177e4SLinus Torvalds break; 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds case 0x12: /* Data overrun/underrun-The target attempted to transfer more data 1421da177e4SLinus Torvalds than was allocated by the Data Length field or the sum of the 1431da177e4SLinus Torvalds Scatter / Gather Data Length fields. */ 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was 1481da177e4SLinus Torvalds invalid. This usually indicates a software failure. */ 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. 1511da177e4SLinus Torvalds This usually indicates a software failure. */ 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set 1541da177e4SLinus Torvalds of linked CCB's does not specify the same logical unit number as 1551da177e4SLinus Torvalds the first. */ 1561da177e4SLinus Torvalds case 0x18: /* Invalid Target Direction received from Host-The direction of a 1571da177e4SLinus Torvalds Target Mode CCB was invalid. */ 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was 1601da177e4SLinus Torvalds received to service data transfer between the same target LUN 1611da177e4SLinus Torvalds and initiator SCSI ID in the same direction. */ 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero 1641da177e4SLinus Torvalds length segment or invalid segment list boundaries was received. 1651da177e4SLinus Torvalds A CCB parameter was invalid. */ 166fde1fb8aSOndrej Zary #ifdef DEBUG 167fde1fb8aSOndrej Zary printk("Aha1542: %x %x\n", hosterr, scsierr); 168fde1fb8aSOndrej Zary #endif 1691da177e4SLinus Torvalds hosterr = DID_ERROR; /* Couldn't find any better */ 1701da177e4SLinus Torvalds break; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus 1731da177e4SLinus Torvalds phase sequence was requested by the target. The host adapter 1741da177e4SLinus Torvalds will generate a SCSI Reset Condition, notifying the host with 1751da177e4SLinus Torvalds a SCRD interrupt */ 1761da177e4SLinus Torvalds hosterr = DID_RESET; 1771da177e4SLinus Torvalds break; 1781da177e4SLinus Torvalds default: 1791da177e4SLinus Torvalds printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr); 1801da177e4SLinus Torvalds break; 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds return scsierr | (hosterr << 16); 1831da177e4SLinus Torvalds } 1841da177e4SLinus Torvalds 18568ea9de3SOndrej Zary static int aha1542_test_port(struct Scsi_Host *sh) 1861da177e4SLinus Torvalds { 187cb5b570cSOndrej Zary u8 inquiry_result[4]; 188cad2fc72SOndrej Zary int i; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds /* Quick and dirty test for presence of the card. */ 19168ea9de3SOndrej Zary if (inb(STATUS(sh->io_port)) == 0xff) 1921da177e4SLinus Torvalds return 0; 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */ 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds /* In case some other card was probing here, reset interrupts */ 19768ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ 1981da177e4SLinus Torvalds 19968ea9de3SOndrej Zary outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port)); 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds mdelay(20); /* Wait a little bit for things to settle down. */ 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /* Expect INIT and IDLE, any of the others are bad */ 20468ea9de3SOndrej Zary if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) 205a13b3722SOndrej Zary return 0; 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* Shouldn't have generated any interrupts during reset */ 20868ea9de3SOndrej Zary if (inb(INTRFLAGS(sh->io_port)) & INTRMASK) 209a13b3722SOndrej Zary return 0; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* Perform a host adapter inquiry instead so we do not need to set 2121da177e4SLinus Torvalds up the mailboxes ahead of time */ 2131da177e4SLinus Torvalds 21468ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_INQUIRY); 2151da177e4SLinus Torvalds 216cad2fc72SOndrej Zary for (i = 0; i < 4; i++) { 21768ea9de3SOndrej Zary if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0)) 218a13b3722SOndrej Zary return 0; 21968ea9de3SOndrej Zary inquiry_result[i] = inb(DATA(sh->io_port)); 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds /* Reading port should reset DF */ 22368ea9de3SOndrej Zary if (inb(STATUS(sh->io_port)) & DF) 224a13b3722SOndrej Zary return 0; 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds /* When HACC, command is completed, and we're though testing */ 22768ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0)) 228a13b3722SOndrej Zary return 0; 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds /* Clear interrupts */ 23168ea9de3SOndrej Zary outb(IRST, CONTROL(sh->io_port)); 2321da177e4SLinus Torvalds 233bdebe224SOndrej Zary return 1; 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 2361b0224b0SOndrej Zary static irqreturn_t aha1542_interrupt(int irq, void *dev_id) 2371da177e4SLinus Torvalds { 2381b0224b0SOndrej Zary struct Scsi_Host *sh = dev_id; 239c2532f68SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 24055b28f9fSOndrej Zary void (*my_done)(struct scsi_cmnd *) = NULL; 2411da177e4SLinus Torvalds int errstatus, mbi, mbo, mbistatus; 2421da177e4SLinus Torvalds int number_serviced; 2431da177e4SLinus Torvalds unsigned long flags; 24455b28f9fSOndrej Zary struct scsi_cmnd *tmp_cmd; 2451da177e4SLinus Torvalds int flag; 246e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 247e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds #ifdef DEBUG 2501da177e4SLinus Torvalds { 251c2532f68SOndrej Zary flag = inb(INTRFLAGS(sh->io_port)); 2522906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: "); 2531da177e4SLinus Torvalds if (!(flag & ANYINTR)) 2541da177e4SLinus Torvalds printk("no interrupt?"); 2551da177e4SLinus Torvalds if (flag & MBIF) 2561da177e4SLinus Torvalds printk("MBIF "); 2571da177e4SLinus Torvalds if (flag & MBOA) 2581da177e4SLinus Torvalds printk("MBOF "); 2591da177e4SLinus Torvalds if (flag & HACC) 2601da177e4SLinus Torvalds printk("HACC "); 2611da177e4SLinus Torvalds if (flag & SCRD) 2621da177e4SLinus Torvalds printk("SCRD "); 263c2532f68SOndrej Zary printk("status %02x\n", inb(STATUS(sh->io_port))); 2641da177e4SLinus Torvalds }; 2651da177e4SLinus Torvalds #endif 2661da177e4SLinus Torvalds number_serviced = 0; 2671da177e4SLinus Torvalds 2681b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 2691b0224b0SOndrej Zary while (1) { 270c2532f68SOndrej Zary flag = inb(INTRFLAGS(sh->io_port)); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds /* Check for unusual interrupts. If any of these happen, we should 2731da177e4SLinus Torvalds probably do something special, but for now just printing a message 2741da177e4SLinus Torvalds is sufficient. A SCSI reset detected is something that we really 2751da177e4SLinus Torvalds need to deal with in some way. */ 2761da177e4SLinus Torvalds if (flag & ~MBIF) { 2771da177e4SLinus Torvalds if (flag & MBOA) 2781da177e4SLinus Torvalds printk("MBOF "); 2791da177e4SLinus Torvalds if (flag & HACC) 2801da177e4SLinus Torvalds printk("HACC "); 281dfd7c991SOndrej Zary if (flag & SCRD) 2821da177e4SLinus Torvalds printk("SCRD "); 2831da177e4SLinus Torvalds } 284c2532f68SOndrej Zary aha1542_intr_reset(sh->io_port); 2851da177e4SLinus Torvalds 286e98878f7SOndrej Zary mbi = aha1542->aha1542_last_mbi_used + 1; 2871da177e4SLinus Torvalds if (mbi >= 2 * AHA1542_MAILBOXES) 2881da177e4SLinus Torvalds mbi = AHA1542_MAILBOXES; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds do { 2911da177e4SLinus Torvalds if (mb[mbi].status != 0) 2921da177e4SLinus Torvalds break; 2931da177e4SLinus Torvalds mbi++; 2941da177e4SLinus Torvalds if (mbi >= 2 * AHA1542_MAILBOXES) 2951da177e4SLinus Torvalds mbi = AHA1542_MAILBOXES; 296e98878f7SOndrej Zary } while (mbi != aha1542->aha1542_last_mbi_used); 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds if (mb[mbi].status == 0) { 2991b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 3001da177e4SLinus Torvalds /* Hmm, no mail. Must have read it the last time around */ 301dfd7c991SOndrej Zary if (!number_serviced) 3022906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n"); 3031b0224b0SOndrej Zary return IRQ_HANDLED; 3041da177e4SLinus Torvalds }; 3051da177e4SLinus Torvalds 30610be6250SOndrej Zary mbo = (scsi2int(mb[mbi].ccbptr) - (isa_virt_to_bus(&ccb[0]))) / sizeof(struct ccb); 3071da177e4SLinus Torvalds mbistatus = mb[mbi].status; 3081da177e4SLinus Torvalds mb[mbi].status = 0; 309e98878f7SOndrej Zary aha1542->aha1542_last_mbi_used = mbi; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds #ifdef DEBUG 3121da177e4SLinus Torvalds if (ccb[mbo].tarstat | ccb[mbo].hastat) 3132906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n", 3141da177e4SLinus Torvalds ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status); 3151da177e4SLinus Torvalds #endif 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds if (mbistatus == 3) 3181da177e4SLinus Torvalds continue; /* Aborted command not found */ 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds #ifdef DEBUG 3212906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi); 3221da177e4SLinus Torvalds #endif 3231da177e4SLinus Torvalds 32455b28f9fSOndrej Zary tmp_cmd = aha1542->int_cmds[mbo]; 3251da177e4SLinus Torvalds 32655b28f9fSOndrej Zary if (!tmp_cmd || !tmp_cmd->scsi_done) { 3271b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 3282906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n"); 3292906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat, 3301da177e4SLinus Torvalds ccb[mbo].hastat, ccb[mbo].idlun, mbo); 3311b0224b0SOndrej Zary return IRQ_HANDLED; 3321da177e4SLinus Torvalds } 33355b28f9fSOndrej Zary my_done = tmp_cmd->scsi_done; 33455b28f9fSOndrej Zary kfree(tmp_cmd->host_scribble); 33555b28f9fSOndrej Zary tmp_cmd->host_scribble = NULL; 3361da177e4SLinus Torvalds /* Fetch the sense data, and tuck it away, in the required slot. The 3371da177e4SLinus Torvalds Adaptec automatically fetches it, and there is no guarantee that 3381da177e4SLinus Torvalds we will still have it in the cdb when we come back */ 3391da177e4SLinus Torvalds if (ccb[mbo].tarstat == 2) 34055b28f9fSOndrej Zary memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], 341b80ca4f7SFUJITA Tomonori SCSI_SENSE_BUFFERSIZE); 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds /* is there mail :-) */ 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds /* more error checking left out here */ 3471da177e4SLinus Torvalds if (mbistatus != 1) 3481da177e4SLinus Torvalds /* This is surely wrong, but I don't know what's right */ 3491da177e4SLinus Torvalds errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); 3501da177e4SLinus Torvalds else 3511da177e4SLinus Torvalds errstatus = 0; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds #ifdef DEBUG 3541da177e4SLinus Torvalds if (errstatus) 3552906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus, 3561da177e4SLinus Torvalds ccb[mbo].hastat, ccb[mbo].tarstat); 3576ddc8cf4SOndrej Zary if (ccb[mbo].tarstat == 2) 3586ddc8cf4SOndrej Zary print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12); 359fde1fb8aSOndrej Zary if (errstatus) 360fde1fb8aSOndrej Zary printk("aha1542_intr_handle: returning %6x\n", errstatus); 361fde1fb8aSOndrej Zary #endif 36255b28f9fSOndrej Zary tmp_cmd->result = errstatus; 36355b28f9fSOndrej Zary aha1542->int_cmds[mbo] = NULL; /* This effectively frees up the mailbox slot, as 3641da177e4SLinus Torvalds far as queuecommand is concerned */ 36555b28f9fSOndrej Zary my_done(tmp_cmd); 3661da177e4SLinus Torvalds number_serviced++; 3671da177e4SLinus Torvalds }; 3681da177e4SLinus Torvalds } 3691da177e4SLinus Torvalds 3701b0224b0SOndrej Zary static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) 37109a44833SOndrej Zary { 3722906b3ceSOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 373cb5b570cSOndrej Zary u8 direction; 37455b28f9fSOndrej Zary u8 target = cmd->device->id; 37555b28f9fSOndrej Zary u8 lun = cmd->device->lun; 3761da177e4SLinus Torvalds unsigned long flags; 37755b28f9fSOndrej Zary int bufflen = scsi_bufflen(cmd); 3781da177e4SLinus Torvalds int mbo; 379e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 380e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 3811da177e4SLinus Torvalds 38255b28f9fSOndrej Zary if (*cmd->cmnd == REQUEST_SENSE) { 3831da177e4SLinus Torvalds /* Don't do the command - we have the sense data already */ 38455b28f9fSOndrej Zary cmd->result = 0; 3851b0224b0SOndrej Zary cmd->scsi_done(cmd); 3861da177e4SLinus Torvalds return 0; 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds #ifdef DEBUG 389764a0c7eSOndrej Zary { 390764a0c7eSOndrej Zary int i = -1; 39155b28f9fSOndrej Zary if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10) 39255b28f9fSOndrej Zary i = xscsi2int(cmd->cmnd + 2); 39355b28f9fSOndrej Zary else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6) 39455b28f9fSOndrej Zary i = scsi2int(cmd->cmnd + 2); 395764a0c7eSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d", 396764a0c7eSOndrej Zary target, *cmd->cmnd, i, bufflen); 3976ddc8cf4SOndrej Zary print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len); 398764a0c7eSOndrej Zary } 3991da177e4SLinus Torvalds #endif 4001da177e4SLinus Torvalds /* Use the outgoing mailboxes in a round-robin fashion, because this 4011da177e4SLinus Torvalds is how the host adapter will scan for them */ 4021da177e4SLinus Torvalds 4031b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 404e98878f7SOndrej Zary mbo = aha1542->aha1542_last_mbo_used + 1; 4051da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 4061da177e4SLinus Torvalds mbo = 0; 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds do { 40955b28f9fSOndrej Zary if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) 4101da177e4SLinus Torvalds break; 4111da177e4SLinus Torvalds mbo++; 4121da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 4131da177e4SLinus Torvalds mbo = 0; 414e98878f7SOndrej Zary } while (mbo != aha1542->aha1542_last_mbo_used); 4151da177e4SLinus Torvalds 41655b28f9fSOndrej Zary if (mb[mbo].status || aha1542->int_cmds[mbo]) 4171da177e4SLinus Torvalds panic("Unable to find empty mailbox for aha1542.\n"); 4181da177e4SLinus Torvalds 41955b28f9fSOndrej Zary aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from 4201da177e4SLinus Torvalds screwing with this cdb. */ 4211da177e4SLinus Torvalds 422e98878f7SOndrej Zary aha1542->aha1542_last_mbo_used = mbo; 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds #ifdef DEBUG 4251b0224b0SOndrej Zary shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done); 4261da177e4SLinus Torvalds #endif 4271da177e4SLinus Torvalds 42810be6250SOndrej Zary any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */ 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds memset(&ccb[mbo], 0, sizeof(struct ccb)); 4311da177e4SLinus Torvalds 43255b28f9fSOndrej Zary ccb[mbo].cdblen = cmd->cmd_len; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds direction = 0; 43555b28f9fSOndrej Zary if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6) 4361da177e4SLinus Torvalds direction = 8; 43755b28f9fSOndrej Zary else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6) 4381da177e4SLinus Torvalds direction = 16; 4391da177e4SLinus Torvalds 44055b28f9fSOndrej Zary memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen); 4411da177e4SLinus Torvalds 442fc3fdfccSBoaz Harrosh if (bufflen) { 44351cf2249SJens Axboe struct scatterlist *sg; 4441da177e4SLinus Torvalds struct chain *cptr; 44555b28f9fSOndrej Zary int i, sg_count = scsi_sg_count(cmd); 4466ddc8cf4SOndrej Zary 4471da177e4SLinus Torvalds ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ 44855b28f9fSOndrej Zary cmd->host_scribble = kmalloc(sizeof(*cptr)*sg_count, 449fc3fdfccSBoaz Harrosh GFP_KERNEL | GFP_DMA); 45055b28f9fSOndrej Zary cptr = (struct chain *) cmd->host_scribble; 4511da177e4SLinus Torvalds if (cptr == NULL) { 4521da177e4SLinus Torvalds /* free the claimed mailbox slot */ 45355b28f9fSOndrej Zary aha1542->int_cmds[mbo] = NULL; 4541b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 4551da177e4SLinus Torvalds return SCSI_MLQUEUE_HOST_BUSY; 4561da177e4SLinus Torvalds } 45755b28f9fSOndrej Zary scsi_for_each_sg(cmd, sg, sg_count, i) { 45810be6250SOndrej Zary any2scsi(cptr[i].dataptr, isa_page_to_bus(sg_page(sg)) 45910be6250SOndrej Zary + sg->offset); 46051cf2249SJens Axboe any2scsi(cptr[i].datalen, sg->length); 4611da177e4SLinus Torvalds }; 462fc3fdfccSBoaz Harrosh any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); 46310be6250SOndrej Zary any2scsi(ccb[mbo].dataptr, isa_virt_to_bus(cptr)); 4641da177e4SLinus Torvalds #ifdef DEBUG 4656ddc8cf4SOndrej Zary shost_printk(KERN_DEBUG, sh, "cptr %p: ", cptr); 4666ddc8cf4SOndrej Zary print_hex_dump_bytes("cptr: ", DUMP_PREFIX_NONE, cptr, 18); 4671da177e4SLinus Torvalds #endif 4681da177e4SLinus Torvalds } else { 4691da177e4SLinus Torvalds ccb[mbo].op = 0; /* SCSI Initiator Command */ 47055b28f9fSOndrej Zary cmd->host_scribble = NULL; 471fc3fdfccSBoaz Harrosh any2scsi(ccb[mbo].datalen, 0); 472fc3fdfccSBoaz Harrosh any2scsi(ccb[mbo].dataptr, 0); 4731da177e4SLinus Torvalds }; 4741da177e4SLinus Torvalds ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */ 4751da177e4SLinus Torvalds ccb[mbo].rsalen = 16; 4761da177e4SLinus Torvalds ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; 4771da177e4SLinus Torvalds ccb[mbo].commlinkid = 0; 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds #ifdef DEBUG 4806ddc8cf4SOndrej Zary print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10); 481fde1fb8aSOndrej Zary printk("aha1542_queuecommand: now waiting for interrupt "); 482fde1fb8aSOndrej Zary #endif 4831da177e4SLinus Torvalds mb[mbo].status = 1; 48455b28f9fSOndrej Zary aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI); 4851b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds return 0; 4881da177e4SLinus Torvalds } 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds /* Initialize mailboxes */ 49168ea9de3SOndrej Zary static void setup_mailboxes(struct Scsi_Host *sh) 4921da177e4SLinus Torvalds { 493c2532f68SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 4941da177e4SLinus Torvalds int i; 495e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 496e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 4971da177e4SLinus Torvalds 498cad2fc72SOndrej Zary u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds for (i = 0; i < AHA1542_MAILBOXES; i++) { 5011da177e4SLinus Torvalds mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0; 50210be6250SOndrej Zary any2scsi(mb[i].ccbptr, isa_virt_to_bus(&ccb[i])); 5031da177e4SLinus Torvalds }; 50468ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ 505cad2fc72SOndrej Zary any2scsi((mb_cmd + 2), isa_virt_to_bus(mb)); 50668ea9de3SOndrej Zary if (aha1542_out(sh->io_port, mb_cmd, 5)) 5072906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n"); 50868ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 5091da177e4SLinus Torvalds } 5101da177e4SLinus Torvalds 51168ea9de3SOndrej Zary static int aha1542_getconfig(struct Scsi_Host *sh) 5121da177e4SLinus Torvalds { 513cb5b570cSOndrej Zary u8 inquiry_result[3]; 5141da177e4SLinus Torvalds int i; 51568ea9de3SOndrej Zary i = inb(STATUS(sh->io_port)); 5161da177e4SLinus Torvalds if (i & DF) { 51768ea9de3SOndrej Zary i = inb(DATA(sh->io_port)); 5181da177e4SLinus Torvalds }; 51968ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_RETCONF); 52068ea9de3SOndrej Zary aha1542_in(sh->io_port, inquiry_result, 3, 0); 52168ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) 5222906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "error querying board settings\n"); 52368ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 5241da177e4SLinus Torvalds switch (inquiry_result[0]) { 5251da177e4SLinus Torvalds case 0x80: 52668ea9de3SOndrej Zary sh->dma_channel = 7; 5271da177e4SLinus Torvalds break; 5281da177e4SLinus Torvalds case 0x40: 52968ea9de3SOndrej Zary sh->dma_channel = 6; 5301da177e4SLinus Torvalds break; 5311da177e4SLinus Torvalds case 0x20: 53268ea9de3SOndrej Zary sh->dma_channel = 5; 5331da177e4SLinus Torvalds break; 5341da177e4SLinus Torvalds case 0x01: 53568ea9de3SOndrej Zary sh->dma_channel = 0; 5361da177e4SLinus Torvalds break; 5371da177e4SLinus Torvalds case 0: 5381da177e4SLinus Torvalds /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel. 5391da177e4SLinus Torvalds Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */ 54068ea9de3SOndrej Zary sh->dma_channel = 0xFF; 5411da177e4SLinus Torvalds break; 5421da177e4SLinus Torvalds default: 5432906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n"); 5441da177e4SLinus Torvalds return -1; 5451da177e4SLinus Torvalds }; 5461da177e4SLinus Torvalds switch (inquiry_result[1]) { 5471da177e4SLinus Torvalds case 0x40: 54868ea9de3SOndrej Zary sh->irq = 15; 5491da177e4SLinus Torvalds break; 5501da177e4SLinus Torvalds case 0x20: 55168ea9de3SOndrej Zary sh->irq = 14; 5521da177e4SLinus Torvalds break; 5531da177e4SLinus Torvalds case 0x8: 55468ea9de3SOndrej Zary sh->irq = 12; 5551da177e4SLinus Torvalds break; 5561da177e4SLinus Torvalds case 0x4: 55768ea9de3SOndrej Zary sh->irq = 11; 5581da177e4SLinus Torvalds break; 5591da177e4SLinus Torvalds case 0x2: 56068ea9de3SOndrej Zary sh->irq = 10; 5611da177e4SLinus Torvalds break; 5621da177e4SLinus Torvalds case 0x1: 56368ea9de3SOndrej Zary sh->irq = 9; 5641da177e4SLinus Torvalds break; 5651da177e4SLinus Torvalds default: 5662906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n"); 5671da177e4SLinus Torvalds return -1; 5681da177e4SLinus Torvalds }; 56968ea9de3SOndrej Zary sh->this_id = inquiry_result[2] & 7; 5701da177e4SLinus Torvalds return 0; 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds /* This function should only be called for 1542C boards - we can detect 5741da177e4SLinus Torvalds the special firmware settings and unlock the board */ 5751da177e4SLinus Torvalds 57668ea9de3SOndrej Zary static int aha1542_mbenable(struct Scsi_Host *sh) 5771da177e4SLinus Torvalds { 578cb5b570cSOndrej Zary static u8 mbenable_cmd[3]; 579cb5b570cSOndrej Zary static u8 mbenable_result[2]; 5801da177e4SLinus Torvalds int retval; 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds retval = BIOS_TRANSLATION_6432; 5831da177e4SLinus Torvalds 58468ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_EXTBIOS); 58568ea9de3SOndrej Zary if (aha1542_in(sh->io_port, mbenable_result, 2, 100)) 5861da177e4SLinus Torvalds return retval; 58768ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100)) 5882093bfa1SOndrej Zary goto fail; 58968ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds if ((mbenable_result[0] & 0x08) || mbenable_result[1]) { 5921da177e4SLinus Torvalds mbenable_cmd[0] = CMD_MBENABLE; 5931da177e4SLinus Torvalds mbenable_cmd[1] = 0; 5941da177e4SLinus Torvalds mbenable_cmd[2] = mbenable_result[1]; 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03)) 5971da177e4SLinus Torvalds retval = BIOS_TRANSLATION_25563; 5981da177e4SLinus Torvalds 59968ea9de3SOndrej Zary if (aha1542_out(sh->io_port, mbenable_cmd, 3)) 6002093bfa1SOndrej Zary goto fail; 6011da177e4SLinus Torvalds }; 6021da177e4SLinus Torvalds while (0) { 6031da177e4SLinus Torvalds fail: 6042906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Mailbox init failed\n"); 6051da177e4SLinus Torvalds } 60668ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6071da177e4SLinus Torvalds return retval; 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds /* Query the board to find out if it is a 1542 or a 1740, or whatever. */ 61168ea9de3SOndrej Zary static int aha1542_query(struct Scsi_Host *sh) 6121da177e4SLinus Torvalds { 61368ea9de3SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 614cb5b570cSOndrej Zary u8 inquiry_result[4]; 6151da177e4SLinus Torvalds int i; 61668ea9de3SOndrej Zary i = inb(STATUS(sh->io_port)); 6171da177e4SLinus Torvalds if (i & DF) { 61868ea9de3SOndrej Zary i = inb(DATA(sh->io_port)); 6191da177e4SLinus Torvalds }; 62068ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_INQUIRY); 62168ea9de3SOndrej Zary aha1542_in(sh->io_port, inquiry_result, 4, 0); 62268ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) 6232906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "error querying card type\n"); 62468ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6251da177e4SLinus Torvalds 62668ea9de3SOndrej Zary aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */ 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds /* For an AHA1740 series board, we ignore the board since there is a 6291da177e4SLinus Torvalds hardware bug which can lead to wrong blocks being returned if the board 6301da177e4SLinus Torvalds is operating in the 1542 emulation mode. Since there is an extended mode 6311da177e4SLinus Torvalds driver, we simply ignore the board and let the 1740 driver pick it up. 6321da177e4SLinus Torvalds */ 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds if (inquiry_result[0] == 0x43) { 6352906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n"); 6361da177e4SLinus Torvalds return 1; 6371da177e4SLinus Torvalds }; 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds /* Always call this - boards that do not support extended bios translation 6401da177e4SLinus Torvalds will ignore the command, and we will set the proper default */ 6411da177e4SLinus Torvalds 64268ea9de3SOndrej Zary aha1542->bios_translation = aha1542_mbenable(sh); 6431da177e4SLinus Torvalds 6441da177e4SLinus Torvalds return 0; 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds 647f71429abSOndrej Zary static u8 dma_speed_hw(int dma_speed) 6481da177e4SLinus Torvalds { 649f71429abSOndrej Zary switch (dma_speed) { 6501da177e4SLinus Torvalds case 5: 651f71429abSOndrej Zary return 0x00; 6521da177e4SLinus Torvalds case 6: 653f71429abSOndrej Zary return 0x04; 6541da177e4SLinus Torvalds case 7: 655f71429abSOndrej Zary return 0x01; 6561da177e4SLinus Torvalds case 8: 657f71429abSOndrej Zary return 0x02; 6581da177e4SLinus Torvalds case 10: 659f71429abSOndrej Zary return 0x03; 6601da177e4SLinus Torvalds } 6611da177e4SLinus Torvalds 662f71429abSOndrej Zary return 0xff; /* invalid */ 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds 665b847fd0dSOndrej Zary /* Set the Bus on/off-times as not to ruin floppy performance */ 66637d607bdSOndrej Zary static void aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed) 667b847fd0dSOndrej Zary { 66837d607bdSOndrej Zary if (bus_on > 0) { 66937d607bdSOndrej Zary u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) }; 670b847fd0dSOndrej Zary 67137d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 67237d607bdSOndrej Zary if (aha1542_out(sh->io_port, oncmd, 2)) 673b847fd0dSOndrej Zary goto fail; 674f71429abSOndrej Zary } 675f71429abSOndrej Zary 67637d607bdSOndrej Zary if (bus_off > 0) { 67737d607bdSOndrej Zary u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) }; 678f71429abSOndrej Zary 67937d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 68037d607bdSOndrej Zary if (aha1542_out(sh->io_port, offcmd, 2)) 681b847fd0dSOndrej Zary goto fail; 682f71429abSOndrej Zary } 683f71429abSOndrej Zary 68437d607bdSOndrej Zary if (dma_speed_hw(dma_speed) != 0xff) { 68537d607bdSOndrej Zary u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) }; 686f71429abSOndrej Zary 68737d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 68837d607bdSOndrej Zary if (aha1542_out(sh->io_port, dmacmd, 2)) 689b847fd0dSOndrej Zary goto fail; 690b847fd0dSOndrej Zary } 69137d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 692b847fd0dSOndrej Zary return; 693b847fd0dSOndrej Zary fail: 6942906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n"); 69537d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 696b847fd0dSOndrej Zary } 697b847fd0dSOndrej Zary 6981da177e4SLinus Torvalds /* return non-zero on detection */ 699643a7c43SOndrej Zary static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx) 7001da177e4SLinus Torvalds { 701f71429abSOndrej Zary unsigned int base_io = io[indx]; 702c2532f68SOndrej Zary struct Scsi_Host *sh; 703e98878f7SOndrej Zary struct aha1542_hostdata *aha1542; 7042906b3ceSOndrej Zary char dma_info[] = "no DMA"; 7051da177e4SLinus Torvalds 7063a70c006SOndrej Zary if (base_io == 0) 707643a7c43SOndrej Zary return NULL; 7081da177e4SLinus Torvalds 7093a70c006SOndrej Zary if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542")) 7103a70c006SOndrej Zary return NULL; 7113a70c006SOndrej Zary 712c2532f68SOndrej Zary sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata)); 713c2532f68SOndrej Zary if (!sh) 7143a70c006SOndrej Zary goto release; 715c2532f68SOndrej Zary aha1542 = shost_priv(sh); 7163a70c006SOndrej Zary 71768ea9de3SOndrej Zary sh->unique_id = base_io; 71868ea9de3SOndrej Zary sh->io_port = base_io; 71968ea9de3SOndrej Zary sh->n_io_port = AHA1542_REGION_SIZE; 72068ea9de3SOndrej Zary aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1; 72168ea9de3SOndrej Zary aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1; 72268ea9de3SOndrej Zary 72368ea9de3SOndrej Zary if (!aha1542_test_port(sh)) 7243a70c006SOndrej Zary goto unregister; 7251da177e4SLinus Torvalds 72637d607bdSOndrej Zary aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]); 72768ea9de3SOndrej Zary if (aha1542_query(sh)) 7283a70c006SOndrej Zary goto unregister; 72968ea9de3SOndrej Zary if (aha1542_getconfig(sh) == -1) 7301da177e4SLinus Torvalds goto unregister; 7311da177e4SLinus Torvalds 732c2532f68SOndrej Zary if (sh->dma_channel != 0xFF) 7332906b3ceSOndrej Zary snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel); 7342906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n", 7352906b3ceSOndrej Zary sh->this_id, base_io, sh->irq, dma_info); 7363a70c006SOndrej Zary if (aha1542->bios_translation == BIOS_TRANSLATION_25563) 7372906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Using extended bios translation\n"); 7381da177e4SLinus Torvalds 73968ea9de3SOndrej Zary setup_mailboxes(sh); 7401da177e4SLinus Torvalds 7411b0224b0SOndrej Zary if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) { 7422906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n"); 7431da177e4SLinus Torvalds goto unregister; 7441da177e4SLinus Torvalds } 745c2532f68SOndrej Zary if (sh->dma_channel != 0xFF) { 746c2532f68SOndrej Zary if (request_dma(sh->dma_channel, "aha1542")) { 7472906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n"); 7483a70c006SOndrej Zary goto free_irq; 7491da177e4SLinus Torvalds } 750c2532f68SOndrej Zary if (sh->dma_channel == 0 || sh->dma_channel >= 5) { 751c2532f68SOndrej Zary set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE); 752c2532f68SOndrej Zary enable_dma(sh->dma_channel); 7531da177e4SLinus Torvalds } 7541da177e4SLinus Torvalds } 75587c4d7bcSJeff Garzik 756c2532f68SOndrej Zary if (scsi_add_host(sh, pdev)) 7573a70c006SOndrej Zary goto free_dma; 7581da177e4SLinus Torvalds 759c2532f68SOndrej Zary scsi_scan_host(sh); 7601da177e4SLinus Torvalds 761c2532f68SOndrej Zary return sh; 7623a70c006SOndrej Zary free_dma: 763c2532f68SOndrej Zary if (sh->dma_channel != 0xff) 764c2532f68SOndrej Zary free_dma(sh->dma_channel); 7653a70c006SOndrej Zary free_irq: 766c2532f68SOndrej Zary free_irq(sh->irq, sh); 7671da177e4SLinus Torvalds unregister: 768c2532f68SOndrej Zary scsi_host_put(sh); 7693a70c006SOndrej Zary release: 7703a70c006SOndrej Zary release_region(base_io, AHA1542_REGION_SIZE); 7711da177e4SLinus Torvalds 772643a7c43SOndrej Zary return NULL; 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds 775c2532f68SOndrej Zary static int aha1542_release(struct Scsi_Host *sh) 7761da177e4SLinus Torvalds { 777c2532f68SOndrej Zary scsi_remove_host(sh); 778c2532f68SOndrej Zary if (sh->dma_channel != 0xff) 779c2532f68SOndrej Zary free_dma(sh->dma_channel); 780c2532f68SOndrej Zary if (sh->irq) 781c2532f68SOndrej Zary free_irq(sh->irq, sh); 782c2532f68SOndrej Zary if (sh->io_port && sh->n_io_port) 783c2532f68SOndrej Zary release_region(sh->io_port, sh->n_io_port); 784c2532f68SOndrej Zary scsi_host_put(sh); 7851da177e4SLinus Torvalds return 0; 7861da177e4SLinus Torvalds } 7871da177e4SLinus Torvalds 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds /* 7901da177e4SLinus Torvalds * This is a device reset. This is handled by sending a special command 7911da177e4SLinus Torvalds * to the device. 7921da177e4SLinus Torvalds */ 79355b28f9fSOndrej Zary static int aha1542_dev_reset(struct scsi_cmnd *cmd) 7941da177e4SLinus Torvalds { 7951b0224b0SOndrej Zary struct Scsi_Host *sh = cmd->device->host; 7961b0224b0SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 7971da177e4SLinus Torvalds unsigned long flags; 798e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 79955b28f9fSOndrej Zary u8 target = cmd->device->id; 80055b28f9fSOndrej Zary u8 lun = cmd->device->lun; 8011da177e4SLinus Torvalds int mbo; 802e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 8031da177e4SLinus Torvalds 8041b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 805e98878f7SOndrej Zary mbo = aha1542->aha1542_last_mbo_used + 1; 8061da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 8071da177e4SLinus Torvalds mbo = 0; 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds do { 81055b28f9fSOndrej Zary if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) 8111da177e4SLinus Torvalds break; 8121da177e4SLinus Torvalds mbo++; 8131da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 8141da177e4SLinus Torvalds mbo = 0; 815e98878f7SOndrej Zary } while (mbo != aha1542->aha1542_last_mbo_used); 8161da177e4SLinus Torvalds 81755b28f9fSOndrej Zary if (mb[mbo].status || aha1542->int_cmds[mbo]) 8181da177e4SLinus Torvalds panic("Unable to find empty mailbox for aha1542.\n"); 8191da177e4SLinus Torvalds 82055b28f9fSOndrej Zary aha1542->int_cmds[mbo] = cmd; /* This will effectively 8211da177e4SLinus Torvalds prevent someone else from 8221da177e4SLinus Torvalds screwing with this cdb. */ 8231da177e4SLinus Torvalds 824e98878f7SOndrej Zary aha1542->aha1542_last_mbo_used = mbo; 8251da177e4SLinus Torvalds 82610be6250SOndrej Zary any2scsi(mb[mbo].ccbptr, isa_virt_to_bus(&ccb[mbo])); /* This gets trashed for some reason */ 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds memset(&ccb[mbo], 0, sizeof(struct ccb)); 8291da177e4SLinus Torvalds 8301da177e4SLinus Torvalds ccb[mbo].op = 0x81; /* BUS DEVICE RESET */ 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */ 8331da177e4SLinus Torvalds 8341da177e4SLinus Torvalds ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; 8351da177e4SLinus Torvalds ccb[mbo].commlinkid = 0; 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds /* 8381da177e4SLinus Torvalds * Now tell the 1542 to flush all pending commands for this 8391da177e4SLinus Torvalds * target 8401da177e4SLinus Torvalds */ 8411b0224b0SOndrej Zary aha1542_outb(sh->io_port, CMD_START_SCSI); 8421b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 8431da177e4SLinus Torvalds 84455b28f9fSOndrej Zary scmd_printk(KERN_WARNING, cmd, 845017560fcSJeff Garzik "Trying device reset for target\n"); 8461da177e4SLinus Torvalds 8471da177e4SLinus Torvalds return SUCCESS; 8481da177e4SLinus Torvalds } 8491da177e4SLinus Torvalds 85055b28f9fSOndrej Zary static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd) 8511da177e4SLinus Torvalds { 8521b0224b0SOndrej Zary struct Scsi_Host *sh = cmd->device->host; 8531b0224b0SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 8541b0224b0SOndrej Zary unsigned long flags; 8551da177e4SLinus Torvalds int i; 8561da177e4SLinus Torvalds 8571b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 8581da177e4SLinus Torvalds /* 8591da177e4SLinus Torvalds * This does a scsi reset for all devices on the bus. 8601da177e4SLinus Torvalds * In principle, we could also reset the 1542 - should 8611da177e4SLinus Torvalds * we do this? Try this first, and we can add that later 8621da177e4SLinus Torvalds * if it turns out to be useful. 8631da177e4SLinus Torvalds */ 86455b28f9fSOndrej Zary outb(reset_cmd, CONTROL(cmd->device->host->io_port)); 8651da177e4SLinus Torvalds 86655b28f9fSOndrej Zary if (!wait_mask(STATUS(cmd->device->host->io_port), 8677061dec4SOndrej Zary STATMASK, IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) { 8681b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 869a13b3722SOndrej Zary return FAILED; 870a13b3722SOndrej Zary } 8711b0224b0SOndrej Zary 8721da177e4SLinus Torvalds /* 8731da177e4SLinus Torvalds * We need to do this too before the 1542 can interact with 8748537cba8SOndrej Zary * us again after host reset. 8751da177e4SLinus Torvalds */ 8768537cba8SOndrej Zary if (reset_cmd & HRST) 87768ea9de3SOndrej Zary setup_mailboxes(cmd->device->host); 8781b0224b0SOndrej Zary 8791da177e4SLinus Torvalds /* 8801da177e4SLinus Torvalds * Now try to pick up the pieces. For all pending commands, 8811da177e4SLinus Torvalds * free any internal data structures, and basically clear things 8821da177e4SLinus Torvalds * out. We do not try and restart any commands or anything - 8831da177e4SLinus Torvalds * the strategy handler takes care of that crap. 8841da177e4SLinus Torvalds */ 8852906b3ceSOndrej Zary shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no); 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds for (i = 0; i < AHA1542_MAILBOXES; i++) { 88855b28f9fSOndrej Zary if (aha1542->int_cmds[i] != NULL) { 88955b28f9fSOndrej Zary struct scsi_cmnd *tmp_cmd; 89055b28f9fSOndrej Zary tmp_cmd = aha1542->int_cmds[i]; 8911da177e4SLinus Torvalds 89255b28f9fSOndrej Zary if (tmp_cmd->device->soft_reset) { 8931da177e4SLinus Torvalds /* 8941da177e4SLinus Torvalds * If this device implements the soft reset option, 8951da177e4SLinus Torvalds * then it is still holding onto the command, and 8961da177e4SLinus Torvalds * may yet complete it. In this case, we don't 8971da177e4SLinus Torvalds * flush the data. 8981da177e4SLinus Torvalds */ 8991da177e4SLinus Torvalds continue; 9001da177e4SLinus Torvalds } 90155b28f9fSOndrej Zary kfree(tmp_cmd->host_scribble); 90255b28f9fSOndrej Zary tmp_cmd->host_scribble = NULL; 90355b28f9fSOndrej Zary aha1542->int_cmds[i] = NULL; 904e98878f7SOndrej Zary aha1542->mb[i].status = 0; 9051da177e4SLinus Torvalds } 9061da177e4SLinus Torvalds } 9071da177e4SLinus Torvalds 9081b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 9091da177e4SLinus Torvalds return SUCCESS; 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds 91255b28f9fSOndrej Zary static int aha1542_bus_reset(struct scsi_cmnd *cmd) 9138537cba8SOndrej Zary { 91455b28f9fSOndrej Zary return aha1542_reset(cmd, SCRST); 9158537cba8SOndrej Zary } 9168537cba8SOndrej Zary 91755b28f9fSOndrej Zary static int aha1542_host_reset(struct scsi_cmnd *cmd) 9188537cba8SOndrej Zary { 91955b28f9fSOndrej Zary return aha1542_reset(cmd, HRST | SCRST); 9208537cba8SOndrej Zary } 9218537cba8SOndrej Zary 9221da177e4SLinus Torvalds static int aha1542_biosparam(struct scsi_device *sdev, 92317787a09SOndrej Zary struct block_device *bdev, sector_t capacity, int geom[]) 9241da177e4SLinus Torvalds { 925e98878f7SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sdev->host); 9261da177e4SLinus Torvalds 92717787a09SOndrej Zary if (capacity >= 0x200000 && 92817787a09SOndrej Zary aha1542->bios_translation == BIOS_TRANSLATION_25563) { 9291da177e4SLinus Torvalds /* Please verify that this is the same as what DOS returns */ 93017787a09SOndrej Zary geom[0] = 255; /* heads */ 93117787a09SOndrej Zary geom[1] = 63; /* sectors */ 9321da177e4SLinus Torvalds } else { 93317787a09SOndrej Zary geom[0] = 64; /* heads */ 93417787a09SOndrej Zary geom[1] = 32; /* sectors */ 9351da177e4SLinus Torvalds } 93617787a09SOndrej Zary geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */ 9371da177e4SLinus Torvalds 9381da177e4SLinus Torvalds return 0; 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 9411da177e4SLinus Torvalds 942d0be4a7dSChristoph Hellwig static struct scsi_host_template driver_template = { 943643a7c43SOndrej Zary .module = THIS_MODULE, 9441da177e4SLinus Torvalds .proc_name = "aha1542", 9451da177e4SLinus Torvalds .name = "Adaptec 1542", 9461da177e4SLinus Torvalds .queuecommand = aha1542_queuecommand, 9471da177e4SLinus Torvalds .eh_device_reset_handler= aha1542_dev_reset, 9481da177e4SLinus Torvalds .eh_bus_reset_handler = aha1542_bus_reset, 9491da177e4SLinus Torvalds .eh_host_reset_handler = aha1542_host_reset, 9501da177e4SLinus Torvalds .bios_param = aha1542_biosparam, 9511da177e4SLinus Torvalds .can_queue = AHA1542_MAILBOXES, 9521da177e4SLinus Torvalds .this_id = 7, 95310be6250SOndrej Zary .sg_tablesize = 16, 95410be6250SOndrej Zary .cmd_per_lun = 1, 9551da177e4SLinus Torvalds .unchecked_isa_dma = 1, 9561da177e4SLinus Torvalds .use_clustering = ENABLE_CLUSTERING, 9571da177e4SLinus Torvalds }; 958643a7c43SOndrej Zary 959643a7c43SOndrej Zary static int aha1542_isa_match(struct device *pdev, unsigned int ndev) 960643a7c43SOndrej Zary { 961643a7c43SOndrej Zary struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev); 962643a7c43SOndrej Zary 963643a7c43SOndrej Zary if (!sh) 964643a7c43SOndrej Zary return 0; 965643a7c43SOndrej Zary 966643a7c43SOndrej Zary dev_set_drvdata(pdev, sh); 967643a7c43SOndrej Zary return 1; 968643a7c43SOndrej Zary } 969643a7c43SOndrej Zary 970643a7c43SOndrej Zary static int aha1542_isa_remove(struct device *pdev, 971643a7c43SOndrej Zary unsigned int ndev) 972643a7c43SOndrej Zary { 973643a7c43SOndrej Zary aha1542_release(dev_get_drvdata(pdev)); 974643a7c43SOndrej Zary dev_set_drvdata(pdev, NULL); 975643a7c43SOndrej Zary return 0; 976643a7c43SOndrej Zary } 977643a7c43SOndrej Zary 978643a7c43SOndrej Zary static struct isa_driver aha1542_isa_driver = { 979643a7c43SOndrej Zary .match = aha1542_isa_match, 980643a7c43SOndrej Zary .remove = aha1542_isa_remove, 981643a7c43SOndrej Zary .driver = { 982643a7c43SOndrej Zary .name = "aha1542" 983643a7c43SOndrej Zary }, 984643a7c43SOndrej Zary }; 985643a7c43SOndrej Zary static int isa_registered; 986643a7c43SOndrej Zary 987643a7c43SOndrej Zary #ifdef CONFIG_PNP 988643a7c43SOndrej Zary static struct pnp_device_id aha1542_pnp_ids[] = { 989643a7c43SOndrej Zary { .id = "ADP1542" }, 990643a7c43SOndrej Zary { .id = "" } 991643a7c43SOndrej Zary }; 992643a7c43SOndrej Zary MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids); 993643a7c43SOndrej Zary 994643a7c43SOndrej Zary static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id) 995643a7c43SOndrej Zary { 996643a7c43SOndrej Zary int indx; 997643a7c43SOndrej Zary struct Scsi_Host *sh; 998643a7c43SOndrej Zary 999f71429abSOndrej Zary for (indx = 0; indx < ARRAY_SIZE(io); indx++) { 1000f71429abSOndrej Zary if (io[indx]) 1001643a7c43SOndrej Zary continue; 1002643a7c43SOndrej Zary 1003643a7c43SOndrej Zary if (pnp_activate_dev(pdev) < 0) 1004643a7c43SOndrej Zary continue; 1005643a7c43SOndrej Zary 1006f71429abSOndrej Zary io[indx] = pnp_port_start(pdev, 0); 1007643a7c43SOndrej Zary 1008643a7c43SOndrej Zary /* The card can be queried for its DMA, we have 1009643a7c43SOndrej Zary the DMA set up that is enough */ 1010643a7c43SOndrej Zary 10112906b3ceSOndrej Zary dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]); 1012643a7c43SOndrej Zary } 1013643a7c43SOndrej Zary 1014643a7c43SOndrej Zary sh = aha1542_hw_init(&driver_template, &pdev->dev, indx); 1015643a7c43SOndrej Zary if (!sh) 1016643a7c43SOndrej Zary return -ENODEV; 1017643a7c43SOndrej Zary 1018643a7c43SOndrej Zary pnp_set_drvdata(pdev, sh); 1019643a7c43SOndrej Zary return 0; 1020643a7c43SOndrej Zary } 1021643a7c43SOndrej Zary 1022643a7c43SOndrej Zary static void aha1542_pnp_remove(struct pnp_dev *pdev) 1023643a7c43SOndrej Zary { 1024643a7c43SOndrej Zary aha1542_release(pnp_get_drvdata(pdev)); 1025643a7c43SOndrej Zary pnp_set_drvdata(pdev, NULL); 1026643a7c43SOndrej Zary } 1027643a7c43SOndrej Zary 1028643a7c43SOndrej Zary static struct pnp_driver aha1542_pnp_driver = { 1029643a7c43SOndrej Zary .name = "aha1542", 1030643a7c43SOndrej Zary .id_table = aha1542_pnp_ids, 1031643a7c43SOndrej Zary .probe = aha1542_pnp_probe, 1032643a7c43SOndrej Zary .remove = aha1542_pnp_remove, 1033643a7c43SOndrej Zary }; 1034643a7c43SOndrej Zary static int pnp_registered; 1035643a7c43SOndrej Zary #endif /* CONFIG_PNP */ 1036643a7c43SOndrej Zary 1037643a7c43SOndrej Zary static int __init aha1542_init(void) 1038643a7c43SOndrej Zary { 1039643a7c43SOndrej Zary int ret = 0; 1040643a7c43SOndrej Zary 1041643a7c43SOndrej Zary #ifdef CONFIG_PNP 1042643a7c43SOndrej Zary if (isapnp) { 1043643a7c43SOndrej Zary ret = pnp_register_driver(&aha1542_pnp_driver); 1044643a7c43SOndrej Zary if (!ret) 1045643a7c43SOndrej Zary pnp_registered = 1; 1046643a7c43SOndrej Zary } 1047643a7c43SOndrej Zary #endif 1048643a7c43SOndrej Zary ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS); 1049643a7c43SOndrej Zary if (!ret) 1050643a7c43SOndrej Zary isa_registered = 1; 1051643a7c43SOndrej Zary 1052643a7c43SOndrej Zary #ifdef CONFIG_PNP 1053643a7c43SOndrej Zary if (pnp_registered) 1054643a7c43SOndrej Zary ret = 0; 1055643a7c43SOndrej Zary #endif 1056643a7c43SOndrej Zary if (isa_registered) 1057643a7c43SOndrej Zary ret = 0; 1058643a7c43SOndrej Zary 1059643a7c43SOndrej Zary return ret; 1060643a7c43SOndrej Zary } 1061643a7c43SOndrej Zary 1062643a7c43SOndrej Zary static void __exit aha1542_exit(void) 1063643a7c43SOndrej Zary { 1064643a7c43SOndrej Zary #ifdef CONFIG_PNP 1065643a7c43SOndrej Zary if (pnp_registered) 1066643a7c43SOndrej Zary pnp_unregister_driver(&aha1542_pnp_driver); 1067643a7c43SOndrej Zary #endif 1068643a7c43SOndrej Zary if (isa_registered) 1069643a7c43SOndrej Zary isa_unregister_driver(&aha1542_isa_driver); 1070643a7c43SOndrej Zary } 1071643a7c43SOndrej Zary 1072643a7c43SOndrej Zary module_init(aha1542_init); 1073643a7c43SOndrej Zary module_exit(aha1542_exit); 1074