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 68*2f2fef02SChristoph Hellwig #define AHA1542_MAX_SECTORS 16 69*2f2fef02SChristoph Hellwig 701794ef2bSChristoph Hellwig struct aha1542_cmd { 71*2f2fef02SChristoph Hellwig /* bounce buffer */ 72*2f2fef02SChristoph Hellwig void *data_buffer; 73*2f2fef02SChristoph 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 { 209cb5b570cSOndrej Zary u8 inquiry_result[4]; 210cad2fc72SOndrej Zary int i; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* Quick and dirty test for presence of the card. */ 21368ea9de3SOndrej Zary if (inb(STATUS(sh->io_port)) == 0xff) 2141da177e4SLinus Torvalds return 0; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */ 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds /* In case some other card was probing here, reset interrupts */ 21968ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ 2201da177e4SLinus Torvalds 22168ea9de3SOndrej Zary outb(SRST | IRST /*|SCRST */ , CONTROL(sh->io_port)); 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds mdelay(20); /* Wait a little bit for things to settle down. */ 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds /* Expect INIT and IDLE, any of the others are bad */ 22668ea9de3SOndrej Zary if (!wait_mask(STATUS(sh->io_port), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) 227a13b3722SOndrej Zary return 0; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /* Shouldn't have generated any interrupts during reset */ 23068ea9de3SOndrej Zary if (inb(INTRFLAGS(sh->io_port)) & INTRMASK) 231a13b3722SOndrej Zary return 0; 2321da177e4SLinus Torvalds 233e4da5febSSergey Shtylyov /* 234e4da5febSSergey Shtylyov * Perform a host adapter inquiry instead so we do not need to set 235e4da5febSSergey Shtylyov * up the mailboxes ahead of time 236e4da5febSSergey Shtylyov */ 2371da177e4SLinus Torvalds 23868ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_INQUIRY); 2391da177e4SLinus Torvalds 240cad2fc72SOndrej Zary for (i = 0; i < 4; i++) { 24168ea9de3SOndrej Zary if (!wait_mask(STATUS(sh->io_port), DF, DF, 0, 0)) 242a13b3722SOndrej Zary return 0; 24368ea9de3SOndrej Zary inquiry_result[i] = inb(DATA(sh->io_port)); 2441da177e4SLinus Torvalds } 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds /* Reading port should reset DF */ 24768ea9de3SOndrej Zary if (inb(STATUS(sh->io_port)) & DF) 248a13b3722SOndrej Zary return 0; 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* When HACC, command is completed, and we're though testing */ 25168ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), HACC, HACC, 0, 0)) 252a13b3722SOndrej Zary return 0; 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds /* Clear interrupts */ 25568ea9de3SOndrej Zary outb(IRST, CONTROL(sh->io_port)); 2561da177e4SLinus Torvalds 257bdebe224SOndrej Zary return 1; 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 2601794ef2bSChristoph Hellwig static void aha1542_free_cmd(struct scsi_cmnd *cmd) 2611794ef2bSChristoph Hellwig { 2621794ef2bSChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 2631794ef2bSChristoph Hellwig 264*2f2fef02SChristoph Hellwig if (cmd->sc_data_direction == DMA_FROM_DEVICE) { 265*2f2fef02SChristoph Hellwig void *buf = acmd->data_buffer; 266*2f2fef02SChristoph Hellwig struct req_iterator iter; 267*2f2fef02SChristoph Hellwig struct bio_vec bv; 268*2f2fef02SChristoph Hellwig 269*2f2fef02SChristoph Hellwig rq_for_each_segment(bv, cmd->request, iter) { 270*2f2fef02SChristoph Hellwig memcpy_to_page(bv.bv_page, bv.bv_offset, buf, 271*2f2fef02SChristoph Hellwig bv.bv_len); 272*2f2fef02SChristoph Hellwig buf += bv.bv_len; 273*2f2fef02SChristoph Hellwig } 2741794ef2bSChristoph Hellwig } 2751794ef2bSChristoph Hellwig 2761794ef2bSChristoph Hellwig scsi_dma_unmap(cmd); 2771794ef2bSChristoph Hellwig } 2781794ef2bSChristoph Hellwig 2791b0224b0SOndrej Zary static irqreturn_t aha1542_interrupt(int irq, void *dev_id) 2801da177e4SLinus Torvalds { 2811b0224b0SOndrej Zary struct Scsi_Host *sh = dev_id; 282c2532f68SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 28355b28f9fSOndrej Zary void (*my_done)(struct scsi_cmnd *) = NULL; 2841da177e4SLinus Torvalds int errstatus, mbi, mbo, mbistatus; 2851da177e4SLinus Torvalds int number_serviced; 2861da177e4SLinus Torvalds unsigned long flags; 28755b28f9fSOndrej Zary struct scsi_cmnd *tmp_cmd; 2881da177e4SLinus Torvalds int flag; 289e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 290e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds #ifdef DEBUG 2931da177e4SLinus Torvalds { 294c2532f68SOndrej Zary flag = inb(INTRFLAGS(sh->io_port)); 2952906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_intr_handle: "); 2961da177e4SLinus Torvalds if (!(flag & ANYINTR)) 2971da177e4SLinus Torvalds printk("no interrupt?"); 2981da177e4SLinus Torvalds if (flag & MBIF) 2991da177e4SLinus Torvalds printk("MBIF "); 3001da177e4SLinus Torvalds if (flag & MBOA) 3011da177e4SLinus Torvalds printk("MBOF "); 3021da177e4SLinus Torvalds if (flag & HACC) 3031da177e4SLinus Torvalds printk("HACC "); 3041da177e4SLinus Torvalds if (flag & SCRD) 3051da177e4SLinus Torvalds printk("SCRD "); 306c2532f68SOndrej Zary printk("status %02x\n", inb(STATUS(sh->io_port))); 3071da177e4SLinus Torvalds }; 3081da177e4SLinus Torvalds #endif 3091da177e4SLinus Torvalds number_serviced = 0; 3101da177e4SLinus Torvalds 3111b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 3121b0224b0SOndrej Zary while (1) { 313c2532f68SOndrej Zary flag = inb(INTRFLAGS(sh->io_port)); 3141da177e4SLinus Torvalds 315e4da5febSSergey Shtylyov /* 316e4da5febSSergey Shtylyov * Check for unusual interrupts. If any of these happen, we should 317e4da5febSSergey Shtylyov * probably do something special, but for now just printing a message 318e4da5febSSergey Shtylyov * is sufficient. A SCSI reset detected is something that we really 319e4da5febSSergey Shtylyov * need to deal with in some way. 320e4da5febSSergey Shtylyov */ 3211da177e4SLinus Torvalds if (flag & ~MBIF) { 3221da177e4SLinus Torvalds if (flag & MBOA) 3231da177e4SLinus Torvalds printk("MBOF "); 3241da177e4SLinus Torvalds if (flag & HACC) 3251da177e4SLinus Torvalds printk("HACC "); 326dfd7c991SOndrej Zary if (flag & SCRD) 3271da177e4SLinus Torvalds printk("SCRD "); 3281da177e4SLinus Torvalds } 329c2532f68SOndrej Zary aha1542_intr_reset(sh->io_port); 3301da177e4SLinus Torvalds 331e98878f7SOndrej Zary mbi = aha1542->aha1542_last_mbi_used + 1; 3321da177e4SLinus Torvalds if (mbi >= 2 * AHA1542_MAILBOXES) 3331da177e4SLinus Torvalds mbi = AHA1542_MAILBOXES; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds do { 3361da177e4SLinus Torvalds if (mb[mbi].status != 0) 3371da177e4SLinus Torvalds break; 3381da177e4SLinus Torvalds mbi++; 3391da177e4SLinus Torvalds if (mbi >= 2 * AHA1542_MAILBOXES) 3401da177e4SLinus Torvalds mbi = AHA1542_MAILBOXES; 341e98878f7SOndrej Zary } while (mbi != aha1542->aha1542_last_mbi_used); 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds if (mb[mbi].status == 0) { 3441b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 3451da177e4SLinus Torvalds /* Hmm, no mail. Must have read it the last time around */ 346dfd7c991SOndrej Zary if (!number_serviced) 3472906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n"); 3481b0224b0SOndrej Zary return IRQ_HANDLED; 3491da177e4SLinus Torvalds }; 3501da177e4SLinus Torvalds 351492ca4daSJames Bottomley mbo = (scsi2int(mb[mbi].ccbptr) - (unsigned long)aha1542->ccb_handle) / sizeof(struct ccb); 3521da177e4SLinus Torvalds mbistatus = mb[mbi].status; 3531da177e4SLinus Torvalds mb[mbi].status = 0; 354e98878f7SOndrej Zary aha1542->aha1542_last_mbi_used = mbi; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds #ifdef DEBUG 3571da177e4SLinus Torvalds if (ccb[mbo].tarstat | ccb[mbo].hastat) 3582906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_command: returning %x (status %d)\n", 3591da177e4SLinus Torvalds ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status); 3601da177e4SLinus Torvalds #endif 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds if (mbistatus == 3) 3631da177e4SLinus Torvalds continue; /* Aborted command not found */ 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds #ifdef DEBUG 3662906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "...done %d %d\n", mbo, mbi); 3671da177e4SLinus Torvalds #endif 3681da177e4SLinus Torvalds 36955b28f9fSOndrej Zary tmp_cmd = aha1542->int_cmds[mbo]; 3701da177e4SLinus Torvalds 37155b28f9fSOndrej Zary if (!tmp_cmd || !tmp_cmd->scsi_done) { 3721b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 3732906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "Unexpected interrupt\n"); 3742906b3ceSOndrej Zary shost_printk(KERN_WARNING, sh, "tarstat=%x, hastat=%x idlun=%x ccb#=%d\n", ccb[mbo].tarstat, 3751da177e4SLinus Torvalds ccb[mbo].hastat, ccb[mbo].idlun, mbo); 3761b0224b0SOndrej Zary return IRQ_HANDLED; 3771da177e4SLinus Torvalds } 37855b28f9fSOndrej Zary my_done = tmp_cmd->scsi_done; 3791794ef2bSChristoph Hellwig aha1542_free_cmd(tmp_cmd); 380e4da5febSSergey Shtylyov /* 381e4da5febSSergey Shtylyov * Fetch the sense data, and tuck it away, in the required slot. The 382e4da5febSSergey Shtylyov * Adaptec automatically fetches it, and there is no guarantee that 383e4da5febSSergey Shtylyov * we will still have it in the cdb when we come back 384e4da5febSSergey Shtylyov */ 3851da177e4SLinus Torvalds if (ccb[mbo].tarstat == 2) 38655b28f9fSOndrej Zary memcpy(tmp_cmd->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], 387b80ca4f7SFUJITA Tomonori SCSI_SENSE_BUFFERSIZE); 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds /* is there mail :-) */ 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds /* more error checking left out here */ 3931da177e4SLinus Torvalds if (mbistatus != 1) 3941da177e4SLinus Torvalds /* This is surely wrong, but I don't know what's right */ 3951da177e4SLinus Torvalds errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); 3961da177e4SLinus Torvalds else 3971da177e4SLinus Torvalds errstatus = 0; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds #ifdef DEBUG 4001da177e4SLinus Torvalds if (errstatus) 4012906b3ceSOndrej Zary shost_printk(KERN_DEBUG, sh, "(aha1542 error:%x %x %x) ", errstatus, 4021da177e4SLinus Torvalds ccb[mbo].hastat, ccb[mbo].tarstat); 4036ddc8cf4SOndrej Zary if (ccb[mbo].tarstat == 2) 4046ddc8cf4SOndrej Zary print_hex_dump_bytes("sense: ", DUMP_PREFIX_NONE, &ccb[mbo].cdb[ccb[mbo].cdblen], 12); 405fde1fb8aSOndrej Zary if (errstatus) 406fde1fb8aSOndrej Zary printk("aha1542_intr_handle: returning %6x\n", errstatus); 407fde1fb8aSOndrej Zary #endif 40855b28f9fSOndrej Zary tmp_cmd->result = errstatus; 40955b28f9fSOndrej Zary aha1542->int_cmds[mbo] = NULL; /* This effectively frees up the mailbox slot, as 410e4da5febSSergey Shtylyov * far as queuecommand is concerned 411e4da5febSSergey Shtylyov */ 41255b28f9fSOndrej Zary my_done(tmp_cmd); 4131da177e4SLinus Torvalds number_serviced++; 4141da177e4SLinus Torvalds }; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171b0224b0SOndrej Zary static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) 41809a44833SOndrej Zary { 4191794ef2bSChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 4202906b3ceSOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 421cb5b570cSOndrej Zary u8 direction; 42255b28f9fSOndrej Zary u8 target = cmd->device->id; 42355b28f9fSOndrej Zary u8 lun = cmd->device->lun; 4241da177e4SLinus Torvalds unsigned long flags; 42555b28f9fSOndrej Zary int bufflen = scsi_bufflen(cmd); 426*2f2fef02SChristoph Hellwig int mbo; 427e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 428e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 4291da177e4SLinus Torvalds 43055b28f9fSOndrej Zary if (*cmd->cmnd == REQUEST_SENSE) { 4311da177e4SLinus Torvalds /* Don't do the command - we have the sense data already */ 43255b28f9fSOndrej Zary cmd->result = 0; 4331b0224b0SOndrej Zary cmd->scsi_done(cmd); 4341da177e4SLinus Torvalds return 0; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds #ifdef DEBUG 437764a0c7eSOndrej Zary { 438764a0c7eSOndrej Zary int i = -1; 43955b28f9fSOndrej Zary if (*cmd->cmnd == READ_10 || *cmd->cmnd == WRITE_10) 44055b28f9fSOndrej Zary i = xscsi2int(cmd->cmnd + 2); 44155b28f9fSOndrej Zary else if (*cmd->cmnd == READ_6 || *cmd->cmnd == WRITE_6) 44255b28f9fSOndrej Zary i = scsi2int(cmd->cmnd + 2); 443764a0c7eSOndrej Zary shost_printk(KERN_DEBUG, sh, "aha1542_queuecommand: dev %d cmd %02x pos %d len %d", 444764a0c7eSOndrej Zary target, *cmd->cmnd, i, bufflen); 4456ddc8cf4SOndrej Zary print_hex_dump_bytes("command: ", DUMP_PREFIX_NONE, cmd->cmnd, cmd->cmd_len); 446764a0c7eSOndrej Zary } 4471da177e4SLinus Torvalds #endif 4481794ef2bSChristoph Hellwig 449*2f2fef02SChristoph Hellwig if (cmd->sc_data_direction == DMA_TO_DEVICE) { 450*2f2fef02SChristoph Hellwig void *buf = acmd->data_buffer; 451*2f2fef02SChristoph Hellwig struct req_iterator iter; 452*2f2fef02SChristoph Hellwig struct bio_vec bv; 453*2f2fef02SChristoph Hellwig 454*2f2fef02SChristoph Hellwig rq_for_each_segment(bv, cmd->request, iter) { 455*2f2fef02SChristoph Hellwig memcpy_from_page(buf, bv.bv_page, bv.bv_offset, 456*2f2fef02SChristoph Hellwig bv.bv_len); 457*2f2fef02SChristoph Hellwig buf += bv.bv_len; 458*2f2fef02SChristoph Hellwig } 4598c08a621SOndrej Zary } 4608c08a621SOndrej Zary 461e4da5febSSergey Shtylyov /* 462e4da5febSSergey Shtylyov * Use the outgoing mailboxes in a round-robin fashion, because this 463e4da5febSSergey Shtylyov * is how the host adapter will scan for them 464e4da5febSSergey Shtylyov */ 4651da177e4SLinus Torvalds 4661b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 467e98878f7SOndrej Zary mbo = aha1542->aha1542_last_mbo_used + 1; 4681da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 4691da177e4SLinus Torvalds mbo = 0; 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds do { 47255b28f9fSOndrej Zary if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) 4731da177e4SLinus Torvalds break; 4741da177e4SLinus Torvalds mbo++; 4751da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 4761da177e4SLinus Torvalds mbo = 0; 477e98878f7SOndrej Zary } while (mbo != aha1542->aha1542_last_mbo_used); 4781da177e4SLinus Torvalds 47955b28f9fSOndrej Zary if (mb[mbo].status || aha1542->int_cmds[mbo]) 4801da177e4SLinus Torvalds panic("Unable to find empty mailbox for aha1542.\n"); 4811da177e4SLinus Torvalds 48255b28f9fSOndrej Zary aha1542->int_cmds[mbo] = cmd; /* This will effectively prevent someone else from 483e4da5febSSergey Shtylyov * screwing with this cdb. 484e4da5febSSergey Shtylyov */ 4851da177e4SLinus Torvalds 486e98878f7SOndrej Zary aha1542->aha1542_last_mbo_used = mbo; 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds #ifdef DEBUG 4891b0224b0SOndrej Zary shost_printk(KERN_DEBUG, sh, "Sending command (%d %p)...", mbo, cmd->scsi_done); 4901da177e4SLinus Torvalds #endif 4911da177e4SLinus Torvalds 4921794ef2bSChristoph Hellwig /* This gets trashed for some reason */ 4931794ef2bSChristoph Hellwig any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds memset(&ccb[mbo], 0, sizeof(struct ccb)); 4961da177e4SLinus Torvalds 49755b28f9fSOndrej Zary ccb[mbo].cdblen = cmd->cmd_len; 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds direction = 0; 50055b28f9fSOndrej Zary if (*cmd->cmnd == READ_10 || *cmd->cmnd == READ_6) 5011da177e4SLinus Torvalds direction = 8; 50255b28f9fSOndrej Zary else if (*cmd->cmnd == WRITE_10 || *cmd->cmnd == WRITE_6) 5031da177e4SLinus Torvalds direction = 16; 5041da177e4SLinus Torvalds 50555b28f9fSOndrej Zary memcpy(ccb[mbo].cdb, cmd->cmnd, ccb[mbo].cdblen); 5061da177e4SLinus Torvalds ccb[mbo].op = 0; /* SCSI Initiator Command */ 507*2f2fef02SChristoph Hellwig any2scsi(ccb[mbo].datalen, bufflen); 508*2f2fef02SChristoph Hellwig if (bufflen) 509*2f2fef02SChristoph Hellwig any2scsi(ccb[mbo].dataptr, acmd->data_buffer_handle); 510*2f2fef02SChristoph Hellwig else 511fc3fdfccSBoaz Harrosh any2scsi(ccb[mbo].dataptr, 0); 5121da177e4SLinus Torvalds ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */ 5131da177e4SLinus Torvalds ccb[mbo].rsalen = 16; 5141da177e4SLinus Torvalds ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; 5151da177e4SLinus Torvalds ccb[mbo].commlinkid = 0; 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds #ifdef DEBUG 5186ddc8cf4SOndrej Zary print_hex_dump_bytes("sending: ", DUMP_PREFIX_NONE, &ccb[mbo], sizeof(ccb[mbo]) - 10); 519fde1fb8aSOndrej Zary printk("aha1542_queuecommand: now waiting for interrupt "); 520fde1fb8aSOndrej Zary #endif 5211da177e4SLinus Torvalds mb[mbo].status = 1; 52255b28f9fSOndrej Zary aha1542_outb(cmd->device->host->io_port, CMD_START_SCSI); 5231b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds return 0; 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds /* Initialize mailboxes */ 52968ea9de3SOndrej Zary static void setup_mailboxes(struct Scsi_Host *sh) 5301da177e4SLinus Torvalds { 531c2532f68SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 532cad2fc72SOndrej Zary u8 mb_cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; 5331794ef2bSChristoph Hellwig int i; 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds for (i = 0; i < AHA1542_MAILBOXES; i++) { 5361794ef2bSChristoph Hellwig aha1542->mb[i].status = 0; 5371794ef2bSChristoph Hellwig any2scsi(aha1542->mb[i].ccbptr, 5381794ef2bSChristoph Hellwig aha1542->ccb_handle + i * sizeof(struct ccb)); 5391794ef2bSChristoph Hellwig aha1542->mb[AHA1542_MAILBOXES + i].status = 0; 5401da177e4SLinus Torvalds }; 54168ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */ 5421794ef2bSChristoph Hellwig any2scsi(mb_cmd + 2, aha1542->mb_handle); 54368ea9de3SOndrej Zary if (aha1542_out(sh->io_port, mb_cmd, 5)) 5442906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "failed setting up mailboxes\n"); 54568ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 5461da177e4SLinus Torvalds } 5471da177e4SLinus Torvalds 54868ea9de3SOndrej Zary static int aha1542_getconfig(struct Scsi_Host *sh) 5491da177e4SLinus Torvalds { 550cb5b570cSOndrej Zary u8 inquiry_result[3]; 5511da177e4SLinus Torvalds int i; 55268ea9de3SOndrej Zary i = inb(STATUS(sh->io_port)); 5531da177e4SLinus Torvalds if (i & DF) { 55468ea9de3SOndrej Zary i = inb(DATA(sh->io_port)); 5551da177e4SLinus Torvalds }; 55668ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_RETCONF); 55768ea9de3SOndrej Zary aha1542_in(sh->io_port, inquiry_result, 3, 0); 55868ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) 5592906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "error querying board settings\n"); 56068ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 5611da177e4SLinus Torvalds switch (inquiry_result[0]) { 5621da177e4SLinus Torvalds case 0x80: 56368ea9de3SOndrej Zary sh->dma_channel = 7; 5641da177e4SLinus Torvalds break; 5651da177e4SLinus Torvalds case 0x40: 56668ea9de3SOndrej Zary sh->dma_channel = 6; 5671da177e4SLinus Torvalds break; 5681da177e4SLinus Torvalds case 0x20: 56968ea9de3SOndrej Zary sh->dma_channel = 5; 5701da177e4SLinus Torvalds break; 5711da177e4SLinus Torvalds case 0x01: 57268ea9de3SOndrej Zary sh->dma_channel = 0; 5731da177e4SLinus Torvalds break; 5741da177e4SLinus Torvalds case 0: 575e4da5febSSergey Shtylyov /* 576e4da5febSSergey Shtylyov * This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel. 577e4da5febSSergey Shtylyov * Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. 578e4da5febSSergey Shtylyov */ 57968ea9de3SOndrej Zary sh->dma_channel = 0xFF; 5801da177e4SLinus Torvalds break; 5811da177e4SLinus Torvalds default: 5822906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n"); 5831da177e4SLinus Torvalds return -1; 5841da177e4SLinus Torvalds }; 5851da177e4SLinus Torvalds switch (inquiry_result[1]) { 5861da177e4SLinus Torvalds case 0x40: 58768ea9de3SOndrej Zary sh->irq = 15; 5881da177e4SLinus Torvalds break; 5891da177e4SLinus Torvalds case 0x20: 59068ea9de3SOndrej Zary sh->irq = 14; 5911da177e4SLinus Torvalds break; 5921da177e4SLinus Torvalds case 0x8: 59368ea9de3SOndrej Zary sh->irq = 12; 5941da177e4SLinus Torvalds break; 5951da177e4SLinus Torvalds case 0x4: 59668ea9de3SOndrej Zary sh->irq = 11; 5971da177e4SLinus Torvalds break; 5981da177e4SLinus Torvalds case 0x2: 59968ea9de3SOndrej Zary sh->irq = 10; 6001da177e4SLinus Torvalds break; 6011da177e4SLinus Torvalds case 0x1: 60268ea9de3SOndrej Zary sh->irq = 9; 6031da177e4SLinus Torvalds break; 6041da177e4SLinus Torvalds default: 6052906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n"); 6061da177e4SLinus Torvalds return -1; 6071da177e4SLinus Torvalds }; 60868ea9de3SOndrej Zary sh->this_id = inquiry_result[2] & 7; 6091da177e4SLinus Torvalds return 0; 6101da177e4SLinus Torvalds } 6111da177e4SLinus Torvalds 612e4da5febSSergey Shtylyov /* 613e4da5febSSergey Shtylyov * This function should only be called for 1542C boards - we can detect 614e4da5febSSergey Shtylyov * the special firmware settings and unlock the board 615e4da5febSSergey Shtylyov */ 6161da177e4SLinus Torvalds 61768ea9de3SOndrej Zary static int aha1542_mbenable(struct Scsi_Host *sh) 6181da177e4SLinus Torvalds { 619cb5b570cSOndrej Zary static u8 mbenable_cmd[3]; 620cb5b570cSOndrej Zary static u8 mbenable_result[2]; 6211da177e4SLinus Torvalds int retval; 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds retval = BIOS_TRANSLATION_6432; 6241da177e4SLinus Torvalds 62568ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_EXTBIOS); 62668ea9de3SOndrej Zary if (aha1542_in(sh->io_port, mbenable_result, 2, 100)) 6271da177e4SLinus Torvalds return retval; 62868ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 100)) 6292093bfa1SOndrej Zary goto fail; 63068ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds if ((mbenable_result[0] & 0x08) || mbenable_result[1]) { 6331da177e4SLinus Torvalds mbenable_cmd[0] = CMD_MBENABLE; 6341da177e4SLinus Torvalds mbenable_cmd[1] = 0; 6351da177e4SLinus Torvalds mbenable_cmd[2] = mbenable_result[1]; 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03)) 6381da177e4SLinus Torvalds retval = BIOS_TRANSLATION_25563; 6391da177e4SLinus Torvalds 64068ea9de3SOndrej Zary if (aha1542_out(sh->io_port, mbenable_cmd, 3)) 6412093bfa1SOndrej Zary goto fail; 6421da177e4SLinus Torvalds }; 6431da177e4SLinus Torvalds while (0) { 6441da177e4SLinus Torvalds fail: 6452906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Mailbox init failed\n"); 6461da177e4SLinus Torvalds } 64768ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6481da177e4SLinus Torvalds return retval; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds /* Query the board to find out if it is a 1542 or a 1740, or whatever. */ 65268ea9de3SOndrej Zary static int aha1542_query(struct Scsi_Host *sh) 6531da177e4SLinus Torvalds { 65468ea9de3SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 655cb5b570cSOndrej Zary u8 inquiry_result[4]; 6561da177e4SLinus Torvalds int i; 65768ea9de3SOndrej Zary i = inb(STATUS(sh->io_port)); 6581da177e4SLinus Torvalds if (i & DF) { 65968ea9de3SOndrej Zary i = inb(DATA(sh->io_port)); 6601da177e4SLinus Torvalds }; 66168ea9de3SOndrej Zary aha1542_outb(sh->io_port, CMD_INQUIRY); 66268ea9de3SOndrej Zary aha1542_in(sh->io_port, inquiry_result, 4, 0); 66368ea9de3SOndrej Zary if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0)) 6642906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "error querying card type\n"); 66568ea9de3SOndrej Zary aha1542_intr_reset(sh->io_port); 6661da177e4SLinus Torvalds 66768ea9de3SOndrej Zary aha1542->bios_translation = BIOS_TRANSLATION_6432; /* Default case */ 6681da177e4SLinus Torvalds 669e4da5febSSergey Shtylyov /* 670e4da5febSSergey Shtylyov * For an AHA1740 series board, we ignore the board since there is a 671e4da5febSSergey Shtylyov * hardware bug which can lead to wrong blocks being returned if the board 672e4da5febSSergey Shtylyov * is operating in the 1542 emulation mode. Since there is an extended mode 673e4da5febSSergey Shtylyov * driver, we simply ignore the board and let the 1740 driver pick it up. 6741da177e4SLinus Torvalds */ 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds if (inquiry_result[0] == 0x43) { 6772906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n"); 6781da177e4SLinus Torvalds return 1; 6791da177e4SLinus Torvalds }; 6801da177e4SLinus Torvalds 681e4da5febSSergey Shtylyov /* 682e4da5febSSergey Shtylyov * Always call this - boards that do not support extended bios translation 683e4da5febSSergey Shtylyov * will ignore the command, and we will set the proper default 684e4da5febSSergey Shtylyov */ 6851da177e4SLinus Torvalds 68668ea9de3SOndrej Zary aha1542->bios_translation = aha1542_mbenable(sh); 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds return 0; 6891da177e4SLinus Torvalds } 6901da177e4SLinus Torvalds 691f71429abSOndrej Zary static u8 dma_speed_hw(int dma_speed) 6921da177e4SLinus Torvalds { 693f71429abSOndrej Zary switch (dma_speed) { 6941da177e4SLinus Torvalds case 5: 695f71429abSOndrej Zary return 0x00; 6961da177e4SLinus Torvalds case 6: 697f71429abSOndrej Zary return 0x04; 6981da177e4SLinus Torvalds case 7: 699f71429abSOndrej Zary return 0x01; 7001da177e4SLinus Torvalds case 8: 701f71429abSOndrej Zary return 0x02; 7021da177e4SLinus Torvalds case 10: 703f71429abSOndrej Zary return 0x03; 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 706f71429abSOndrej Zary return 0xff; /* invalid */ 7071da177e4SLinus Torvalds } 7081da177e4SLinus Torvalds 709b847fd0dSOndrej Zary /* Set the Bus on/off-times as not to ruin floppy performance */ 71037d607bdSOndrej Zary static void aha1542_set_bus_times(struct Scsi_Host *sh, int bus_on, int bus_off, int dma_speed) 711b847fd0dSOndrej Zary { 71237d607bdSOndrej Zary if (bus_on > 0) { 71337d607bdSOndrej Zary u8 oncmd[] = { CMD_BUSON_TIME, clamp(bus_on, 2, 15) }; 714b847fd0dSOndrej Zary 71537d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 71637d607bdSOndrej Zary if (aha1542_out(sh->io_port, oncmd, 2)) 717b847fd0dSOndrej Zary goto fail; 718f71429abSOndrej Zary } 719f71429abSOndrej Zary 72037d607bdSOndrej Zary if (bus_off > 0) { 72137d607bdSOndrej Zary u8 offcmd[] = { CMD_BUSOFF_TIME, clamp(bus_off, 1, 64) }; 722f71429abSOndrej Zary 72337d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 72437d607bdSOndrej Zary if (aha1542_out(sh->io_port, offcmd, 2)) 725b847fd0dSOndrej Zary goto fail; 726f71429abSOndrej Zary } 727f71429abSOndrej Zary 72837d607bdSOndrej Zary if (dma_speed_hw(dma_speed) != 0xff) { 72937d607bdSOndrej Zary u8 dmacmd[] = { CMD_DMASPEED, dma_speed_hw(dma_speed) }; 730f71429abSOndrej Zary 73137d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 73237d607bdSOndrej Zary if (aha1542_out(sh->io_port, dmacmd, 2)) 733b847fd0dSOndrej Zary goto fail; 734b847fd0dSOndrej Zary } 73537d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 736b847fd0dSOndrej Zary return; 737b847fd0dSOndrej Zary fail: 7382906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "setting bus on/off-time failed\n"); 73937d607bdSOndrej Zary aha1542_intr_reset(sh->io_port); 740b847fd0dSOndrej Zary } 741b847fd0dSOndrej Zary 7421da177e4SLinus Torvalds /* return non-zero on detection */ 743643a7c43SOndrej Zary static struct Scsi_Host *aha1542_hw_init(struct scsi_host_template *tpnt, struct device *pdev, int indx) 7441da177e4SLinus Torvalds { 745f71429abSOndrej Zary unsigned int base_io = io[indx]; 746c2532f68SOndrej Zary struct Scsi_Host *sh; 747e98878f7SOndrej Zary struct aha1542_hostdata *aha1542; 7482906b3ceSOndrej Zary char dma_info[] = "no DMA"; 7491da177e4SLinus Torvalds 7503a70c006SOndrej Zary if (base_io == 0) 751643a7c43SOndrej Zary return NULL; 7521da177e4SLinus Torvalds 7533a70c006SOndrej Zary if (!request_region(base_io, AHA1542_REGION_SIZE, "aha1542")) 7543a70c006SOndrej Zary return NULL; 7553a70c006SOndrej Zary 756c2532f68SOndrej Zary sh = scsi_host_alloc(tpnt, sizeof(struct aha1542_hostdata)); 757c2532f68SOndrej Zary if (!sh) 7583a70c006SOndrej Zary goto release; 759c2532f68SOndrej Zary aha1542 = shost_priv(sh); 7603a70c006SOndrej Zary 76168ea9de3SOndrej Zary sh->unique_id = base_io; 76268ea9de3SOndrej Zary sh->io_port = base_io; 76368ea9de3SOndrej Zary sh->n_io_port = AHA1542_REGION_SIZE; 76468ea9de3SOndrej Zary aha1542->aha1542_last_mbi_used = 2 * AHA1542_MAILBOXES - 1; 76568ea9de3SOndrej Zary aha1542->aha1542_last_mbo_used = AHA1542_MAILBOXES - 1; 76668ea9de3SOndrej Zary 76768ea9de3SOndrej Zary if (!aha1542_test_port(sh)) 7683a70c006SOndrej Zary goto unregister; 7691da177e4SLinus Torvalds 77037d607bdSOndrej Zary aha1542_set_bus_times(sh, bus_on[indx], bus_off[indx], dma_speed[indx]); 77168ea9de3SOndrej Zary if (aha1542_query(sh)) 7723a70c006SOndrej Zary goto unregister; 77368ea9de3SOndrej Zary if (aha1542_getconfig(sh) == -1) 7741da177e4SLinus Torvalds goto unregister; 7751da177e4SLinus Torvalds 776c2532f68SOndrej Zary if (sh->dma_channel != 0xFF) 7772906b3ceSOndrej Zary snprintf(dma_info, sizeof(dma_info), "DMA %d", sh->dma_channel); 7782906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Adaptec AHA-1542 (SCSI-ID %d) at IO 0x%x, IRQ %d, %s\n", 7792906b3ceSOndrej Zary sh->this_id, base_io, sh->irq, dma_info); 7803a70c006SOndrej Zary if (aha1542->bios_translation == BIOS_TRANSLATION_25563) 7812906b3ceSOndrej Zary shost_printk(KERN_INFO, sh, "Using extended bios translation\n"); 7821da177e4SLinus Torvalds 7831794ef2bSChristoph Hellwig if (dma_set_mask_and_coherent(pdev, DMA_BIT_MASK(24)) < 0) 7841794ef2bSChristoph Hellwig goto unregister; 7851794ef2bSChristoph Hellwig 7861794ef2bSChristoph Hellwig aha1542->mb = dma_alloc_coherent(pdev, 7871794ef2bSChristoph Hellwig AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), 7881794ef2bSChristoph Hellwig &aha1542->mb_handle, GFP_KERNEL); 7891794ef2bSChristoph Hellwig if (!aha1542->mb) 7901794ef2bSChristoph Hellwig goto unregister; 7911794ef2bSChristoph Hellwig 7921794ef2bSChristoph Hellwig aha1542->ccb = dma_alloc_coherent(pdev, 7931794ef2bSChristoph Hellwig AHA1542_MAILBOXES * sizeof(struct ccb), 7941794ef2bSChristoph Hellwig &aha1542->ccb_handle, GFP_KERNEL); 7951794ef2bSChristoph Hellwig if (!aha1542->ccb) 7961794ef2bSChristoph Hellwig goto free_mb; 7971794ef2bSChristoph Hellwig 79868ea9de3SOndrej Zary setup_mailboxes(sh); 7991da177e4SLinus Torvalds 8001b0224b0SOndrej Zary if (request_irq(sh->irq, aha1542_interrupt, 0, "aha1542", sh)) { 8012906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to allocate IRQ.\n"); 8021794ef2bSChristoph Hellwig goto free_ccb; 8031da177e4SLinus Torvalds } 804c2532f68SOndrej Zary if (sh->dma_channel != 0xFF) { 805c2532f68SOndrej Zary if (request_dma(sh->dma_channel, "aha1542")) { 8062906b3ceSOndrej Zary shost_printk(KERN_ERR, sh, "Unable to allocate DMA channel.\n"); 8073a70c006SOndrej Zary goto free_irq; 8081da177e4SLinus Torvalds } 809c2532f68SOndrej Zary if (sh->dma_channel == 0 || sh->dma_channel >= 5) { 810c2532f68SOndrej Zary set_dma_mode(sh->dma_channel, DMA_MODE_CASCADE); 811c2532f68SOndrej Zary enable_dma(sh->dma_channel); 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds } 81487c4d7bcSJeff Garzik 815c2532f68SOndrej Zary if (scsi_add_host(sh, pdev)) 8163a70c006SOndrej Zary goto free_dma; 8171da177e4SLinus Torvalds 818c2532f68SOndrej Zary scsi_scan_host(sh); 8191da177e4SLinus Torvalds 820c2532f68SOndrej Zary return sh; 8211794ef2bSChristoph Hellwig 8223a70c006SOndrej Zary free_dma: 823c2532f68SOndrej Zary if (sh->dma_channel != 0xff) 824c2532f68SOndrej Zary free_dma(sh->dma_channel); 8253a70c006SOndrej Zary free_irq: 826c2532f68SOndrej Zary free_irq(sh->irq, sh); 8271794ef2bSChristoph Hellwig free_ccb: 8281794ef2bSChristoph Hellwig dma_free_coherent(pdev, AHA1542_MAILBOXES * sizeof(struct ccb), 8291794ef2bSChristoph Hellwig aha1542->ccb, aha1542->ccb_handle); 8301794ef2bSChristoph Hellwig free_mb: 8311794ef2bSChristoph Hellwig dma_free_coherent(pdev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), 8321794ef2bSChristoph Hellwig aha1542->mb, aha1542->mb_handle); 8331da177e4SLinus Torvalds unregister: 834c2532f68SOndrej Zary scsi_host_put(sh); 8353a70c006SOndrej Zary release: 8363a70c006SOndrej Zary release_region(base_io, AHA1542_REGION_SIZE); 8371da177e4SLinus Torvalds 838643a7c43SOndrej Zary return NULL; 8391da177e4SLinus Torvalds } 8401da177e4SLinus Torvalds 841c2532f68SOndrej Zary static int aha1542_release(struct Scsi_Host *sh) 8421da177e4SLinus Torvalds { 8431794ef2bSChristoph Hellwig struct aha1542_hostdata *aha1542 = shost_priv(sh); 8441794ef2bSChristoph Hellwig struct device *dev = sh->dma_dev; 8451794ef2bSChristoph Hellwig 846c2532f68SOndrej Zary scsi_remove_host(sh); 847c2532f68SOndrej Zary if (sh->dma_channel != 0xff) 848c2532f68SOndrej Zary free_dma(sh->dma_channel); 8491794ef2bSChristoph Hellwig dma_free_coherent(dev, AHA1542_MAILBOXES * sizeof(struct ccb), 8501794ef2bSChristoph Hellwig aha1542->ccb, aha1542->ccb_handle); 8511794ef2bSChristoph Hellwig dma_free_coherent(dev, AHA1542_MAILBOXES * 2 * sizeof(struct mailbox), 8521794ef2bSChristoph Hellwig aha1542->mb, aha1542->mb_handle); 853c2532f68SOndrej Zary if (sh->irq) 854c2532f68SOndrej Zary free_irq(sh->irq, sh); 855c2532f68SOndrej Zary if (sh->io_port && sh->n_io_port) 856c2532f68SOndrej Zary release_region(sh->io_port, sh->n_io_port); 857c2532f68SOndrej Zary scsi_host_put(sh); 8581da177e4SLinus Torvalds return 0; 8591da177e4SLinus Torvalds } 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds 8621da177e4SLinus Torvalds /* 8631da177e4SLinus Torvalds * This is a device reset. This is handled by sending a special command 8641da177e4SLinus Torvalds * to the device. 8651da177e4SLinus Torvalds */ 86655b28f9fSOndrej Zary static int aha1542_dev_reset(struct scsi_cmnd *cmd) 8671da177e4SLinus Torvalds { 8681b0224b0SOndrej Zary struct Scsi_Host *sh = cmd->device->host; 8691b0224b0SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 8701da177e4SLinus Torvalds unsigned long flags; 871e98878f7SOndrej Zary struct mailbox *mb = aha1542->mb; 87255b28f9fSOndrej Zary u8 target = cmd->device->id; 87355b28f9fSOndrej Zary u8 lun = cmd->device->lun; 8741da177e4SLinus Torvalds int mbo; 875e98878f7SOndrej Zary struct ccb *ccb = aha1542->ccb; 8761da177e4SLinus Torvalds 8771b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 878e98878f7SOndrej Zary mbo = aha1542->aha1542_last_mbo_used + 1; 8791da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 8801da177e4SLinus Torvalds mbo = 0; 8811da177e4SLinus Torvalds 8821da177e4SLinus Torvalds do { 88355b28f9fSOndrej Zary if (mb[mbo].status == 0 && aha1542->int_cmds[mbo] == NULL) 8841da177e4SLinus Torvalds break; 8851da177e4SLinus Torvalds mbo++; 8861da177e4SLinus Torvalds if (mbo >= AHA1542_MAILBOXES) 8871da177e4SLinus Torvalds mbo = 0; 888e98878f7SOndrej Zary } while (mbo != aha1542->aha1542_last_mbo_used); 8891da177e4SLinus Torvalds 89055b28f9fSOndrej Zary if (mb[mbo].status || aha1542->int_cmds[mbo]) 8911da177e4SLinus Torvalds panic("Unable to find empty mailbox for aha1542.\n"); 8921da177e4SLinus Torvalds 89355b28f9fSOndrej Zary aha1542->int_cmds[mbo] = cmd; /* This will effectively 894e4da5febSSergey Shtylyov * prevent someone else from 895e4da5febSSergey Shtylyov * screwing with this cdb. 896e4da5febSSergey Shtylyov */ 8971da177e4SLinus Torvalds 898e98878f7SOndrej Zary aha1542->aha1542_last_mbo_used = mbo; 8991da177e4SLinus Torvalds 9001794ef2bSChristoph Hellwig /* This gets trashed for some reason */ 9011794ef2bSChristoph Hellwig any2scsi(mb[mbo].ccbptr, aha1542->ccb_handle + mbo * sizeof(*ccb)); 9021da177e4SLinus Torvalds 9031da177e4SLinus Torvalds memset(&ccb[mbo], 0, sizeof(struct ccb)); 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds ccb[mbo].op = 0x81; /* BUS DEVICE RESET */ 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */ 9081da177e4SLinus Torvalds 9091da177e4SLinus Torvalds ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; 9101da177e4SLinus Torvalds ccb[mbo].commlinkid = 0; 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds /* 9131da177e4SLinus Torvalds * Now tell the 1542 to flush all pending commands for this 9141da177e4SLinus Torvalds * target 9151da177e4SLinus Torvalds */ 9161b0224b0SOndrej Zary aha1542_outb(sh->io_port, CMD_START_SCSI); 9171b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 9181da177e4SLinus Torvalds 91955b28f9fSOndrej Zary scmd_printk(KERN_WARNING, cmd, 920017560fcSJeff Garzik "Trying device reset for target\n"); 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds return SUCCESS; 9231da177e4SLinus Torvalds } 9241da177e4SLinus Torvalds 92555b28f9fSOndrej Zary static int aha1542_reset(struct scsi_cmnd *cmd, u8 reset_cmd) 9261da177e4SLinus Torvalds { 9271b0224b0SOndrej Zary struct Scsi_Host *sh = cmd->device->host; 9281b0224b0SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sh); 9291b0224b0SOndrej Zary unsigned long flags; 9301da177e4SLinus Torvalds int i; 9311da177e4SLinus Torvalds 9321b0224b0SOndrej Zary spin_lock_irqsave(sh->host_lock, flags); 9331da177e4SLinus Torvalds /* 9341da177e4SLinus Torvalds * This does a scsi reset for all devices on the bus. 9351da177e4SLinus Torvalds * In principle, we could also reset the 1542 - should 9361da177e4SLinus Torvalds * we do this? Try this first, and we can add that later 9371da177e4SLinus Torvalds * if it turns out to be useful. 9381da177e4SLinus Torvalds */ 93955b28f9fSOndrej Zary outb(reset_cmd, CONTROL(cmd->device->host->io_port)); 9401da177e4SLinus Torvalds 94155b28f9fSOndrej Zary if (!wait_mask(STATUS(cmd->device->host->io_port), 9427061dec4SOndrej Zary STATMASK, IDLE, STST | DIAGF | INVDCMD | DF | CDF, 0)) { 9431b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 944a13b3722SOndrej Zary return FAILED; 945a13b3722SOndrej Zary } 9461b0224b0SOndrej Zary 9471da177e4SLinus Torvalds /* 9481da177e4SLinus Torvalds * We need to do this too before the 1542 can interact with 9498537cba8SOndrej Zary * us again after host reset. 9501da177e4SLinus Torvalds */ 9518537cba8SOndrej Zary if (reset_cmd & HRST) 95268ea9de3SOndrej Zary setup_mailboxes(cmd->device->host); 9531b0224b0SOndrej Zary 9541da177e4SLinus Torvalds /* 9551da177e4SLinus Torvalds * Now try to pick up the pieces. For all pending commands, 9561da177e4SLinus Torvalds * free any internal data structures, and basically clear things 9571da177e4SLinus Torvalds * out. We do not try and restart any commands or anything - 9581da177e4SLinus Torvalds * the strategy handler takes care of that crap. 9591da177e4SLinus Torvalds */ 9602906b3ceSOndrej Zary shost_printk(KERN_WARNING, cmd->device->host, "Sent BUS RESET to scsi host %d\n", cmd->device->host->host_no); 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds for (i = 0; i < AHA1542_MAILBOXES; i++) { 96355b28f9fSOndrej Zary if (aha1542->int_cmds[i] != NULL) { 96455b28f9fSOndrej Zary struct scsi_cmnd *tmp_cmd; 96555b28f9fSOndrej Zary tmp_cmd = aha1542->int_cmds[i]; 9661da177e4SLinus Torvalds 96755b28f9fSOndrej Zary if (tmp_cmd->device->soft_reset) { 9681da177e4SLinus Torvalds /* 9691da177e4SLinus Torvalds * If this device implements the soft reset option, 9701da177e4SLinus Torvalds * then it is still holding onto the command, and 9711da177e4SLinus Torvalds * may yet complete it. In this case, we don't 9721da177e4SLinus Torvalds * flush the data. 9731da177e4SLinus Torvalds */ 9741da177e4SLinus Torvalds continue; 9751da177e4SLinus Torvalds } 9761794ef2bSChristoph Hellwig aha1542_free_cmd(tmp_cmd); 97755b28f9fSOndrej Zary aha1542->int_cmds[i] = NULL; 978e98878f7SOndrej Zary aha1542->mb[i].status = 0; 9791da177e4SLinus Torvalds } 9801da177e4SLinus Torvalds } 9811da177e4SLinus Torvalds 9821b0224b0SOndrej Zary spin_unlock_irqrestore(sh->host_lock, flags); 9831da177e4SLinus Torvalds return SUCCESS; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 98655b28f9fSOndrej Zary static int aha1542_bus_reset(struct scsi_cmnd *cmd) 9878537cba8SOndrej Zary { 98855b28f9fSOndrej Zary return aha1542_reset(cmd, SCRST); 9898537cba8SOndrej Zary } 9908537cba8SOndrej Zary 99155b28f9fSOndrej Zary static int aha1542_host_reset(struct scsi_cmnd *cmd) 9928537cba8SOndrej Zary { 99355b28f9fSOndrej Zary return aha1542_reset(cmd, HRST | SCRST); 9948537cba8SOndrej Zary } 9958537cba8SOndrej Zary 9961da177e4SLinus Torvalds static int aha1542_biosparam(struct scsi_device *sdev, 99717787a09SOndrej Zary struct block_device *bdev, sector_t capacity, int geom[]) 9981da177e4SLinus Torvalds { 999e98878f7SOndrej Zary struct aha1542_hostdata *aha1542 = shost_priv(sdev->host); 10001da177e4SLinus Torvalds 100117787a09SOndrej Zary if (capacity >= 0x200000 && 100217787a09SOndrej Zary aha1542->bios_translation == BIOS_TRANSLATION_25563) { 10031da177e4SLinus Torvalds /* Please verify that this is the same as what DOS returns */ 100417787a09SOndrej Zary geom[0] = 255; /* heads */ 100517787a09SOndrej Zary geom[1] = 63; /* sectors */ 10061da177e4SLinus Torvalds } else { 100717787a09SOndrej Zary geom[0] = 64; /* heads */ 100817787a09SOndrej Zary geom[1] = 32; /* sectors */ 10091da177e4SLinus Torvalds } 101017787a09SOndrej Zary geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */ 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds return 0; 10131da177e4SLinus Torvalds } 10141da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 10151da177e4SLinus Torvalds 1016*2f2fef02SChristoph Hellwig static int aha1542_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) 1017*2f2fef02SChristoph Hellwig { 1018*2f2fef02SChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 1019*2f2fef02SChristoph Hellwig 1020*2f2fef02SChristoph Hellwig acmd->data_buffer = dma_alloc_coherent(shost->dma_dev, 1021*2f2fef02SChristoph Hellwig SECTOR_SIZE * AHA1542_MAX_SECTORS, 1022*2f2fef02SChristoph Hellwig &acmd->data_buffer_handle, GFP_KERNEL); 1023*2f2fef02SChristoph Hellwig if (!acmd->data_buffer) 1024*2f2fef02SChristoph Hellwig return -ENOMEM; 1025*2f2fef02SChristoph Hellwig return 0; 1026*2f2fef02SChristoph Hellwig } 1027*2f2fef02SChristoph Hellwig 1028*2f2fef02SChristoph Hellwig static int aha1542_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) 1029*2f2fef02SChristoph Hellwig { 1030*2f2fef02SChristoph Hellwig struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); 1031*2f2fef02SChristoph Hellwig 1032*2f2fef02SChristoph Hellwig dma_free_coherent(shost->dma_dev, SECTOR_SIZE * AHA1542_MAX_SECTORS, 1033*2f2fef02SChristoph Hellwig acmd->data_buffer, acmd->data_buffer_handle); 1034*2f2fef02SChristoph Hellwig return 0; 1035*2f2fef02SChristoph Hellwig } 1036*2f2fef02SChristoph Hellwig 1037d0be4a7dSChristoph Hellwig static 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, 1047*2f2fef02SChristoph Hellwig .init_cmd_priv = aha1542_init_cmd_priv, 1048*2f2fef02SChristoph Hellwig .exit_cmd_priv = aha1542_exit_cmd_priv, 10491da177e4SLinus Torvalds .can_queue = AHA1542_MAILBOXES, 10501da177e4SLinus Torvalds .this_id = 7, 1051*2f2fef02SChristoph Hellwig .max_sectors = AHA1542_MAX_SECTORS, 1052*2f2fef02SChristoph 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