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 682f2fef02SChristoph Hellwig #define AHA1542_MAX_SECTORS 16 692f2fef02SChristoph Hellwig 701794ef2bSChristoph Hellwig struct aha1542_cmd { 712f2fef02SChristoph Hellwig /* bounce buffer */ 722f2fef02SChristoph Hellwig void *data_buffer; 732f2fef02SChristoph Hellwig dma_addr_t data_buffer_handle; 741da177e4SLinus Torvalds }; 751da177e4SLinus Torvalds 76f1bbef63SOndrej Zary static inline void aha1542_intr_reset(u16 base) 77f1bbef63SOndrej Zary { 78f1bbef63SOndrej Zary outb(IRST, CONTROL(base)); 79f1bbef63SOndrej Zary } 801da177e4SLinus Torvalds 812093bfa1SOndrej Zary static inline bool wait_mask(u16 port, u8 mask, u8 allof, u8 noneof, int timeout) 822093bfa1SOndrej Zary { 832093bfa1SOndrej Zary bool delayed = true; 842093bfa1SOndrej Zary 852093bfa1SOndrej Zary if (timeout == 0) { 862093bfa1SOndrej Zary timeout = 3000000; 872093bfa1SOndrej Zary delayed = false; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 902093bfa1SOndrej Zary while (1) { 912093bfa1SOndrej Zary u8 bits = inb(port) & mask; 922093bfa1SOndrej Zary if ((bits & allof) == allof && ((bits & noneof) == 0)) 932093bfa1SOndrej Zary break; 942093bfa1SOndrej Zary if (delayed) 952093bfa1SOndrej Zary mdelay(1); 962093bfa1SOndrej Zary if (--timeout == 0) 972093bfa1SOndrej Zary return false; 982093bfa1SOndrej Zary } 992093bfa1SOndrej Zary 1002093bfa1SOndrej Zary return true; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 103cad2fc72SOndrej Zary static int aha1542_outb(unsigned int base, u8 val) 1041da177e4SLinus Torvalds { 1052906b3ceSOndrej Zary if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) 1060c2b6481SOndrej Zary return 1; 107cad2fc72SOndrej Zary outb(val, DATA(base)); 108eef77801SOndrej Zary 1091da177e4SLinus Torvalds return 0; 1101da177e4SLinus Torvalds } 1110c2b6481SOndrej Zary 112cad2fc72SOndrej Zary static int aha1542_out(unsigned int base, u8 *buf, int len) 1130c2b6481SOndrej Zary { 1141da177e4SLinus Torvalds while (len--) { 1151b0224b0SOndrej Zary if (!wait_mask(STATUS(base), CDF, 0, CDF, 0)) 1161da177e4SLinus Torvalds return 1; 117cad2fc72SOndrej Zary outb(*buf++, DATA(base)); 1180c2b6481SOndrej Zary } 11923e6940aSOndrej Zary if (!wait_mask(INTRFLAGS(base), INTRMASK, HACC, 0, 0)) 12023e6940aSOndrej Zary return 1; 1210c2b6481SOndrej Zary 1220c2b6481SOndrej Zary return 0; 1230c2b6481SOndrej Zary } 1241da177e4SLinus Torvalds 125e4da5febSSergey Shtylyov /* 126e4da5febSSergey Shtylyov * Only used at boot time, so we do not need to worry about latency as much 127e4da5febSSergey Shtylyov * here 128e4da5febSSergey Shtylyov */ 1291da177e4SLinus Torvalds 130cad2fc72SOndrej Zary static int aha1542_in(unsigned int base, u8 *buf, int len, int timeout) 1311da177e4SLinus Torvalds { 1321da177e4SLinus Torvalds while (len--) { 1331b0224b0SOndrej Zary if (!wait_mask(STATUS(base), DF, DF, 0, timeout)) 1341da177e4SLinus Torvalds return 1; 135cad2fc72SOndrej Zary *buf++ = inb(DATA(base)); 136a13b3722SOndrej Zary } 137a13b3722SOndrej Zary return 0; 138a13b3722SOndrej Zary } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds static int makecode(unsigned hosterr, unsigned scsierr) 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds switch (hosterr) { 1431da177e4SLinus Torvalds case 0x0: 1441da177e4SLinus Torvalds case 0xa: /* Linked command complete without error and linked normally */ 1451da177e4SLinus Torvalds case 0xb: /* Linked command complete without error, interrupt generated */ 1461da177e4SLinus Torvalds hosterr = 0; 1471da177e4SLinus Torvalds break; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds case 0x11: /* Selection time out-The initiator selection or target 150e4da5febSSergey Shtylyov * reselection was not complete within the SCSI Time out period 151e4da5febSSergey Shtylyov */ 1521da177e4SLinus Torvalds hosterr = DID_TIME_OUT; 1531da177e4SLinus Torvalds break; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds case 0x12: /* Data overrun/underrun-The target attempted to transfer more data 156e4da5febSSergey Shtylyov * than was allocated by the Data Length field or the sum of the 157e4da5febSSergey Shtylyov * Scatter / Gather Data Length fields. 158e4da5febSSergey Shtylyov */ 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was 163e4da5febSSergey Shtylyov * invalid. This usually indicates a software failure. 164e4da5febSSergey Shtylyov */ 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. 167e4da5febSSergey Shtylyov * This usually indicates a software failure. 168e4da5febSSergey Shtylyov */ 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set 171e4da5febSSergey Shtylyov * of linked CCB's does not specify the same logical unit number as 172e4da5febSSergey Shtylyov * the first. 173e4da5febSSergey Shtylyov */ 1741da177e4SLinus Torvalds case 0x18: /* Invalid Target Direction received from Host-The direction of a 175e4da5febSSergey Shtylyov * Target Mode CCB was invalid. 176e4da5febSSergey Shtylyov */ 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was 179e4da5febSSergey Shtylyov * received to service data transfer between the same target LUN 180e4da5febSSergey Shtylyov * and initiator SCSI ID in the same direction. 181e4da5febSSergey Shtylyov */ 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero 184e4da5febSSergey Shtylyov * length segment or invalid segment list boundaries was received. 185e4da5febSSergey Shtylyov * A CCB parameter was invalid. 186e4da5febSSergey Shtylyov */ 187fde1fb8aSOndrej Zary #ifdef DEBUG 188fde1fb8aSOndrej Zary printk("Aha1542: %x %x\n", hosterr, scsierr); 189fde1fb8aSOndrej Zary #endif 1901da177e4SLinus Torvalds hosterr = DID_ERROR; /* Couldn't find any better */ 1911da177e4SLinus Torvalds break; 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus 194e4da5febSSergey Shtylyov * phase sequence was requested by the target. The host adapter 195e4da5febSSergey Shtylyov * will generate a SCSI Reset Condition, notifying the host with 196e4da5febSSergey Shtylyov * a SCRD interrupt 197e4da5febSSergey Shtylyov */ 1981da177e4SLinus Torvalds hosterr = DID_RESET; 1991da177e4SLinus Torvalds break; 2001da177e4SLinus Torvalds default: 2011da177e4SLinus Torvalds printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr); 2021da177e4SLinus Torvalds break; 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds return scsierr | (hosterr << 16); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 20768ea9de3SOndrej Zary static int aha1542_test_port(struct Scsi_Host *sh) 2081da177e4SLinus Torvalds { 209cad2fc72SOndrej Zary int i; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* Quick and dirty test for presence of the card. */ 21268ea9de3SOndrej Zary if (inb(STATUS(sh->io_port)) == 0xff) 2131da177e4SLinus Torvalds return 0; 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */ 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds /* In case some other card was probing here, reset interrupts */ 21868ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ 2191da177e4SLinus Torvalds 22068ea9de3SOndrej Zary outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port)); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds mdelay(20); /* Wait a little bit for things to settle down. */ 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds /* Expect INIT and IDLE, any of the others are bad */ 22568ea9de3SOndrej Zary if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) 226a13b3722SOndrej Zary return 0; 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds /* Shouldn't have generated any interrupts during reset */ 22968ea9de3SOndrej Zary if (inb(INTRFLAGS(sh->io_port)) & INTRMASK) 230a13b3722SOndrej Zary return 0; 2311da177e4SLinus Torvalds 232e4da5febSSergey Shtylyov /* 233e4da5febSSergey Shtylyov * Perform a host adapter inquiry instead so we do not need to set 234e4da5febSSergey Shtylyov * up the mailboxes ahead of time 235e4da5febSSergey Shtylyov */ 2361da177e4SLinus Torvalds 23768ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_INQUIRY); 2381da177e4SLinus Torvalds 239cad2fc72SOndrej Zary for (i = 0; i < 4; i++) { 24068ea9de3SOndrej Zary if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0)) 241a13b3722SOndrej Zary return 0; 242ea1c9475SBart Van Assche (void)inb(DATA(sh->io_port)); 2431da177e4SLinus Torvalds } 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds /* Reading port should reset DF */ 24668ea9de3SOndrej Zary if (inb(STATUS(sh->io_port)) & DF) 247a13b3722SOndrej Zary return 0; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds /* When HACC, command is completed, and we're though testing */ 25068ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0)) 251a13b3722SOndrej Zary return 0; 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds /* Clear interrupts */ 25468ea9de3SOndrej Zary outb(IRST, CONTROL(sh->io_port)); 2551da177e4SLinus Torvalds 256bdebe224SOndrej Zary return 1; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591794ef2bSChristoph Hellwig static void aha1542_free_cmd(struct scsi_cmnd *cmd) 2601794ef2bSChristoph Hellwig { 2611794ef2bSChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 2621794ef2bSChristoph Hellwig 2632f2fef02SChristoph Hellwig if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 26411bf4ec5SBart Van Assche struct request *rq = scsi_cmd_to_rq(cmd); 2652f2fef02SChristoph Hellwig void *buf = acmd->data_buffer; 2662f2fef02SChristoph Hellwig struct req_iterator iter; 2672f2fef02SChristoph Hellwig struct bio_vec bv; 2682f2fef02SChristoph Hellwig 26911bf4ec5SBart Van Assche rq_for_each_segment(bv, rq, iter) { 270e6ab6113SChristoph Hellwig memcpy_to_bvec(&bv, buf); 2712f2fef02SChristoph Hellwig buf += bv.bv_len; 2722f2fef02SChristoph Hellwig } 2731794ef2bSChristoph Hellwig } 2741794ef2bSChristoph Hellwig 2751794ef2bSChristoph Hellwig scsi_dma_unmap(cmd); 2761794ef2bSChristoph Hellwig } 2771794ef2bSChristoph Hellwig 2781b0224b0SOndrej Zary static irqreturn_t aha1542_interrupt(int irq, void *dev_id) 2791da177e4SLinus Torvalds { 2801b0224b0SOndrej Zary struct Scsi_Host *sh = dev_id; 281c2532f68SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 2821da177e4SLinus Torvalds int errstatus, mbi, mbo, mbistatus; 2831da177e4SLinus Torvalds int number_serviced; 2841da177e4SLinus Torvalds unsigned long flags; 28555b28f9fSOndrej Zary struct scsi_cmnd *tmp_cmd; 2861da177e4SLinus Torvalds int flag; 287e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 288e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds #ifdef DEBUG 2911da177e4SLinus Torvalds { 292c2532f68SOndrej Zary flag = inb(INTRFLAGS(sh->io_port)); 2932906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: "); 2941da177e4SLinus Torvalds if (!(flag & ANYINTR)) 2951da177e4SLinus Torvalds printk("no interrupt?"); 2961da177e4SLinus Torvalds if (flag & MBIF) 2971da177e4SLinus Torvalds printk("MBIF "); 2981da177e4SLinus Torvalds if (flag & MBOA) 2991da177e4SLinus Torvalds printk("MBOF "); 3001da177e4SLinus Torvalds if (flag & HACC) 3011da177e4SLinus Torvalds printk("HACC "); 3021da177e4SLinus Torvalds if (flag & SCRD) 3031da177e4SLinus Torvalds printk("SCRD "); 304c2532f68SOndrej Zary printk("status %02x\n", inb(STATUS(sh->io_port))); 3058c36b054SHaowen Bai } 3061da177e4SLinus Torvalds #endif 3071da177e4SLinus Torvalds number_serviced = 0; 3081da177e4SLinus Torvalds 3091b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 3101b0224b0SOndrej Zary while (1) { 311c2532f68SOndrej Zary flag = inb(INTRFLAGS(sh->io_port)); 3121da177e4SLinus Torvalds 313e4da5febSSergey Shtylyov /* 314e4da5febSSergey Shtylyov * Check for unusual interrupts. If any of these happen, we should 315e4da5febSSergey Shtylyov * probably do something special, but for now just printing a message 316e4da5febSSergey Shtylyov * is sufficient. A SCSI reset detected is something that we really 317e4da5febSSergey Shtylyov * need to deal with in some way. 318e4da5febSSergey Shtylyov */ 3191da177e4SLinus Torvalds if (flag & ~MBIF) { 3201da177e4SLinus Torvalds if (flag & MBOA) 3211da177e4SLinus Torvalds printk("MBOF "); 3221da177e4SLinus Torvalds if (flag & HACC) 3231da177e4SLinus Torvalds printk("HACC "); 324dfd7c991SOndrej Zary if (flag & SCRD) 3251da177e4SLinus Torvalds printk("SCRD "); 3261da177e4SLinus Torvalds } 327c2532f68SOndrej Zary aha1542_intr_reset(sh->io_port); 3281da177e4SLinus Torvalds 329e98878f7SOndrej Zary mbi = aha1542->aha1542_last_mbi_used + 1; 3301da177e4SLinus Torvalds if (mbi >= 2 * AHA1542_MAILBOXES) 3311da177e4SLinus Torvalds mbi = AHA1542_MAILBOXES; 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds do { 3341da177e4SLinus Torvalds if (mb[mbi].status != 0) 3351da177e4SLinus Torvalds break; 3361da177e4SLinus Torvalds mbi++; 3371da177e4SLinus Torvalds if (mbi >= 2 * AHA1542_MAILBOXES) 3381da177e4SLinus Torvalds mbi = AHA1542_MAILBOXES; 339e98878f7SOndrej Zary } while (mbi != aha1542->aha1542_last_mbi_used); 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds if (mb[mbi].status == 0) { 3421b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 3431da177e4SLinus Torvalds /* Hmm, no mail. Must have read it the last time around */ 344dfd7c991SOndrej Zary if (!number_serviced) 3452906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n"); 3461b0224b0SOndrej Zary return IRQ_HANDLED; 3478c36b054SHaowen Bai } 3481da177e4SLinus Torvalds 349492ca4daSJames Bottomley mbo = (scsi2int(mb[mbi].ccbptr) - (unsigned long)aha1542->ccb_handle) / sizeof(struct ccb); 3501da177e4SLinus Torvalds mbistatus = mb[mbi].status; 3511da177e4SLinus Torvalds mb[mbi].status = 0; 352e98878f7SOndrej Zary aha1542->aha1542_last_mbi_used = mbi; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds #ifdef DEBUG 3551da177e4SLinus Torvalds if (ccb[mbo].tarstat | ccb[mbo].hastat) 3562906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n", 3571da177e4SLinus Torvalds ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status); 3581da177e4SLinus Torvalds #endif 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds if (mbistatus == 3) 3611da177e4SLinus Torvalds continue; /* Aborted command not found */ 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds #ifdef DEBUG 3642906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi); 3651da177e4SLinus Torvalds #endif 3661da177e4SLinus Torvalds 36755b28f9fSOndrej Zary tmp_cmd = aha1542->int_cmds[mbo]; 3681da177e4SLinus Torvalds 36913522352SBart Van Assche if (!tmp_cmd) { 3701b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 3712906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n"); 3722906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat, 3731da177e4SLinus Torvalds ccb[mbo].hastat, ccb[mbo].idlun, mbo); 3741b0224b0SOndrej Zary return IRQ_HANDLED; 3751da177e4SLinus Torvalds } 3761794ef2bSChristoph Hellwig aha1542_free_cmd(tmp_cmd); 377e4da5febSSergey Shtylyov /* 378e4da5febSSergey Shtylyov * Fetch the sense data, and tuck it away, in the required slot. The 379e4da5febSSergey Shtylyov * Adaptec automatically fetches it, and there is no guarantee that 380e4da5febSSergey Shtylyov * we will still have it in the cdb when we come back 381e4da5febSSergey Shtylyov */ 3821da177e4SLinus Torvalds if (ccb[mbo].tarstat == 2) 38355b28f9fSOndrej Zary memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], 384b80ca4f7SFUJITA Tomonori SCSI_SENSE_BUFFERSIZE); 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds /* is there mail :-) */ 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds /* more error checking left out here */ 3901da177e4SLinus Torvalds if (mbistatus != 1) 3911da177e4SLinus Torvalds /* This is surely wrong, but I don't know what's right */ 3921da177e4SLinus Torvalds errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); 3931da177e4SLinus Torvalds else 3941da177e4SLinus Torvalds errstatus = 0; 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds #ifdef DEBUG 3971da177e4SLinus Torvalds if (errstatus) 3982906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus, 3991da177e4SLinus Torvalds ccb[mbo].hastat, ccb[mbo].tarstat); 4006ddc8cf4SOndrej Zary if (ccb[mbo].tarstat == 2) 4016ddc8cf4SOndrej Zary print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12); 402fde1fb8aSOndrej Zary if (errstatus) 403fde1fb8aSOndrej Zary printk("aha1542_intr_handle: returning %6x\n", errstatus); 404fde1fb8aSOndrej Zary #endif 40555b28f9fSOndrej Zary tmp_cmd->result = errstatus; 40655b28f9fSOndrej Zary aha1542->int_cmds[mbo] = NULL; /* This effectively frees up the mailbox slot, as 407e4da5febSSergey Shtylyov * far as queuecommand is concerned 408e4da5febSSergey Shtylyov */ 40913522352SBart Van Assche scsi_done(tmp_cmd); 4101da177e4SLinus Torvalds number_serviced++; 4118c36b054SHaowen Bai } 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141b0224b0SOndrej Zary static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) 41509a44833SOndrej Zary { 4161794ef2bSChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 4172906b3ceSOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 418cb5b570cSOndrej Zary u8 direction; 41955b28f9fSOndrej Zary u8 target = cmd->device->id; 42055b28f9fSOndrej Zary u8 lun = cmd->device->lun; 4211da177e4SLinus Torvalds unsigned long flags; 42255b28f9fSOndrej Zary int bufflen = scsi_bufflen(cmd); 4232f2fef02SChristoph Hellwig int mbo; 424e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 425e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 4261da177e4SLinus Torvalds 42755b28f9fSOndrej Zary if (*cmd->cmnd == REQUEST_SENSE) { 4281da177e4SLinus Torvalds /* Don't do the command - we have the sense data already */ 42955b28f9fSOndrej Zary cmd->result = 0; 43013522352SBart Van Assche scsi_done(cmd); 4311da177e4SLinus Torvalds return 0; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds #ifdef DEBUG 434764a0c7eSOndrej Zary { 435764a0c7eSOndrej Zary int i = -1; 43655b28f9fSOndrej Zary if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10) 43755b28f9fSOndrej Zary i = xscsi2int(cmd->cmnd + 2); 43855b28f9fSOndrej Zary else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6) 43955b28f9fSOndrej Zary i = scsi2int(cmd->cmnd + 2); 440764a0c7eSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d", 441764a0c7eSOndrej Zary target, *cmd->cmnd, i, bufflen); 4426ddc8cf4SOndrej Zary print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len); 443764a0c7eSOndrej Zary } 4441da177e4SLinus Torvalds #endif 4451794ef2bSChristoph Hellwig 4462f2fef02SChristoph Hellwig if (cmd->sc_data_direction == DMA_TO_DEVICE) { 44711bf4ec5SBart Van Assche struct request *rq = scsi_cmd_to_rq(cmd); 4482f2fef02SChristoph Hellwig void *buf = acmd->data_buffer; 4492f2fef02SChristoph Hellwig struct req_iterator iter; 4502f2fef02SChristoph Hellwig struct bio_vec bv; 4512f2fef02SChristoph Hellwig 45211bf4ec5SBart Van Assche rq_for_each_segment(bv, rq, iter) { 453e6ab6113SChristoph Hellwig memcpy_from_bvec(buf, &bv); 4542f2fef02SChristoph Hellwig buf += bv.bv_len; 4552f2fef02SChristoph Hellwig } 4568c08a621SOndrej Zary } 4578c08a621SOndrej Zary 458e4da5febSSergey Shtylyov /* 459e4da5febSSergey Shtylyov * Use the outgoing mailboxes in a round-robin fashion, because this 460e4da5febSSergey Shtylyov * is how the host adapter will scan for them 461e4da5febSSergey Shtylyov */ 4621da177e4SLinus Torvalds 4631b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 464e98878f7SOndrej Zary mbo = aha1542->aha1542_last_mbo_used + 1; 4651da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 4661da177e4SLinus Torvalds mbo = 0; 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds do { 46955b28f9fSOndrej Zary if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) 4701da177e4SLinus Torvalds break; 4711da177e4SLinus Torvalds mbo++; 4721da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 4731da177e4SLinus Torvalds mbo = 0; 474e98878f7SOndrej Zary } while (mbo != aha1542->aha1542_last_mbo_used); 4751da177e4SLinus Torvalds 47655b28f9fSOndrej Zary if (mb[mbo].status || aha1542->int_cmds[mbo]) 4771da177e4SLinus Torvalds panic("Unable to find empty mailbox for aha1542.\n"); 4781da177e4SLinus Torvalds 47955b28f9fSOndrej Zary aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from 480e4da5febSSergey Shtylyov * screwing with this cdb. 481e4da5febSSergey Shtylyov */ 4821da177e4SLinus Torvalds 483e98878f7SOndrej Zary aha1542->aha1542_last_mbo_used = mbo; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds #ifdef DEBUG 48613522352SBart Van Assche shost_printk(KERN_DEBUG, sh, "Sending command (%d)...", mbo); 4871da177e4SLinus Torvalds #endif 4881da177e4SLinus Torvalds 4891794ef2bSChristoph Hellwig /* This gets trashed for some reason */ 4901794ef2bSChristoph Hellwig any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds memset(&ccb[mbo], 0, sizeof(struct ccb)); 4931da177e4SLinus Torvalds 49455b28f9fSOndrej Zary ccb[mbo].cdblen = cmd->cmd_len; 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds direction = 0; 49755b28f9fSOndrej Zary if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6) 4981da177e4SLinus Torvalds direction = 8; 49955b28f9fSOndrej Zary else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6) 5001da177e4SLinus Torvalds direction = 16; 5011da177e4SLinus Torvalds 50255b28f9fSOndrej Zary memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen); 5031da177e4SLinus Torvalds ccb[mbo].op = 0; /* SCSI Initiator Command */ 5042f2fef02SChristoph Hellwig any2scsi(ccb[mbo].datalen, bufflen); 5052f2fef02SChristoph Hellwig if (bufflen) 5062f2fef02SChristoph Hellwig any2scsi(ccb[mbo].dataptr, acmd->data_buffer_handle); 5072f2fef02SChristoph Hellwig else 508fc3fdfccSBoaz Harrosh any2scsi(ccb[mbo].dataptr, 0); 5091da177e4SLinus Torvalds ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */ 5101da177e4SLinus Torvalds ccb[mbo].rsalen = 16; 5111da177e4SLinus Torvalds ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; 5121da177e4SLinus Torvalds ccb[mbo].commlinkid = 0; 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds #ifdef DEBUG 5156ddc8cf4SOndrej Zary print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10); 516fde1fb8aSOndrej Zary printk("aha1542_queuecommand: now waiting for interrupt "); 517fde1fb8aSOndrej Zary #endif 5181da177e4SLinus Torvalds mb[mbo].status = 1; 51955b28f9fSOndrej Zary aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI); 5201b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds return 0; 5231da177e4SLinus Torvalds } 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds /* Initialize mailboxes */ 52668ea9de3SOndrej Zary static void setup_mailboxes(struct Scsi_Host *sh) 5271da177e4SLinus Torvalds { 528c2532f68SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 529cad2fc72SOndrej Zary u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; 5301794ef2bSChristoph Hellwig int i; 5311da177e4SLinus Torvalds 5321da177e4SLinus Torvalds for (i = 0; i < AHA1542_MAILBOXES; i++) { 5331794ef2bSChristoph Hellwig aha1542->mb[i].status = 0; 5341794ef2bSChristoph Hellwig any2scsi(aha1542->mb[i].ccbptr, 5351794ef2bSChristoph Hellwig aha1542->ccb_handle + i * sizeof(struct ccb)); 5361794ef2bSChristoph Hellwig aha1542->mb[AHA1542_MAILBOXES + i].status = 0; 5378c36b054SHaowen Bai } 53868ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ 5391794ef2bSChristoph Hellwig any2scsi(mb_cmd + 2, aha1542->mb_handle); 54068ea9de3SOndrej Zary if (aha1542_out(sh->io_port, mb_cmd, 5)) 5412906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n"); 54268ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 54568ea9de3SOndrej Zary static int aha1542_getconfig(struct Scsi_Host *sh) 5461da177e4SLinus Torvalds { 547cb5b570cSOndrej Zary u8 inquiry_result[3]; 5481da177e4SLinus Torvalds int i; 54968ea9de3SOndrej Zary i = inb(STATUS(sh->io_port)); 5501da177e4SLinus Torvalds if (i & DF) { 55168ea9de3SOndrej Zary i = inb(DATA(sh->io_port)); 5528c36b054SHaowen Bai } 55368ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_RETCONF); 55468ea9de3SOndrej Zary aha1542_in(sh->io_port, inquiry_result, 3, 0); 55568ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) 5562906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "error querying board settings\n"); 55768ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 5581da177e4SLinus Torvalds switch (inquiry_result[0]) { 5591da177e4SLinus Torvalds case 0x80: 56068ea9de3SOndrej Zary sh->dma_channel = 7; 5611da177e4SLinus Torvalds break; 5621da177e4SLinus Torvalds case 0x40: 56368ea9de3SOndrej Zary sh->dma_channel = 6; 5641da177e4SLinus Torvalds break; 5651da177e4SLinus Torvalds case 0x20: 56668ea9de3SOndrej Zary sh->dma_channel = 5; 5671da177e4SLinus Torvalds break; 5681da177e4SLinus Torvalds case 0x01: 56968ea9de3SOndrej Zary sh->dma_channel = 0; 5701da177e4SLinus Torvalds break; 5711da177e4SLinus Torvalds case 0: 572e4da5febSSergey Shtylyov /* 573e4da5febSSergey Shtylyov * This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel. 574e4da5febSSergey Shtylyov * Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. 575e4da5febSSergey Shtylyov */ 57668ea9de3SOndrej Zary sh->dma_channel = 0xFF; 5771da177e4SLinus Torvalds break; 5781da177e4SLinus Torvalds default: 5792906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n"); 5801da177e4SLinus Torvalds return -1; 5818c36b054SHaowen Bai } 5821da177e4SLinus Torvalds switch (inquiry_result[1]) { 5831da177e4SLinus Torvalds case 0x40: 58468ea9de3SOndrej Zary sh->irq = 15; 5851da177e4SLinus Torvalds break; 5861da177e4SLinus Torvalds case 0x20: 58768ea9de3SOndrej Zary sh->irq = 14; 5881da177e4SLinus Torvalds break; 5891da177e4SLinus Torvalds case 0x8: 59068ea9de3SOndrej Zary sh->irq = 12; 5911da177e4SLinus Torvalds break; 5921da177e4SLinus Torvalds case 0x4: 59368ea9de3SOndrej Zary sh->irq = 11; 5941da177e4SLinus Torvalds break; 5951da177e4SLinus Torvalds case 0x2: 59668ea9de3SOndrej Zary sh->irq = 10; 5971da177e4SLinus Torvalds break; 5981da177e4SLinus Torvalds case 0x1: 59968ea9de3SOndrej Zary sh->irq = 9; 6001da177e4SLinus Torvalds break; 6011da177e4SLinus Torvalds default: 6022906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n"); 6031da177e4SLinus Torvalds return -1; 6048c36b054SHaowen Bai } 60568ea9de3SOndrej Zary sh->this_id = inquiry_result[2] & 7; 6061da177e4SLinus Torvalds return 0; 6071da177e4SLinus Torvalds } 6081da177e4SLinus Torvalds 609e4da5febSSergey Shtylyov /* 610e4da5febSSergey Shtylyov * This function should only be called for 1542C boards - we can detect 611e4da5febSSergey Shtylyov * the special firmware settings and unlock the board 612e4da5febSSergey Shtylyov */ 6131da177e4SLinus Torvalds 61468ea9de3SOndrej Zary static int aha1542_mbenable(struct Scsi_Host *sh) 6151da177e4SLinus Torvalds { 616cb5b570cSOndrej Zary static u8 mbenable_cmd[3]; 617cb5b570cSOndrej Zary static u8 mbenable_result[2]; 6181da177e4SLinus Torvalds int retval; 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds retval = BIOS_TRANSLATION_6432; 6211da177e4SLinus Torvalds 62268ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_EXTBIOS); 62368ea9de3SOndrej Zary if (aha1542_in(sh->io_port, mbenable_result, 2, 100)) 6241da177e4SLinus Torvalds return retval; 62568ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100)) 6262093bfa1SOndrej Zary goto fail; 62768ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds if ((mbenable_result[0] & 0x08) || mbenable_result[1]) { 6301da177e4SLinus Torvalds mbenable_cmd[0] = CMD_MBENABLE; 6311da177e4SLinus Torvalds mbenable_cmd[1] = 0; 6321da177e4SLinus Torvalds mbenable_cmd[2] = mbenable_result[1]; 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03)) 6351da177e4SLinus Torvalds retval = BIOS_TRANSLATION_25563; 6361da177e4SLinus Torvalds 63768ea9de3SOndrej Zary if (aha1542_out(sh->io_port, mbenable_cmd, 3)) 6382093bfa1SOndrej Zary goto fail; 6398c36b054SHaowen Bai } 6401da177e4SLinus Torvalds while (0) { 6411da177e4SLinus Torvalds fail: 6422906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Mailbox init failed\n"); 6431da177e4SLinus Torvalds } 64468ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6451da177e4SLinus Torvalds return retval; 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds /* Query the board to find out if it is a 1542 or a 1740, or whatever. */ 64968ea9de3SOndrej Zary static int aha1542_query(struct Scsi_Host *sh) 6501da177e4SLinus Torvalds { 65168ea9de3SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 652cb5b570cSOndrej Zary u8 inquiry_result[4]; 6531da177e4SLinus Torvalds int i; 65468ea9de3SOndrej Zary i = inb(STATUS(sh->io_port)); 6551da177e4SLinus Torvalds if (i & DF) { 65668ea9de3SOndrej Zary i = inb(DATA(sh->io_port)); 6578c36b054SHaowen Bai } 65868ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_INQUIRY); 65968ea9de3SOndrej Zary aha1542_in(sh->io_port, inquiry_result, 4, 0); 66068ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) 6612906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "error querying card type\n"); 66268ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6631da177e4SLinus Torvalds 66468ea9de3SOndrej Zary aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */ 6651da177e4SLinus Torvalds 666e4da5febSSergey Shtylyov /* 667e4da5febSSergey Shtylyov * For an AHA1740 series board, we ignore the board since there is a 668e4da5febSSergey Shtylyov * hardware bug which can lead to wrong blocks being returned if the board 669e4da5febSSergey Shtylyov * is operating in the 1542 emulation mode. Since there is an extended mode 670e4da5febSSergey Shtylyov * driver, we simply ignore the board and let the 1740 driver pick it up. 6711da177e4SLinus Torvalds */ 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds if (inquiry_result[0] == 0x43) { 6742906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n"); 6751da177e4SLinus Torvalds return 1; 6768c36b054SHaowen Bai } 6771da177e4SLinus Torvalds 678e4da5febSSergey Shtylyov /* 679e4da5febSSergey Shtylyov * Always call this - boards that do not support extended bios translation 680e4da5febSSergey Shtylyov * will ignore the command, and we will set the proper default 681e4da5febSSergey Shtylyov */ 6821da177e4SLinus Torvalds 68368ea9de3SOndrej Zary aha1542->bios_translation = aha1542_mbenable(sh); 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds return 0; 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds 688f71429abSOndrej Zary static u8 dma_speed_hw(int dma_speed) 6891da177e4SLinus Torvalds { 690f71429abSOndrej Zary switch (dma_speed) { 6911da177e4SLinus Torvalds case 5: 692f71429abSOndrej Zary return 0x00; 6931da177e4SLinus Torvalds case 6: 694f71429abSOndrej Zary return 0x04; 6951da177e4SLinus Torvalds case 7: 696f71429abSOndrej Zary return 0x01; 6971da177e4SLinus Torvalds case 8: 698f71429abSOndrej Zary return 0x02; 6991da177e4SLinus Torvalds case 10: 700f71429abSOndrej Zary return 0x03; 7011da177e4SLinus Torvalds } 7021da177e4SLinus Torvalds 703f71429abSOndrej Zary return 0xff; /* invalid */ 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 706b847fd0dSOndrej Zary /* Set the Bus on/off-times as not to ruin floppy performance */ 70737d607bdSOndrej Zary static void aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed) 708b847fd0dSOndrej Zary { 70937d607bdSOndrej Zary if (bus_on > 0) { 71037d607bdSOndrej Zary u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) }; 711b847fd0dSOndrej Zary 71237d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 71337d607bdSOndrej Zary if (aha1542_out(sh->io_port, oncmd, 2)) 714b847fd0dSOndrej Zary goto fail; 715f71429abSOndrej Zary } 716f71429abSOndrej Zary 71737d607bdSOndrej Zary if (bus_off > 0) { 71837d607bdSOndrej Zary u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) }; 719f71429abSOndrej Zary 72037d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 72137d607bdSOndrej Zary if (aha1542_out(sh->io_port, offcmd, 2)) 722b847fd0dSOndrej Zary goto fail; 723f71429abSOndrej Zary } 724f71429abSOndrej Zary 72537d607bdSOndrej Zary if (dma_speed_hw(dma_speed) != 0xff) { 72637d607bdSOndrej Zary u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) }; 727f71429abSOndrej Zary 72837d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 72937d607bdSOndrej Zary if (aha1542_out(sh->io_port, dmacmd, 2)) 730b847fd0dSOndrej Zary goto fail; 731b847fd0dSOndrej Zary } 73237d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 733b847fd0dSOndrej Zary return; 734b847fd0dSOndrej Zary fail: 7352906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n"); 73637d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 737b847fd0dSOndrej Zary } 738b847fd0dSOndrej Zary 7391da177e4SLinus Torvalds /* return non-zero on detection */ 74077168bd7SBart Van Assche static struct Scsi_Host *aha1542_hw_init(const struct scsi_host_template *tpnt, 74177168bd7SBart Van Assche struct device *pdev, int indx) 7421da177e4SLinus Torvalds { 743f71429abSOndrej Zary unsigned int base_io = io[indx]; 744c2532f68SOndrej Zary struct Scsi_Host *sh; 745e98878f7SOndrej Zary struct aha1542_hostdata *aha1542; 7462906b3ceSOndrej Zary char dma_info[] = "no DMA"; 7471da177e4SLinus Torvalds 7483a70c006SOndrej Zary if (base_io == 0) 749643a7c43SOndrej Zary return NULL; 7501da177e4SLinus Torvalds 7513a70c006SOndrej Zary if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542")) 7523a70c006SOndrej Zary return NULL; 7533a70c006SOndrej Zary 754c2532f68SOndrej Zary sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata)); 755c2532f68SOndrej Zary if (!sh) 7563a70c006SOndrej Zary goto release; 757c2532f68SOndrej Zary aha1542 = shost_priv(sh); 7583a70c006SOndrej Zary 75968ea9de3SOndrej Zary sh->unique_id = base_io; 76068ea9de3SOndrej Zary sh->io_port = base_io; 76168ea9de3SOndrej Zary sh->n_io_port = AHA1542_REGION_SIZE; 76268ea9de3SOndrej Zary aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1; 76368ea9de3SOndrej Zary aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1; 76468ea9de3SOndrej Zary 76568ea9de3SOndrej Zary if (!aha1542_test_port(sh)) 7663a70c006SOndrej Zary goto unregister; 7671da177e4SLinus Torvalds 76837d607bdSOndrej Zary aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]); 76968ea9de3SOndrej Zary if (aha1542_query(sh)) 7703a70c006SOndrej Zary goto unregister; 77168ea9de3SOndrej Zary if (aha1542_getconfig(sh) == -1) 7721da177e4SLinus Torvalds goto unregister; 7731da177e4SLinus Torvalds 774c2532f68SOndrej Zary if (sh->dma_channel != 0xFF) 7752906b3ceSOndrej Zary snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel); 7762906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n", 7772906b3ceSOndrej Zary sh->this_id, base_io, sh->irq, dma_info); 7783a70c006SOndrej Zary if (aha1542->bios_translation == BIOS_TRANSLATION_25563) 7792906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Using extended bios translation\n"); 7801da177e4SLinus Torvalds 7811794ef2bSChristoph Hellwig if (dma_set_mask_and_coherent(pdev, DMA_BIT_MASK(24)) < 0) 7821794ef2bSChristoph Hellwig goto unregister; 7831794ef2bSChristoph Hellwig 7841794ef2bSChristoph Hellwig aha1542->mb = dma_alloc_coherent(pdev, 7851794ef2bSChristoph Hellwig AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), 7861794ef2bSChristoph Hellwig &aha1542->mb_handle, GFP_KERNEL); 7871794ef2bSChristoph Hellwig if (!aha1542->mb) 7881794ef2bSChristoph Hellwig goto unregister; 7891794ef2bSChristoph Hellwig 7901794ef2bSChristoph Hellwig aha1542->ccb = dma_alloc_coherent(pdev, 7911794ef2bSChristoph Hellwig AHA1542_MAILBOXES * sizeof(struct ccb), 7921794ef2bSChristoph Hellwig &aha1542->ccb_handle, GFP_KERNEL); 7931794ef2bSChristoph Hellwig if (!aha1542->ccb) 7941794ef2bSChristoph Hellwig goto free_mb; 7951794ef2bSChristoph Hellwig 79668ea9de3SOndrej Zary setup_mailboxes(sh); 7971da177e4SLinus Torvalds 7981b0224b0SOndrej Zary if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) { 7992906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n"); 8001794ef2bSChristoph Hellwig goto free_ccb; 8011da177e4SLinus Torvalds } 802c2532f68SOndrej Zary if (sh->dma_channel != 0xFF) { 803c2532f68SOndrej Zary if (request_dma(sh->dma_channel, "aha1542")) { 8042906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n"); 8053a70c006SOndrej Zary goto free_irq; 8061da177e4SLinus Torvalds } 807c2532f68SOndrej Zary if (sh->dma_channel == 0 || sh->dma_channel >= 5) { 808c2532f68SOndrej Zary set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE); 809c2532f68SOndrej Zary enable_dma(sh->dma_channel); 8101da177e4SLinus Torvalds } 8111da177e4SLinus Torvalds } 81287c4d7bcSJeff Garzik 813c2532f68SOndrej Zary if (scsi_add_host(sh, pdev)) 8143a70c006SOndrej Zary goto free_dma; 8151da177e4SLinus Torvalds 816c2532f68SOndrej Zary scsi_scan_host(sh); 8171da177e4SLinus Torvalds 818c2532f68SOndrej Zary return sh; 8191794ef2bSChristoph Hellwig 8203a70c006SOndrej Zary free_dma: 821c2532f68SOndrej Zary if (sh->dma_channel != 0xff) 822c2532f68SOndrej Zary free_dma(sh->dma_channel); 8233a70c006SOndrej Zary free_irq: 824c2532f68SOndrej Zary free_irq(sh->irq, sh); 8251794ef2bSChristoph Hellwig free_ccb: 8261794ef2bSChristoph Hellwig dma_free_coherent(pdev, AHA1542_MAILBOXES * sizeof(struct ccb), 8271794ef2bSChristoph Hellwig aha1542->ccb, aha1542->ccb_handle); 8281794ef2bSChristoph Hellwig free_mb: 8291794ef2bSChristoph Hellwig dma_free_coherent(pdev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), 8301794ef2bSChristoph Hellwig aha1542->mb, aha1542->mb_handle); 8311da177e4SLinus Torvalds unregister: 832c2532f68SOndrej Zary scsi_host_put(sh); 8333a70c006SOndrej Zary release: 8343a70c006SOndrej Zary release_region(base_io, AHA1542_REGION_SIZE); 8351da177e4SLinus Torvalds 836643a7c43SOndrej Zary return NULL; 8371da177e4SLinus Torvalds } 8381da177e4SLinus Torvalds 839c2532f68SOndrej Zary static int aha1542_release(struct Scsi_Host *sh) 8401da177e4SLinus Torvalds { 8411794ef2bSChristoph Hellwig struct aha1542_hostdata *aha1542 = shost_priv(sh); 8421794ef2bSChristoph Hellwig struct device *dev = sh->dma_dev; 8431794ef2bSChristoph Hellwig 844c2532f68SOndrej Zary scsi_remove_host(sh); 845c2532f68SOndrej Zary if (sh->dma_channel != 0xff) 846c2532f68SOndrej Zary free_dma(sh->dma_channel); 8471794ef2bSChristoph Hellwig dma_free_coherent(dev, AHA1542_MAILBOXES * sizeof(struct ccb), 8481794ef2bSChristoph Hellwig aha1542->ccb, aha1542->ccb_handle); 8491794ef2bSChristoph Hellwig dma_free_coherent(dev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), 8501794ef2bSChristoph Hellwig aha1542->mb, aha1542->mb_handle); 851c2532f68SOndrej Zary if (sh->irq) 852c2532f68SOndrej Zary free_irq(sh->irq, sh); 853c2532f68SOndrej Zary if (sh->io_port && sh->n_io_port) 854c2532f68SOndrej Zary release_region(sh->io_port, sh->n_io_port); 855c2532f68SOndrej Zary scsi_host_put(sh); 8561da177e4SLinus Torvalds return 0; 8571da177e4SLinus Torvalds } 8581da177e4SLinus Torvalds 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds /* 8611da177e4SLinus Torvalds * This is a device reset. This is handled by sending a special command 8621da177e4SLinus Torvalds * to the device. 8631da177e4SLinus Torvalds */ 86455b28f9fSOndrej Zary static int aha1542_dev_reset(struct scsi_cmnd *cmd) 8651da177e4SLinus Torvalds { 8661b0224b0SOndrej Zary struct Scsi_Host *sh = cmd->device->host; 8671b0224b0SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 8681da177e4SLinus Torvalds unsigned long flags; 869e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 87055b28f9fSOndrej Zary u8 target = cmd->device->id; 87155b28f9fSOndrej Zary u8 lun = cmd->device->lun; 8721da177e4SLinus Torvalds int mbo; 873e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 8741da177e4SLinus Torvalds 8751b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 876e98878f7SOndrej Zary mbo = aha1542->aha1542_last_mbo_used + 1; 8771da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 8781da177e4SLinus Torvalds mbo = 0; 8791da177e4SLinus Torvalds 8801da177e4SLinus Torvalds do { 88155b28f9fSOndrej Zary if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) 8821da177e4SLinus Torvalds break; 8831da177e4SLinus Torvalds mbo++; 8841da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 8851da177e4SLinus Torvalds mbo = 0; 886e98878f7SOndrej Zary } while (mbo != aha1542->aha1542_last_mbo_used); 8871da177e4SLinus Torvalds 88855b28f9fSOndrej Zary if (mb[mbo].status || aha1542->int_cmds[mbo]) 8891da177e4SLinus Torvalds panic("Unable to find empty mailbox for aha1542.\n"); 8901da177e4SLinus Torvalds 89155b28f9fSOndrej Zary aha1542->int_cmds[mbo] = cmd; /* This will effectively 892e4da5febSSergey Shtylyov * prevent someone else from 893e4da5febSSergey Shtylyov * screwing with this cdb. 894e4da5febSSergey Shtylyov */ 8951da177e4SLinus Torvalds 896e98878f7SOndrej Zary aha1542->aha1542_last_mbo_used = mbo; 8971da177e4SLinus Torvalds 8981794ef2bSChristoph Hellwig /* This gets trashed for some reason */ 8991794ef2bSChristoph Hellwig any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); 9001da177e4SLinus Torvalds 9011da177e4SLinus Torvalds memset(&ccb[mbo], 0, sizeof(struct ccb)); 9021da177e4SLinus Torvalds 9031da177e4SLinus Torvalds ccb[mbo].op = 0x81; /* BUS DEVICE RESET */ 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */ 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; 9081da177e4SLinus Torvalds ccb[mbo].commlinkid = 0; 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds /* 9111da177e4SLinus Torvalds * Now tell the 1542 to flush all pending commands for this 9121da177e4SLinus Torvalds * target 9131da177e4SLinus Torvalds */ 9141b0224b0SOndrej Zary aha1542_outb(sh->io_port, CMD_START_SCSI); 9151b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 9161da177e4SLinus Torvalds 91755b28f9fSOndrej Zary scmd_printk(KERN_WARNING, cmd, 918017560fcSJeff Garzik "Trying device reset for target\n"); 9191da177e4SLinus Torvalds 9201da177e4SLinus Torvalds return SUCCESS; 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds 92355b28f9fSOndrej Zary static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd) 9241da177e4SLinus Torvalds { 9251b0224b0SOndrej Zary struct Scsi_Host *sh = cmd->device->host; 9261b0224b0SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 9271b0224b0SOndrej Zary unsigned long flags; 9281da177e4SLinus Torvalds int i; 9291da177e4SLinus Torvalds 9301b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 9311da177e4SLinus Torvalds /* 9321da177e4SLinus Torvalds * This does a scsi reset for all devices on the bus. 9331da177e4SLinus Torvalds * In principle, we could also reset the 1542 - should 9341da177e4SLinus Torvalds * we do this? Try this first, and we can add that later 9351da177e4SLinus Torvalds * if it turns out to be useful. 9361da177e4SLinus Torvalds */ 93755b28f9fSOndrej Zary outb(reset_cmd, CONTROL(cmd->device->host->io_port)); 9381da177e4SLinus Torvalds 93955b28f9fSOndrej Zary if (!wait_mask(STATUS(cmd->device->host->io_port), 9407061dec4SOndrej Zary STATMASK, IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) { 9411b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 942a13b3722SOndrej Zary return FAILED; 943a13b3722SOndrej Zary } 9441b0224b0SOndrej Zary 9451da177e4SLinus Torvalds /* 9461da177e4SLinus Torvalds * We need to do this too before the 1542 can interact with 9478537cba8SOndrej Zary * us again after host reset. 9481da177e4SLinus Torvalds */ 9498537cba8SOndrej Zary if (reset_cmd & HRST) 95068ea9de3SOndrej Zary setup_mailboxes(cmd->device->host); 9511b0224b0SOndrej Zary 9521da177e4SLinus Torvalds /* 9531da177e4SLinus Torvalds * Now try to pick up the pieces. For all pending commands, 9541da177e4SLinus Torvalds * free any internal data structures, and basically clear things 9551da177e4SLinus Torvalds * out. We do not try and restart any commands or anything - 9561da177e4SLinus Torvalds * the strategy handler takes care of that crap. 9571da177e4SLinus Torvalds */ 9582906b3ceSOndrej Zary shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no); 9591da177e4SLinus Torvalds 9601da177e4SLinus Torvalds for (i = 0; i < AHA1542_MAILBOXES; i++) { 96155b28f9fSOndrej Zary if (aha1542->int_cmds[i] != NULL) { 96255b28f9fSOndrej Zary struct scsi_cmnd *tmp_cmd; 96355b28f9fSOndrej Zary tmp_cmd = aha1542->int_cmds[i]; 9641da177e4SLinus Torvalds 96555b28f9fSOndrej Zary if (tmp_cmd->device->soft_reset) { 9661da177e4SLinus Torvalds /* 9671da177e4SLinus Torvalds * If this device implements the soft reset option, 9681da177e4SLinus Torvalds * then it is still holding onto the command, and 9691da177e4SLinus Torvalds * may yet complete it. In this case, we don't 9701da177e4SLinus Torvalds * flush the data. 9711da177e4SLinus Torvalds */ 9721da177e4SLinus Torvalds continue; 9731da177e4SLinus Torvalds } 9741794ef2bSChristoph Hellwig aha1542_free_cmd(tmp_cmd); 97555b28f9fSOndrej Zary aha1542->int_cmds[i] = NULL; 976e98878f7SOndrej Zary aha1542->mb[i].status = 0; 9771da177e4SLinus Torvalds } 9781da177e4SLinus Torvalds } 9791da177e4SLinus Torvalds 9801b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 9811da177e4SLinus Torvalds return SUCCESS; 9821da177e4SLinus Torvalds } 9831da177e4SLinus Torvalds 98455b28f9fSOndrej Zary static int aha1542_bus_reset(struct scsi_cmnd *cmd) 9858537cba8SOndrej Zary { 98655b28f9fSOndrej Zary return aha1542_reset(cmd, SCRST); 9878537cba8SOndrej Zary } 9888537cba8SOndrej Zary 98955b28f9fSOndrej Zary static int aha1542_host_reset(struct scsi_cmnd *cmd) 9908537cba8SOndrej Zary { 99155b28f9fSOndrej Zary return aha1542_reset(cmd, HRST | SCRST); 9928537cba8SOndrej Zary } 9938537cba8SOndrej Zary 9941da177e4SLinus Torvalds static int aha1542_biosparam(struct scsi_device *sdev, 99517787a09SOndrej Zary struct block_device *bdev, sector_t capacity, int geom[]) 9961da177e4SLinus Torvalds { 997e98878f7SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sdev->host); 9981da177e4SLinus Torvalds 99917787a09SOndrej Zary if (capacity >= 0x200000 && 100017787a09SOndrej Zary aha1542->bios_translation == BIOS_TRANSLATION_25563) { 10011da177e4SLinus Torvalds /* Please verify that this is the same as what DOS returns */ 100217787a09SOndrej Zary geom[0] = 255; /* heads */ 100317787a09SOndrej Zary geom[1] = 63; /* sectors */ 10041da177e4SLinus Torvalds } else { 100517787a09SOndrej Zary geom[0] = 64; /* heads */ 100617787a09SOndrej Zary geom[1] = 32; /* sectors */ 10071da177e4SLinus Torvalds } 100817787a09SOndrej Zary geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */ 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds return 0; 10111da177e4SLinus Torvalds } 1012*95f8bf93SJeff Johnson 1013*95f8bf93SJeff Johnson MODULE_DESCRIPTION("Adaptec AHA-1542 SCSI host adapter driver"); 10141da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 10151da177e4SLinus Torvalds 10162f2fef02SChristoph Hellwig static int aha1542_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) 10172f2fef02SChristoph Hellwig { 10182f2fef02SChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 10192f2fef02SChristoph Hellwig 10202f2fef02SChristoph Hellwig acmd->data_buffer = dma_alloc_coherent(shost->dma_dev, 10212f2fef02SChristoph Hellwig SECTOR_SIZE * AHA1542_MAX_SECTORS, 10222f2fef02SChristoph Hellwig &acmd->data_buffer_handle, GFP_KERNEL); 10232f2fef02SChristoph Hellwig if (!acmd->data_buffer) 10242f2fef02SChristoph Hellwig return -ENOMEM; 10252f2fef02SChristoph Hellwig return 0; 10262f2fef02SChristoph Hellwig } 10272f2fef02SChristoph Hellwig 10282f2fef02SChristoph Hellwig static int aha1542_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) 10292f2fef02SChristoph Hellwig { 10302f2fef02SChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 10312f2fef02SChristoph Hellwig 10322f2fef02SChristoph Hellwig dma_free_coherent(shost->dma_dev, SECTOR_SIZE * AHA1542_MAX_SECTORS, 10332f2fef02SChristoph Hellwig acmd->data_buffer, acmd->data_buffer_handle); 10342f2fef02SChristoph Hellwig return 0; 10352f2fef02SChristoph Hellwig } 10362f2fef02SChristoph Hellwig 103777168bd7SBart Van Assche static const struct scsi_host_template driver_template = { 1038643a7c43SOndrej Zary .module = THIS_MODULE, 10391da177e4SLinus Torvalds .proc_name = "aha1542", 10401da177e4SLinus Torvalds .name = "Adaptec 1542", 10411794ef2bSChristoph Hellwig .cmd_size = sizeof(struct aha1542_cmd), 10421da177e4SLinus Torvalds .queuecommand = aha1542_queuecommand, 10431da177e4SLinus Torvalds .eh_device_reset_handler= aha1542_dev_reset, 10441da177e4SLinus Torvalds .eh_bus_reset_handler = aha1542_bus_reset, 10451da177e4SLinus Torvalds .eh_host_reset_handler = aha1542_host_reset, 10461da177e4SLinus Torvalds .bios_param = aha1542_biosparam, 10472f2fef02SChristoph Hellwig .init_cmd_priv = aha1542_init_cmd_priv, 10482f2fef02SChristoph Hellwig .exit_cmd_priv = aha1542_exit_cmd_priv, 10491da177e4SLinus Torvalds .can_queue = AHA1542_MAILBOXES, 10501da177e4SLinus Torvalds .this_id = 7, 10512f2fef02SChristoph Hellwig .max_sectors = AHA1542_MAX_SECTORS, 10522f2fef02SChristoph Hellwig .sg_tablesize = SG_ALL, 10531da177e4SLinus Torvalds }; 1054643a7c43SOndrej Zary 1055643a7c43SOndrej Zary static int aha1542_isa_match(struct device *pdev, unsigned int ndev) 1056643a7c43SOndrej Zary { 1057643a7c43SOndrej Zary struct Scsi_Host *sh = aha1542_hw_init(&driver_template, pdev, ndev); 1058643a7c43SOndrej Zary 1059643a7c43SOndrej Zary if (!sh) 1060643a7c43SOndrej Zary return 0; 1061643a7c43SOndrej Zary 1062643a7c43SOndrej Zary dev_set_drvdata(pdev, sh); 1063643a7c43SOndrej Zary return 1; 1064643a7c43SOndrej Zary } 1065643a7c43SOndrej Zary 106630e88d01SUwe Kleine-König static void aha1542_isa_remove(struct device *pdev, 1067643a7c43SOndrej Zary unsigned int ndev) 1068643a7c43SOndrej Zary { 1069643a7c43SOndrej Zary aha1542_release(dev_get_drvdata(pdev)); 1070643a7c43SOndrej Zary dev_set_drvdata(pdev, NULL); 1071643a7c43SOndrej Zary } 1072643a7c43SOndrej Zary 1073643a7c43SOndrej Zary static struct isa_driver aha1542_isa_driver = { 1074643a7c43SOndrej Zary .match = aha1542_isa_match, 1075643a7c43SOndrej Zary .remove = aha1542_isa_remove, 1076643a7c43SOndrej Zary .driver = { 1077643a7c43SOndrej Zary .name = "aha1542" 1078643a7c43SOndrej Zary }, 1079643a7c43SOndrej Zary }; 1080643a7c43SOndrej Zary static int isa_registered; 1081643a7c43SOndrej Zary 1082643a7c43SOndrej Zary #ifdef CONFIG_PNP 108378453a31SArvind Yadav static const struct pnp_device_id aha1542_pnp_ids[] = { 1084643a7c43SOndrej Zary { .id = "ADP1542" }, 1085643a7c43SOndrej Zary { .id = "" } 1086643a7c43SOndrej Zary }; 1087643a7c43SOndrej Zary MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids); 1088643a7c43SOndrej Zary 1089643a7c43SOndrej Zary static int aha1542_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id) 1090643a7c43SOndrej Zary { 1091643a7c43SOndrej Zary int indx; 1092643a7c43SOndrej Zary struct Scsi_Host *sh; 1093643a7c43SOndrej Zary 1094f71429abSOndrej Zary for (indx = 0; indx < ARRAY_SIZE(io); indx++) { 1095f71429abSOndrej Zary if (io[indx]) 1096643a7c43SOndrej Zary continue; 1097643a7c43SOndrej Zary 1098643a7c43SOndrej Zary if (pnp_activate_dev(pdev) < 0) 1099643a7c43SOndrej Zary continue; 1100643a7c43SOndrej Zary 1101f71429abSOndrej Zary io[indx] = pnp_port_start(pdev, 0); 1102643a7c43SOndrej Zary 1103e4da5febSSergey Shtylyov /* 1104e4da5febSSergey Shtylyov * The card can be queried for its DMA, we have 1105e4da5febSSergey Shtylyov * the DMA set up that is enough 1106e4da5febSSergey Shtylyov */ 1107643a7c43SOndrej Zary 11082906b3ceSOndrej Zary dev_info(&pdev->dev, "ISAPnP found an AHA1535 at I/O 0x%03X", io[indx]); 1109643a7c43SOndrej Zary } 1110643a7c43SOndrej Zary 1111643a7c43SOndrej Zary sh = aha1542_hw_init(&driver_template, &pdev->dev, indx); 1112643a7c43SOndrej Zary if (!sh) 1113643a7c43SOndrej Zary return -ENODEV; 1114643a7c43SOndrej Zary 1115643a7c43SOndrej Zary pnp_set_drvdata(pdev, sh); 1116643a7c43SOndrej Zary return 0; 1117643a7c43SOndrej Zary } 1118643a7c43SOndrej Zary 1119643a7c43SOndrej Zary static void aha1542_pnp_remove(struct pnp_dev *pdev) 1120643a7c43SOndrej Zary { 1121643a7c43SOndrej Zary aha1542_release(pnp_get_drvdata(pdev)); 1122643a7c43SOndrej Zary pnp_set_drvdata(pdev, NULL); 1123643a7c43SOndrej Zary } 1124643a7c43SOndrej Zary 1125643a7c43SOndrej Zary static struct pnp_driver aha1542_pnp_driver = { 1126643a7c43SOndrej Zary .name = "aha1542", 1127643a7c43SOndrej Zary .id_table = aha1542_pnp_ids, 1128643a7c43SOndrej Zary .probe = aha1542_pnp_probe, 1129643a7c43SOndrej Zary .remove = aha1542_pnp_remove, 1130643a7c43SOndrej Zary }; 1131643a7c43SOndrej Zary static int pnp_registered; 1132643a7c43SOndrej Zary #endif /* CONFIG_PNP */ 1133643a7c43SOndrej Zary 1134643a7c43SOndrej Zary static int __init aha1542_init(void) 1135643a7c43SOndrej Zary { 1136643a7c43SOndrej Zary int ret = 0; 1137643a7c43SOndrej Zary 1138643a7c43SOndrej Zary #ifdef CONFIG_PNP 1139643a7c43SOndrej Zary if (isapnp) { 1140643a7c43SOndrej Zary ret = pnp_register_driver(&aha1542_pnp_driver); 1141643a7c43SOndrej Zary if (!ret) 1142643a7c43SOndrej Zary pnp_registered = 1; 1143643a7c43SOndrej Zary } 1144643a7c43SOndrej Zary #endif 1145643a7c43SOndrej Zary ret = isa_register_driver(&aha1542_isa_driver, MAXBOARDS); 1146643a7c43SOndrej Zary if (!ret) 1147643a7c43SOndrej Zary isa_registered = 1; 1148643a7c43SOndrej Zary 1149643a7c43SOndrej Zary #ifdef CONFIG_PNP 1150643a7c43SOndrej Zary if (pnp_registered) 1151643a7c43SOndrej Zary ret = 0; 1152643a7c43SOndrej Zary #endif 1153643a7c43SOndrej Zary if (isa_registered) 1154643a7c43SOndrej Zary ret = 0; 1155643a7c43SOndrej Zary 1156643a7c43SOndrej Zary return ret; 1157643a7c43SOndrej Zary } 1158643a7c43SOndrej Zary 1159643a7c43SOndrej Zary static void __exit aha1542_exit(void) 1160643a7c43SOndrej Zary { 1161643a7c43SOndrej Zary #ifdef CONFIG_PNP 1162643a7c43SOndrej Zary if (pnp_registered) 1163643a7c43SOndrej Zary pnp_unregister_driver(&aha1542_pnp_driver); 1164643a7c43SOndrej Zary #endif 1165643a7c43SOndrej Zary if (isa_registered) 1166643a7c43SOndrej Zary isa_unregister_driver(&aha1542_isa_driver); 1167643a7c43SOndrej Zary } 1168643a7c43SOndrej Zary 1169643a7c43SOndrej Zary module_init(aha1542_init); 1170643a7c43SOndrej Zary module_exit(aha1542_exit); 1171