X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Fa100u2w.c;h=f608d4a1d6daeaa8b44ca46d25cb3fe2b3cc2276;hb=f18816ba20655deb3227da0600d5c34201467993;hp=7f4241bfb9c437dcadf63f21913f803cccfdbae7;hpb=2aa6eb313e57a8254b17e60b8bb5e0a2570d7776;p=linux-2.6-omap-h63xx.git diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index 7f4241bfb9c..f608d4a1d6d 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -19,27 +19,6 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - * -------------------------------------------------------------------------- - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU General Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -75,6 +54,8 @@ * 9/28/04 Christoph Hellwig * - merge the two source files * - remove internal queueing code + * 14/06/07 Alan Cox + * - Grand cleanup and Linuxisation */ #include @@ -102,14 +83,12 @@ #include "a100u2w.h" -#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ) -#define MS_TO_JIFFIES(j) ((j * HZ) / 1000) +static struct orc_scb *__orc_alloc_scb(struct orc_host * host); +static void inia100_scb_handler(struct orc_host *host, struct orc_scb *scb); -static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp); -static void inia100SCBPost(BYTE * pHcb, BYTE * pScb); +static struct orc_nvram nvram, *nvramp = &nvram; -static NVRAM nvram, *nvramp = &nvram; -static UCHAR dftNvRam[64] = +static u8 default_nvram[64] = { /*----------header -------------*/ 0x01, /* 0x00: Sub System Vendor ID 0 */ @@ -158,823 +137,882 @@ static UCHAR dftNvRam[64] = }; -/***************************************************************************/ -static void waitForPause(unsigned amount) -{ - ULONG the_time = jiffies + MS_TO_JIFFIES(amount); - while (time_before_eq(jiffies, the_time)) - cpu_relax(); -} - -/***************************************************************************/ -static UCHAR waitChipReady(ORC_HCS * hcsp) +static u8 wait_chip_ready(struct orc_host * host) { int i; for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */ + if (inb(host->base + ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */ return 1; - waitForPause(100); /* wait 100ms before try again */ + mdelay(100); } return 0; } -/***************************************************************************/ -static UCHAR waitFWReady(ORC_HCS * hcsp) +static u8 wait_firmware_ready(struct orc_host * host) { int i; for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) /* Wait READY set */ + if (inb(host->base + ORC_HSTUS) & RREADY) /* Wait READY set */ return 1; - waitForPause(100); /* wait 100ms before try again */ + mdelay(100); /* wait 100ms before try again */ } return 0; } /***************************************************************************/ -static UCHAR waitSCSIRSTdone(ORC_HCS * hcsp) +static u8 wait_scsi_reset_done(struct orc_host * host) { int i; for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */ + if (!(inb(host->base + ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */ return 1; - waitForPause(100); /* wait 100ms before try again */ + mdelay(100); /* wait 100ms before try again */ } return 0; } /***************************************************************************/ -static UCHAR waitHDOoff(ORC_HCS * hcsp) +static u8 wait_HDO_off(struct orc_host * host) { int i; for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO)) /* Wait HDO off */ + if (!(inb(host->base + ORC_HCTRL) & HDO)) /* Wait HDO off */ return 1; - waitForPause(100); /* wait 100ms before try again */ + mdelay(100); /* wait 100ms before try again */ } return 0; } /***************************************************************************/ -static UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData) +static u8 wait_hdi_set(struct orc_host * host, u8 * data) { int i; for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI) + if ((*data = inb(host->base + ORC_HSTUS)) & HDI) return 1; /* Wait HDI set */ - waitForPause(100); /* wait 100ms before try again */ + mdelay(100); /* wait 100ms before try again */ } return 0; } /***************************************************************************/ -static unsigned short get_FW_version(ORC_HCS * hcsp) +static unsigned short orc_read_fwrev(struct orc_host * host) { - UCHAR bData; - union { - unsigned short sVersion; - unsigned char cVersion[2]; - } Version; - - ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_VERSION); - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); - if (waitHDOoff(hcsp) == 0) /* Wait HDO off */ + u16 version; + u8 data; + + outb(ORC_CMD_VERSION, host->base + ORC_HDATA); + outb(HDO, host->base + ORC_HCTRL); + if (wait_HDO_off(host) == 0) /* Wait HDO off */ return 0; - if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */ + if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */ return 0; - Version.cVersion[0] = ORC_RD(hcsp->HCS_Base, ORC_HDATA); - ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + version = inb(host->base + ORC_HDATA); + outb(data, host->base + ORC_HSTUS); /* Clear HDI */ - if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */ + if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */ return 0; - Version.cVersion[1] = ORC_RD(hcsp->HCS_Base, ORC_HDATA); - ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + version |= inb(host->base + ORC_HDATA) << 8; + outb(data, host->base + ORC_HSTUS); /* Clear HDI */ - return (Version.sVersion); + return version; } /***************************************************************************/ -static UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value) +static u8 orc_nv_write(struct orc_host * host, unsigned char address, unsigned char value) { - ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_SET_NVM); /* Write command */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); - if (waitHDOoff(hcsp) == 0) /* Wait HDO off */ + outb(ORC_CMD_SET_NVM, host->base + ORC_HDATA); /* Write command */ + outb(HDO, host->base + ORC_HCTRL); + if (wait_HDO_off(host) == 0) /* Wait HDO off */ return 0; - ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); - if (waitHDOoff(hcsp) == 0) /* Wait HDO off */ + outb(address, host->base + ORC_HDATA); /* Write address */ + outb(HDO, host->base + ORC_HCTRL); + if (wait_HDO_off(host) == 0) /* Wait HDO off */ return 0; - ORC_WR(hcsp->HCS_Base + ORC_HDATA, value); /* Write value */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); - if (waitHDOoff(hcsp) == 0) /* Wait HDO off */ + outb(value, host->base + ORC_HDATA); /* Write value */ + outb(HDO, host->base + ORC_HCTRL); + if (wait_HDO_off(host) == 0) /* Wait HDO off */ return 0; return 1; } /***************************************************************************/ -static UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn) +static u8 orc_nv_read(struct orc_host * host, u8 address, u8 *ptr) { - unsigned char bData; + unsigned char data; - ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_GET_NVM); /* Write command */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); - if (waitHDOoff(hcsp) == 0) /* Wait HDO off */ + outb(ORC_CMD_GET_NVM, host->base + ORC_HDATA); /* Write command */ + outb(HDO, host->base + ORC_HCTRL); + if (wait_HDO_off(host) == 0) /* Wait HDO off */ return 0; - ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); - if (waitHDOoff(hcsp) == 0) /* Wait HDO off */ + outb(address, host->base + ORC_HDATA); /* Write address */ + outb(HDO, host->base + ORC_HCTRL); + if (wait_HDO_off(host) == 0) /* Wait HDO off */ return 0; - if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */ + if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */ return 0; - *pDataIn = ORC_RD(hcsp->HCS_Base, ORC_HDATA); - ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + *ptr = inb(host->base + ORC_HDATA); + outb(data, host->base + ORC_HSTUS); /* Clear HDI */ return 1; + } -/***************************************************************************/ -static void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp) +/** + * orc_exec_sb - Queue an SCB with the HA + * @host: host adapter the SCB belongs to + * @scb: SCB to queue for execution + */ + +static void orc_exec_scb(struct orc_host * host, struct orc_scb * scb) { - scbp->SCB_Status = ORCSCB_POST; - ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx); - return; + scb->status = ORCSCB_POST; + outb(scb->scbidx, host->base + ORC_PQUEUE); } -/*********************************************************************** - Read SCSI H/A configuration parameters from serial EEPROM -************************************************************************/ -static int se2_rd_all(ORC_HCS * hcsp) +/** + * se2_rd_all - read SCSI parameters from EEPROM + * @host: Host whose EEPROM is being loaded + * + * Read SCSI H/A configuration parameters from serial EEPROM + */ + +static int se2_rd_all(struct orc_host * host) { int i; - UCHAR *np, chksum = 0; + u8 *np, chksum = 0; - np = (UCHAR *) nvramp; + np = (u8 *) nvramp; for (i = 0; i < 64; i++, np++) { /* <01> */ - if (get_NVRAM(hcsp, (unsigned char) i, np) == 0) + if (orc_nv_read(host, (u8) i, np) == 0) return -1; -// *np++ = get_NVRAM(hcsp, (unsigned char ) i); } -/*------ Is ckecksum ok ? ------*/ - np = (UCHAR *) nvramp; + /*------ Is ckecksum ok ? ------*/ + np = (u8 *) nvramp; for (i = 0; i < 63; i++) chksum += *np++; - if (nvramp->CheckSum != (UCHAR) chksum) + if (nvramp->CheckSum != (u8) chksum) return -1; return 1; } -/************************************************************************ - Update SCSI H/A configuration parameters from serial EEPROM -*************************************************************************/ -static void se2_update_all(ORC_HCS * hcsp) +/** + * se2_update_all - update the EEPROM + * @host: Host whose EEPROM is being updated + * + * Update changed bytes in the EEPROM image. + */ + +static void se2_update_all(struct orc_host * host) { /* setup default pattern */ int i; - UCHAR *np, *np1, chksum = 0; + u8 *np, *np1, chksum = 0; /* Calculate checksum first */ - np = (UCHAR *) dftNvRam; + np = (u8 *) default_nvram; for (i = 0; i < 63; i++) chksum += *np++; *np = chksum; - np = (UCHAR *) dftNvRam; - np1 = (UCHAR *) nvramp; + np = (u8 *) default_nvram; + np1 = (u8 *) nvramp; for (i = 0; i < 64; i++, np++, np1++) { - if (*np != *np1) { - set_NVRAM(hcsp, (unsigned char) i, *np); - } + if (*np != *np1) + orc_nv_write(host, (u8) i, *np); } - return; } -/************************************************************************* - Function name : read_eeprom -**************************************************************************/ -static void read_eeprom(ORC_HCS * hcsp) +/** + * read_eeprom - load EEPROM + * @host: Host EEPROM to read + * + * Read the EEPROM for a given host. If it is invalid or fails + * the restore the defaults and use them. + */ + +static void read_eeprom(struct orc_host * host) { - if (se2_rd_all(hcsp) != 1) { - se2_update_all(hcsp); /* setup default pattern */ - se2_rd_all(hcsp); /* load again */ + if (se2_rd_all(host) != 1) { + se2_update_all(host); /* setup default pattern */ + se2_rd_all(host); /* load again */ } } -/***************************************************************************/ -static UCHAR load_FW(ORC_HCS * hcsp) +/** + * orc_load_firmware - initialise firmware + * @host: Host to set up + * + * Load the firmware from the EEPROM into controller SRAM. This + * is basically a 4K block copy and then a 4K block read to check + * correctness. The rest is convulted by the indirect interfaces + * in the hardware + */ + +static u8 orc_load_firmware(struct orc_host * host) { - U32 dData; - USHORT wBIOSAddress; - USHORT i; - UCHAR *pData, bData; - - - bData = ORC_RD(hcsp->HCS_Base, ORC_GCFG); - ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData | EEPRG); /* Enable EEPROM programming */ - ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, 0x00); - ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x00); - if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0x55) { - ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */ + u32 data32; + u16 bios_addr; + u16 i; + u8 *data32_ptr, data; + + + /* Set up the EEPROM for access */ + + data = inb(host->base + ORC_GCFG); + outb(data | EEPRG, host->base + ORC_GCFG); /* Enable EEPROM programming */ + outb(0x00, host->base + ORC_EBIOSADR2); + outw(0x0000, host->base + ORC_EBIOSADR0); + if (inb(host->base + ORC_EBIOSDATA) != 0x55) { + outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */ return 0; } - ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x01); - if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0xAA) { - ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */ + outw(0x0001, host->base + ORC_EBIOSADR0); + if (inb(host->base + ORC_EBIOSDATA) != 0xAA) { + outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */ return 0; } - ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Enable SRAM programming */ - pData = (UCHAR *) & dData; - dData = 0; /* Initial FW address to 0 */ - ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x10); - *pData = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ - ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x11); - *(pData + 1) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ - ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x12); - *(pData + 2) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ - ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, *(pData + 2)); - ORC_WRLONG(hcsp->HCS_Base + ORC_FWBASEADR, dData); /* Write FW address */ - - wBIOSAddress = (USHORT) dData; /* FW code locate at BIOS address + ? */ - for (i = 0, pData = (UCHAR *) & dData; /* Download the code */ + + outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Enable SRAM programming */ + data32_ptr = (u8 *) & data32; + data32 = 0; /* Initial FW address to 0 */ + outw(0x0010, host->base + ORC_EBIOSADR0); + *data32_ptr = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ + outw(0x0011, host->base + ORC_EBIOSADR0); + *(data32_ptr + 1) = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ + outw(0x0012, host->base + ORC_EBIOSADR0); + *(data32_ptr + 2) = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ + outw(*(data32_ptr + 2), host->base + ORC_EBIOSADR2); + outl(data32, host->base + ORC_FWBASEADR); /* Write FW address */ + + /* Copy the code from the BIOS to the SRAM */ + + bios_addr = (u16) data32; /* FW code locate at BIOS address + ? */ + for (i = 0, data32_ptr = (u8 *) & data32; /* Download the code */ i < 0x1000; /* Firmware code size = 4K */ - i++, wBIOSAddress++) { - ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress); - *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + i++, bios_addr++) { + outw(bios_addr, host->base + ORC_EBIOSADR0); + *data32_ptr++ = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ if ((i % 4) == 3) { - ORC_WRLONG(hcsp->HCS_Base + ORC_RISCRAM, dData); /* Write every 4 bytes */ - pData = (UCHAR *) & dData; + outl(data32, host->base + ORC_RISCRAM); /* Write every 4 bytes */ + data32_ptr = (u8 *) & data32; } } - ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Reset program count 0 */ - wBIOSAddress -= 0x1000; /* Reset the BIOS adddress */ - for (i = 0, pData = (UCHAR *) & dData; /* Check the code */ + /* Go back and check they match */ + + outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Reset program count 0 */ + bios_addr -= 0x1000; /* Reset the BIOS adddress */ + for (i = 0, data32_ptr = (u8 *) & data32; /* Check the code */ i < 0x1000; /* Firmware code size = 4K */ - i++, wBIOSAddress++) { - ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress); - *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */ + i++, bios_addr++) { + outw(bios_addr, host->base + ORC_EBIOSADR0); + *data32_ptr++ = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ if ((i % 4) == 3) { - if (ORC_RDLONG(hcsp->HCS_Base, ORC_RISCRAM) != dData) { - ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */ - ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /*Disable EEPROM programming */ + if (inl(host->base + ORC_RISCRAM) != data32) { + outb(PRGMRST, host->base + ORC_RISCCTL); /* Reset program to 0 */ + outb(data, host->base + ORC_GCFG); /*Disable EEPROM programming */ return 0; } - pData = (UCHAR *) & dData; + data32_ptr = (u8 *) & data32; } } - ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */ - ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */ + + /* Success */ + outb(PRGMRST, host->base + ORC_RISCCTL); /* Reset program to 0 */ + outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */ return 1; } /***************************************************************************/ -static void setup_SCBs(ORC_HCS * hcsp) +static void setup_SCBs(struct orc_host * host) { - ORC_SCB *pVirScb; + struct orc_scb *scb; int i; - ESCB *pVirEscb; - dma_addr_t pPhysEscb; + struct orc_extended_scb *escb; + dma_addr_t escb_phys; - /* Setup SCB HCS_Base and SCB Size registers */ - ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, ORC_MAXQUEUE); /* Total number of SCBs */ - /* SCB HCS_Base address 0 */ - ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray); - /* SCB HCS_Base address 1 */ - ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray); + /* Setup SCB base and SCB Size registers */ + outb(ORC_MAXQUEUE, host->base + ORC_SCBSIZE); /* Total number of SCBs */ + /* SCB base address 0 */ + outl(host->scb_phys, host->base + ORC_SCBBASE0); + /* SCB base address 1 */ + outl(host->scb_phys, host->base + ORC_SCBBASE1); /* setup scatter list address with one buffer */ - pVirScb = hcsp->HCS_virScbArray; - pVirEscb = hcsp->HCS_virEscbArray; + scb = host->scb_virt; + escb = host->escb_virt; for (i = 0; i < ORC_MAXQUEUE; i++) { - pPhysEscb = (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i)); - pVirScb->SCB_SGPAddr = (U32) pPhysEscb; - pVirScb->SCB_SensePAddr = (U32) pPhysEscb; - pVirScb->SCB_EScb = pVirEscb; - pVirScb->SCB_ScbIdx = i; - pVirScb++; - pVirEscb++; + escb_phys = (host->escb_phys + (sizeof(struct orc_extended_scb) * i)); + scb->sg_addr = (u32) escb_phys; + scb->sense_addr = (u32) escb_phys; + scb->escb = escb; + scb->scbidx = i; + scb++; + escb++; } - - return; } -/***************************************************************************/ -static void initAFlag(ORC_HCS * hcsp) +/** + * init_alloc_map - initialise allocation map + * @host: host map to configure + * + * Initialise the allocation maps for this device. If the device + * is not quiescent the caller must hold the allocation lock + */ + +static void init_alloc_map(struct orc_host * host) { - UCHAR i, j; + u8 i, j; for (i = 0; i < MAX_CHANNELS; i++) { for (j = 0; j < 8; j++) { - hcsp->BitAllocFlag[i][j] = 0xffffffff; + host->allocation_map[i][j] = 0xffffffff; } } } -/***************************************************************************/ -static int init_orchid(ORC_HCS * hcsp) +/** + * init_orchid - initialise the host adapter + * @host:host adapter to initialise + * + * Initialise the controller and if neccessary load the firmware. + * + * Returns -1 if the initialisation fails. + */ + +static int init_orchid(struct orc_host * host) { - UBYTE *readBytep; - USHORT revision; - UCHAR i; - - initAFlag(hcsp); - ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF); /* Disable all interrupt */ - if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) { /* Orchid is ready */ - revision = get_FW_version(hcsp); + u8 *ptr; + u16 revision; + u8 i; + + init_alloc_map(host); + outb(0xFF, host->base + ORC_GIMSK); /* Disable all interrupts */ + + if (inb(host->base + ORC_HSTUS) & RREADY) { /* Orchid is ready */ + revision = orc_read_fwrev(host); if (revision == 0xFFFF) { - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */ - if (waitChipReady(hcsp) == 0) - return (-1); - load_FW(hcsp); /* Download FW */ - setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0); /* clear HOSTSTOP */ - if (waitFWReady(hcsp) == 0) - return (-1); + outb(DEVRST, host->base + ORC_HCTRL); /* Reset Host Adapter */ + if (wait_chip_ready(host) == 0) + return -1; + orc_load_firmware(host); /* Download FW */ + setup_SCBs(host); /* Setup SCB base and SCB Size registers */ + outb(0x00, host->base + ORC_HCTRL); /* clear HOSTSTOP */ + if (wait_firmware_ready(host) == 0) + return -1; /* Wait for firmware ready */ } else { - setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ + setup_SCBs(host); /* Setup SCB base and SCB Size registers */ } } else { /* Orchid is not Ready */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */ - if (waitChipReady(hcsp) == 0) - return (-1); - load_FW(hcsp); /* Download FW */ - setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); /* Do Hardware Reset & */ + outb(DEVRST, host->base + ORC_HCTRL); /* Reset Host Adapter */ + if (wait_chip_ready(host) == 0) + return -1; + orc_load_firmware(host); /* Download FW */ + setup_SCBs(host); /* Setup SCB base and SCB Size registers */ + outb(HDO, host->base + ORC_HCTRL); /* Do Hardware Reset & */ /* clear HOSTSTOP */ - if (waitFWReady(hcsp) == 0) /* Wait for firmware ready */ - return (-1); + if (wait_firmware_ready(host) == 0) /* Wait for firmware ready */ + return -1; } -/*------------- get serial EEProm settting -------*/ - - read_eeprom(hcsp); - - if (nvramp->Revision != 1) - return (-1); + /* Load an EEProm copy into RAM */ + /* Assumes single threaded at this point */ + read_eeprom(host); - hcsp->HCS_SCSI_ID = nvramp->SCSI0Id; - hcsp->HCS_BIOS = nvramp->BIOSConfig1; - hcsp->HCS_MaxTar = MAX_TARGETS; - readBytep = (UCHAR *) & (nvramp->Target00Config); - for (i = 0; i < 16; readBytep++, i++) { - hcsp->TargetFlag[i] = *readBytep; - hcsp->MaximumTags[i] = ORC_MAXTAGS; - } /* for */ + if (nvramp->revision != 1) + return -1; - if (nvramp->SCSI0Config & NCC_BUSRESET) { /* Reset SCSI bus */ - hcsp->HCS_Flags |= HCF_SCSI_RESET; + host->scsi_id = nvramp->scsi_id; + host->BIOScfg = nvramp->BIOSConfig1; + host->max_targets = MAX_TARGETS; + ptr = (u8 *) & (nvramp->Target00Config); + for (i = 0; i < 16; ptr++, i++) { + host->target_flag[i] = *ptr; + host->max_tags[i] = ORC_MAXTAGS; } - ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB); /* enable RP FIFO interrupt */ - return (0); + + if (nvramp->SCSI0Config & NCC_BUSRESET) + host->flags |= HCF_SCSI_RESET; + outb(0xFB, host->base + ORC_GIMSK); /* enable RP FIFO interrupt */ + return 0; } -/***************************************************************************** - Function name : orc_reset_scsi_bus - Description : Reset registers, reset a hanging bus and - kill active and disconnected commands for target w/o soft reset - Input : pHCB - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -static int orc_reset_scsi_bus(ORC_HCS * pHCB) +/** + * orc_reset_scsi_bus - perform bus reset + * @host: host being reset + * + * Perform a full bus reset on the adapter. + */ + +static int orc_reset_scsi_bus(struct orc_host * host) { /* I need Host Control Block Information */ - ULONG flags; + unsigned long flags; - spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); + spin_lock_irqsave(&host->allocation_lock, flags); - initAFlag(pHCB); + init_alloc_map(host); /* reset scsi bus */ - ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST); - if (waitSCSIRSTdone(pHCB) == 0) { - spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); + outb(SCSIRST, host->base + ORC_HCTRL); + /* FIXME: We can spend up to a second with the lock held and + interrupts off here */ + if (wait_scsi_reset_done(host) == 0) { + spin_unlock_irqrestore(&host->allocation_lock, flags); return FAILED; } else { - spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); + spin_unlock_irqrestore(&host->allocation_lock, flags); return SUCCESS; } } -/***************************************************************************** - Function name : orc_device_reset - Description : Reset registers, reset a hanging bus and - kill active and disconnected commands for target w/o soft reset - Input : pHCB - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -static int orc_device_reset(ORC_HCS * pHCB, struct scsi_cmnd *SCpnt, unsigned int target) +/** + * orc_device_reset - device reset handler + * @host: host to reset + * @cmd: command causing the reset + * @target; target device + * + * Reset registers, reset a hanging bus and kill active and disconnected + * commands for target w/o soft reset + */ + +static int orc_device_reset(struct orc_host * host, struct scsi_cmnd *cmd, unsigned int target) { /* I need Host Control Block Information */ - ORC_SCB *pScb; - ESCB *pVirEscb; - ORC_SCB *pVirScb; - UCHAR i; - ULONG flags; + struct orc_scb *scb; + struct orc_extended_scb *escb; + struct orc_scb *host_scb; + u8 i; + unsigned long flags; - spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); - pScb = (ORC_SCB *) NULL; - pVirEscb = (ESCB *) NULL; + spin_lock_irqsave(&(host->allocation_lock), flags); + scb = (struct orc_scb *) NULL; + escb = (struct orc_extended_scb *) NULL; /* setup scatter list address with one buffer */ - pVirScb = pHCB->HCS_virScbArray; + host_scb = host->scb_virt; + + /* FIXME: is this safe if we then fail to issue the reset or race + a completion ? */ + init_alloc_map(host); - initAFlag(pHCB); - /* device reset */ + /* Find the scb corresponding to the command */ for (i = 0; i < ORC_MAXQUEUE; i++) { - pVirEscb = pVirScb->SCB_EScb; - if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt)) + escb = host_scb->escb; + if (host_scb->status && escb->srb == cmd) break; - pVirScb++; + host_scb++; } if (i == ORC_MAXQUEUE) { - printk("Unable to Reset - No SCB Found\n"); - spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); + printk(KERN_ERR "Unable to Reset - No SCB Found\n"); + spin_unlock_irqrestore(&(host->allocation_lock), flags); return FAILED; } - if ((pScb = orc_alloc_scb(pHCB)) == NULL) { - spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); + + /* Allocate a new SCB for the reset command to the firmware */ + if ((scb = __orc_alloc_scb(host)) == NULL) { + /* Can't happen.. */ + spin_unlock_irqrestore(&(host->allocation_lock), flags); return FAILED; } - pScb->SCB_Opcode = ORC_BUSDEVRST; - pScb->SCB_Target = target; - pScb->SCB_HaStat = 0; - pScb->SCB_TaStat = 0; - pScb->SCB_Status = 0x0; - pScb->SCB_Link = 0xFF; - pScb->SCB_Reserved0 = 0; - pScb->SCB_Reserved1 = 0; - pScb->SCB_XferLen = 0; - pScb->SCB_SGLen = 0; - - pVirEscb->SCB_Srb = NULL; - pVirEscb->SCB_Srb = SCpnt; - orc_exec_scb(pHCB, pScb); /* Start execute SCB */ - spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); + + /* Reset device is handled by the firmare, we fill in an SCB and + fire it at the controller, it does the rest */ + scb->opcode = ORC_BUSDEVRST; + scb->target = target; + scb->hastat = 0; + scb->tastat = 0; + scb->status = 0x0; + scb->link = 0xFF; + scb->reserved0 = 0; + scb->reserved1 = 0; + scb->xferlen = 0; + scb->sg_len = 0; + + escb->srb = NULL; + escb->srb = cmd; + orc_exec_scb(host, scb); /* Start execute SCB */ + spin_unlock_irqrestore(&host->allocation_lock, flags); return SUCCESS; } +/** + * __orc_alloc_scb - allocate an SCB + * @host: host to allocate from + * + * Allocate an SCB and return a pointer to the SCB object. NULL + * is returned if no SCB is free. The caller must already hold + * the allocator lock at this point. + */ -/***************************************************************************/ -static ORC_SCB *__orc_alloc_scb(ORC_HCS * hcsp) + +static struct orc_scb *__orc_alloc_scb(struct orc_host * host) { - ORC_SCB *pTmpScb; - UCHAR Ch; - ULONG idx; - UCHAR index; - UCHAR i; + u8 channel; + unsigned long idx; + u8 index; + u8 i; - Ch = hcsp->HCS_Index; + channel = host->index; for (i = 0; i < 8; i++) { for (index = 0; index < 32; index++) { - if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) { - hcsp->BitAllocFlag[Ch][i] &= ~(1 << index); + if ((host->allocation_map[channel][i] >> index) & 0x01) { + host->allocation_map[channel][i] &= ~(1 << index); break; } } idx = index + 32 * i; - pTmpScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB))); - return (pTmpScb); + /* Translate the index to a structure instance */ + return (struct orc_scb *) ((unsigned long) host->scb_virt + (idx * sizeof(struct orc_scb))); } - return (NULL); + return NULL; } -static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp) +/** + * orc_alloc_scb - allocate an SCB + * @host: host to allocate from + * + * Allocate an SCB and return a pointer to the SCB object. NULL + * is returned if no SCB is free. + */ + +static struct orc_scb *orc_alloc_scb(struct orc_host * host) { - ORC_SCB *pTmpScb; - ULONG flags; + struct orc_scb *scb; + unsigned long flags; - spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); - pTmpScb = __orc_alloc_scb(hcsp); - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); - return (pTmpScb); + spin_lock_irqsave(&host->allocation_lock, flags); + scb = __orc_alloc_scb(host); + spin_unlock_irqrestore(&host->allocation_lock, flags); + return scb; } +/** + * orc_release_scb - release an SCB + * @host: host owning the SCB + * @scb: SCB that is now free + * + * Called to return a completed SCB to the allocation pool. Before + * calling the SCB must be out of use on both the host and the HA. + */ -/***************************************************************************/ -static void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp) +static void orc_release_scb(struct orc_host *host, struct orc_scb *scb) { - ULONG flags; - UCHAR Index; - UCHAR i; - UCHAR Ch; - - spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); - Ch = hcsp->HCS_Index; - Index = scbp->SCB_ScbIdx; - i = Index / 32; - Index %= 32; - hcsp->BitAllocFlag[Ch][i] |= (1 << Index); - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); + unsigned long flags; + u8 index, i, channel; + + spin_lock_irqsave(&(host->allocation_lock), flags); + channel = host->index; /* Channel */ + index = scb->scbidx; + i = index / 32; + index %= 32; + host->allocation_map[channel][i] |= (1 << index); + spin_unlock_irqrestore(&(host->allocation_lock), flags); } -/***************************************************************************** - Function name : abort_SCB - Description : Abort a queued command. - (commands that are on the bus can't be aborted easily) - Input : pHCB - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -static int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb) +/** + * orchid_abort_scb - abort a command + * + * Abort a queued command that has been passed to the firmware layer + * if possible. This is all handled by the firmware. We aks the firmware + * and it either aborts the command or fails + */ + +static int orchid_abort_scb(struct orc_host * host, struct orc_scb * scb) { - unsigned char bData, bStatus; + unsigned char data, status; - ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB); /* Write command */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); - if (waitHDOoff(hcsp) == 0) /* Wait HDO off */ + outb(ORC_CMD_ABORT_SCB, host->base + ORC_HDATA); /* Write command */ + outb(HDO, host->base + ORC_HCTRL); + if (wait_HDO_off(host) == 0) /* Wait HDO off */ return 0; - ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx); /* Write address */ - ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); - if (waitHDOoff(hcsp) == 0) /* Wait HDO off */ + outb(scb->scbidx, host->base + ORC_HDATA); /* Write address */ + outb(HDO, host->base + ORC_HCTRL); + if (wait_HDO_off(host) == 0) /* Wait HDO off */ return 0; - if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */ + if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */ return 0; - bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA); - ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ + status = inb(host->base + ORC_HDATA); + outb(data, host->base + ORC_HSTUS); /* Clear HDI */ - if (bStatus == 1) /* 0 - Successfully */ + if (status == 1) /* 0 - Successfully */ return 0; /* 1 - Fail */ return 1; } -/***************************************************************************** - Function name : inia100_abort - Description : Abort a queued command. - (commands that are on the bus can't be aborted easily) - Input : pHCB - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -static int orc_abort_srb(ORC_HCS * hcsp, struct scsi_cmnd *SCpnt) +static int inia100_abort_cmd(struct orc_host * host, struct scsi_cmnd *cmd) { - ESCB *pVirEscb; - ORC_SCB *pVirScb; - UCHAR i; - ULONG flags; + struct orc_extended_scb *escb; + struct orc_scb *scb; + u8 i; + unsigned long flags; - spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); + spin_lock_irqsave(&(host->allocation_lock), flags); - pVirScb = hcsp->HCS_virScbArray; + scb = host->scb_virt; - for (i = 0; i < ORC_MAXQUEUE; i++, pVirScb++) { - pVirEscb = pVirScb->SCB_EScb; - if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt)) { - if (pVirScb->SCB_TagMsg == 0) { - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); - return FAILED; + /* Walk the queue until we find the SCB that belongs to the command + block. This isn't a performance critical path so a walk in the park + here does no harm */ + + for (i = 0; i < ORC_MAXQUEUE; i++, scb++) { + escb = scb->escb; + if (scb->status && escb->srb == cmd) { + if (scb->tag_msg == 0) { + goto out; } else { - if (abort_SCB(hcsp, pVirScb)) { - pVirEscb->SCB_Srb = NULL; - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); + /* Issue an ABORT to the firmware */ + if (orchid_abort_scb(host, scb)) { + escb->srb = NULL; + spin_unlock_irqrestore(&host->allocation_lock, flags); return SUCCESS; - } else { - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); - return FAILED; - } + } else + goto out; } } } - spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); +out: + spin_unlock_irqrestore(&host->allocation_lock, flags); return FAILED; } -/*********************************************************************** - Routine Description: - This is the interrupt service routine for the Orchid SCSI adapter. - It reads the interrupt register to determine if the adapter is indeed - the source of the interrupt and clears the interrupt at the device. - Arguments: - HwDeviceExtension - HBA miniport driver's adapter data storage - Return Value: -***********************************************************************/ -static void orc_interrupt( - ORC_HCS * hcsp -) +/** + * orc_interrupt - IRQ processing + * @host: Host causing the interrupt + * + * This function is called from the IRQ handler and protected + * by the host lock. While the controller reports that there are + * scb's for processing we pull them off the controller, turn the + * index into a host address pointer to the scb and call the scb + * handler. + * + * Returns IRQ_HANDLED if any SCBs were processed, IRQ_NONE otherwise + */ + +static irqreturn_t orc_interrupt(struct orc_host * host) { - BYTE bScbIdx; - ORC_SCB *pScb; + u8 scb_index; + struct orc_scb *scb; - if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) { - return; // 0; + /* Check if we have an SCB queued for servicing */ + if (inb(host->base + ORC_RQUEUECNT) == 0) + return IRQ_NONE; - } do { - bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE); - - pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx)); - pScb->SCB_Status = 0x0; - - inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb); - } while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT)); - return; //1; - + /* Get the SCB index of the SCB to service */ + scb_index = inb(host->base + ORC_RQUEUE); + + /* Translate it back to a host pointer */ + scb = (struct orc_scb *) ((unsigned long) host->scb_virt + (unsigned long) (sizeof(struct orc_scb) * scb_index)); + scb->status = 0x0; + /* Process the SCB */ + inia100_scb_handler(host, scb); + } while (inb(host->base + ORC_RQUEUECNT)); + return IRQ_HANDLED; } /* End of I1060Interrupt() */ -/***************************************************************************** - Function name : inia100BuildSCB - Description : - Input : pHCB - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, struct scsi_cmnd * SCpnt) +/** + * inia100_build_scb - build SCB + * @host: host owing the control block + * @scb: control block to use + * @cmd: Mid layer command + * + * Build a host adapter control block from the SCSI mid layer command + */ + +static void inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struct scsi_cmnd * cmd) { /* Create corresponding SCB */ - struct scatterlist *pSrbSG; - ORC_SG *pSG; /* Pointer to SG list */ + struct scatterlist *sg; + struct orc_sgent *sgent; /* Pointer to SG list */ int i, count_sg; - ESCB *pEScb; - - pEScb = pSCB->SCB_EScb; - pEScb->SCB_Srb = SCpnt; - pSG = NULL; - - pSCB->SCB_Opcode = ORC_EXECSCSI; - pSCB->SCB_Flags = SCF_NO_DCHK; /* Clear done bit */ - pSCB->SCB_Target = SCpnt->device->id; - pSCB->SCB_Lun = SCpnt->device->lun; - pSCB->SCB_Reserved0 = 0; - pSCB->SCB_Reserved1 = 0; - pSCB->SCB_SGLen = 0; - - if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) { - pSG = (ORC_SG *) & pEScb->ESCB_SGList[0]; - if (SCpnt->use_sg) { - pSrbSG = (struct scatterlist *) SCpnt->request_buffer; - count_sg = pci_map_sg(pHCB->pdev, pSrbSG, SCpnt->use_sg, - SCpnt->sc_data_direction); - pSCB->SCB_SGLen = (U32) (count_sg * 8); - for (i = 0; i < count_sg; i++, pSG++, pSrbSG++) { - pSG->SG_Ptr = (U32) sg_dma_address(pSrbSG); - pSG->SG_Len = (U32) sg_dma_len(pSrbSG); - } - } else if (SCpnt->request_bufflen != 0) {/* Non SG */ - pSCB->SCB_SGLen = 0x8; - SCpnt->SCp.dma_handle = pci_map_single(pHCB->pdev, - SCpnt->request_buffer, - SCpnt->request_bufflen, - SCpnt->sc_data_direction); - pSG->SG_Ptr = (U32) SCpnt->SCp.dma_handle; - pSG->SG_Len = (U32) SCpnt->request_bufflen; - } else { - pSCB->SCB_SGLen = 0; - pSG->SG_Ptr = 0; - pSG->SG_Len = 0; + struct orc_extended_scb *escb; + + /* Links between the escb, scb and Linux scsi midlayer cmd */ + escb = scb->escb; + escb->srb = cmd; + sgent = NULL; + + /* Set up the SCB to do a SCSI command block */ + scb->opcode = ORC_EXECSCSI; + scb->flags = SCF_NO_DCHK; /* Clear done bit */ + scb->target = cmd->device->id; + scb->lun = cmd->device->lun; + scb->reserved0 = 0; + scb->reserved1 = 0; + scb->sg_len = 0; + + scb->xferlen = (u32) scsi_bufflen(cmd); + sgent = (struct orc_sgent *) & escb->sglist[0]; + + count_sg = scsi_dma_map(cmd); + BUG_ON(count_sg < 0); + + /* Build the scatter gather lists */ + if (count_sg) { + scb->sg_len = (u32) (count_sg * 8); + scsi_for_each_sg(cmd, sg, count_sg, i) { + sgent->base = (u32) sg_dma_address(sg); + sgent->length = (u32) sg_dma_len(sg); + sgent++; } + } else { + scb->sg_len = 0; + sgent->base = 0; + sgent->length = 0; } - pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr; - pSCB->SCB_HaStat = 0; - pSCB->SCB_TaStat = 0; - pSCB->SCB_Link = 0xFF; - pSCB->SCB_SenseLen = SENSE_SIZE; - pSCB->SCB_CDBLen = SCpnt->cmd_len; - if (pSCB->SCB_CDBLen >= IMAX_CDB) { - printk("max cdb length= %x\b", SCpnt->cmd_len); - pSCB->SCB_CDBLen = IMAX_CDB; + scb->sg_addr = (u32) scb->sense_addr; + scb->hastat = 0; + scb->tastat = 0; + scb->link = 0xFF; + scb->sense_len = SENSE_SIZE; + scb->cdb_len = cmd->cmd_len; + if (scb->cdb_len >= IMAX_CDB) { + printk("max cdb length= %x\b", cmd->cmd_len); + scb->cdb_len = IMAX_CDB; } - pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW; - if (SCpnt->device->tagged_supported) { /* Tag Support */ - pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */ + scb->ident = cmd->device->lun | DISC_ALLOW; + if (cmd->device->tagged_supported) { /* Tag Support */ + scb->tag_msg = SIMPLE_QUEUE_TAG; /* Do simple tag only */ } else { - pSCB->SCB_TagMsg = 0; /* No tag support */ + scb->tag_msg = 0; /* No tag support */ } - memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen); - return; + memcpy(&scb->cdb[0], &cmd->cmnd, scb->cdb_len); } -/***************************************************************************** - Function name : inia100_queue - Description : Queue a command and setup interrupts for a free bus. - Input : pHCB - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -static int inia100_queue(struct scsi_cmnd * SCpnt, void (*done) (struct scsi_cmnd *)) +/** + * inia100_queue - queue command with host + * @cmd: Command block + * @done: Completion function + * + * Called by the mid layer to queue a command. Process the command + * block, build the host specific scb structures and if there is room + * queue the command down to the controller + */ + +static int inia100_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) { - register ORC_SCB *pSCB; - ORC_HCS *pHCB; /* Point to Host adapter control block */ + struct orc_scb *scb; + struct orc_host *host; /* Point to Host adapter control block */ - pHCB = (ORC_HCS *) SCpnt->device->host->hostdata; - SCpnt->scsi_done = done; + host = (struct orc_host *) cmd->device->host->hostdata; + cmd->scsi_done = done; /* Get free SCSI control block */ - if ((pSCB = orc_alloc_scb(pHCB)) == NULL) + if ((scb = orc_alloc_scb(host)) == NULL) return SCSI_MLQUEUE_HOST_BUSY; - inia100BuildSCB(pHCB, pSCB, SCpnt); - orc_exec_scb(pHCB, pSCB); /* Start execute SCB */ - - return (0); + inia100_build_scb(host, scb, cmd); + orc_exec_scb(host, scb); /* Start execute SCB */ + return 0; } /***************************************************************************** Function name : inia100_abort Description : Abort a queued command. (commands that are on the bus can't be aborted easily) - Input : pHCB - Pointer to host adapter structure + Input : host - Pointer to host adapter structure Output : None. Return : pSRB - Pointer to SCSI request block. *****************************************************************************/ -static int inia100_abort(struct scsi_cmnd * SCpnt) +static int inia100_abort(struct scsi_cmnd * cmd) { - ORC_HCS *hcsp; + struct orc_host *host; - hcsp = (ORC_HCS *) SCpnt->device->host->hostdata; - return orc_abort_srb(hcsp, SCpnt); + host = (struct orc_host *) cmd->device->host->hostdata; + return inia100_abort_cmd(host, cmd); } /***************************************************************************** Function name : inia100_reset Description : Reset registers, reset a hanging bus and kill active and disconnected commands for target w/o soft reset - Input : pHCB - Pointer to host adapter structure + Input : host - Pointer to host adapter structure Output : None. Return : pSRB - Pointer to SCSI request block. *****************************************************************************/ -static int inia100_bus_reset(struct scsi_cmnd * SCpnt) +static int inia100_bus_reset(struct scsi_cmnd * cmd) { /* I need Host Control Block Information */ - ORC_HCS *pHCB; - pHCB = (ORC_HCS *) SCpnt->device->host->hostdata; - return orc_reset_scsi_bus(pHCB); + struct orc_host *host; + host = (struct orc_host *) cmd->device->host->hostdata; + return orc_reset_scsi_bus(host); } /***************************************************************************** Function name : inia100_device_reset Description : Reset the device - Input : pHCB - Pointer to host adapter structure + Input : host - Pointer to host adapter structure Output : None. Return : pSRB - Pointer to SCSI request block. *****************************************************************************/ -static int inia100_device_reset(struct scsi_cmnd * SCpnt) +static int inia100_device_reset(struct scsi_cmnd * cmd) { /* I need Host Control Block Information */ - ORC_HCS *pHCB; - pHCB = (ORC_HCS *) SCpnt->device->host->hostdata; - return orc_device_reset(pHCB, SCpnt, scmd_id(SCpnt)); + struct orc_host *host; + host = (struct orc_host *) cmd->device->host->hostdata; + return orc_device_reset(host, cmd, scmd_id(cmd)); } -/***************************************************************************** - Function name : inia100SCBPost - Description : This is callback routine be called when orc finish one - SCSI command. - Input : pHCB - Pointer to host adapter control block. - pSCB - Pointer to SCSI control block. - Output : None. - Return : None. -*****************************************************************************/ -static void inia100SCBPost(BYTE * pHcb, BYTE * pScb) +/** + * inia100_scb_handler - interrupt callback + * @host: Host causing the interrupt + * @scb: SCB the controller returned as needing processing + * + * Perform completion processing on a control block. Do the conversions + * from host to SCSI midlayer error coding, save any sense data and + * the complete with the midlayer and recycle the scb. + */ + +static void inia100_scb_handler(struct orc_host *host, struct orc_scb *scb) { - struct scsi_cmnd *pSRB; /* Pointer to SCSI request block */ - ORC_HCS *pHCB; - ORC_SCB *pSCB; - ESCB *pEScb; - - pHCB = (ORC_HCS *) pHcb; - pSCB = (ORC_SCB *) pScb; - pEScb = pSCB->SCB_EScb; - if ((pSRB = (struct scsi_cmnd *) pEScb->SCB_Srb) == 0) { - printk("inia100SCBPost: SRB pointer is empty\n"); - orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */ + struct scsi_cmnd *cmd; /* Pointer to SCSI request block */ + struct orc_extended_scb *escb; + + escb = scb->escb; + if ((cmd = (struct scsi_cmnd *) escb->srb) == NULL) { + printk(KERN_ERR "inia100_scb_handler: SRB pointer is empty\n"); + orc_release_scb(host, scb); /* Release SCB for current channel */ return; } - pEScb->SCB_Srb = NULL; + escb->srb = NULL; - switch (pSCB->SCB_HaStat) { + switch (scb->hastat) { case 0x0: case 0xa: /* Linked command complete without error and linked normally */ case 0xb: /* Linked command complete without error interrupt generated */ - pSCB->SCB_HaStat = 0; + scb->hastat = 0; break; case 0x11: /* Selection time out-The initiator selection or target reselection was not complete within the SCSI Time out period */ - pSCB->SCB_HaStat = DID_TIME_OUT; + scb->hastat = DID_TIME_OUT; break; case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus phase sequence was requested by the target. The host adapter will generate a SCSI Reset Condition, notifying the host with a SCRD interrupt */ - pSCB->SCB_HaStat = DID_RESET; + scb->hastat = DID_RESET; break; case 0x1a: /* SCB Aborted. 07/21/98 */ - pSCB->SCB_HaStat = DID_ABORT; + scb->hastat = DID_ABORT; break; case 0x12: /* Data overrun/underrun-The target attempted to transfer more data @@ -984,46 +1022,41 @@ static void inia100SCBPost(BYTE * pHcb, BYTE * pScb) case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. */ default: - printk("inia100: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat); - pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */ + printk(KERN_DEBUG "inia100: %x %x\n", scb->hastat, scb->tastat); + scb->hastat = DID_ERROR; /* Couldn't find any better */ break; } - if (pSCB->SCB_TaStat == 2) { /* Check condition */ - memcpy((unsigned char *) &pSRB->sense_buffer[0], - (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE); + if (scb->tastat == 2) { /* Check condition */ + memcpy((unsigned char *) &cmd->sense_buffer[0], + (unsigned char *) &escb->sglist[0], SENSE_SIZE); } - pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16); - - if (pSRB->use_sg) { - pci_unmap_sg(pHCB->pdev, - (struct scatterlist *)pSRB->request_buffer, - pSRB->use_sg, pSRB->sc_data_direction); - } else if (pSRB->request_bufflen != 0) { - pci_unmap_single(pHCB->pdev, pSRB->SCp.dma_handle, - pSRB->request_bufflen, - pSRB->sc_data_direction); - } - - pSRB->scsi_done(pSRB); /* Notify system DONE */ - - orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */ + cmd->result = scb->tastat | (scb->hastat << 16); + scsi_dma_unmap(cmd); + cmd->scsi_done(cmd); /* Notify system DONE */ + orc_release_scb(host, scb); /* Release SCB for current channel */ } -/* - * Interrupt handler (main routine of the driver) +/** + * inia100_intr - interrupt handler + * @irqno: Interrupt value + * @devid: Host adapter + * + * Entry point for IRQ handling. All the real work is performed + * by orc_interrupt. */ static irqreturn_t inia100_intr(int irqno, void *devid) { - struct Scsi_Host *host = (struct Scsi_Host *)devid; - ORC_HCS *pHcb = (ORC_HCS *)host->hostdata; + struct Scsi_Host *shost = (struct Scsi_Host *)devid; + struct orc_host *host = (struct orc_host *)shost->hostdata; unsigned long flags; + irqreturn_t res; - spin_lock_irqsave(host->host_lock, flags); - orc_interrupt(pHcb); - spin_unlock_irqrestore(host->host_lock, flags); + spin_lock_irqsave(shost->host_lock, flags); + res = orc_interrupt(host); + spin_unlock_irqrestore(shost->host_lock, flags); - return IRQ_HANDLED; + return res; } static struct scsi_host_template inia100_template = { @@ -1044,12 +1077,12 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { struct Scsi_Host *shost; - ORC_HCS *pHCB; + struct orc_host *host; unsigned long port, bios; int error = -ENODEV; u32 sz; - unsigned long dBiosAdr; - char *pbBiosAdr; + unsigned long biosaddr; + char *bios_phys; if (pci_enable_device(pdev)) goto out; @@ -1068,55 +1101,55 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev, } /* <02> read from base address + 0x50 offset to get the bios value. */ - bios = ORC_RDWORD(port, 0x50); + bios = inw(port + 0x50); - shost = scsi_host_alloc(&inia100_template, sizeof(ORC_HCS)); + shost = scsi_host_alloc(&inia100_template, sizeof(struct orc_host)); if (!shost) goto out_release_region; - pHCB = (ORC_HCS *)shost->hostdata; - pHCB->pdev = pdev; - pHCB->HCS_Base = port; - pHCB->HCS_BIOS = bios; - spin_lock_init(&pHCB->BitAllocFlagLock); + host = (struct orc_host *)shost->hostdata; + host->pdev = pdev; + host->base = port; + host->BIOScfg = bios; + spin_lock_init(&host->allocation_lock); /* Get total memory needed for SCB */ - sz = ORC_MAXQUEUE * sizeof(ORC_SCB); - pHCB->HCS_virScbArray = pci_alloc_consistent(pdev, sz, - &pHCB->HCS_physScbArray); - if (!pHCB->HCS_virScbArray) { + sz = ORC_MAXQUEUE * sizeof(struct orc_scb); + host->scb_virt = pci_alloc_consistent(pdev, sz, + &host->scb_phys); + if (!host->scb_virt) { printk("inia100: SCB memory allocation error\n"); goto out_host_put; } - memset(pHCB->HCS_virScbArray, 0, sz); + memset(host->scb_virt, 0, sz); /* Get total memory needed for ESCB */ - sz = ORC_MAXQUEUE * sizeof(ESCB); - pHCB->HCS_virEscbArray = pci_alloc_consistent(pdev, sz, - &pHCB->HCS_physEscbArray); - if (!pHCB->HCS_virEscbArray) { + sz = ORC_MAXQUEUE * sizeof(struct orc_extended_scb); + host->escb_virt = pci_alloc_consistent(pdev, sz, + &host->escb_phys); + if (!host->escb_virt) { printk("inia100: ESCB memory allocation error\n"); goto out_free_scb_array; } - memset(pHCB->HCS_virEscbArray, 0, sz); + memset(host->escb_virt, 0, sz); - dBiosAdr = pHCB->HCS_BIOS; - dBiosAdr = (dBiosAdr << 4); - pbBiosAdr = phys_to_virt(dBiosAdr); - if (init_orchid(pHCB)) { /* Initialize orchid chip */ + biosaddr = host->BIOScfg; + biosaddr = (biosaddr << 4); + bios_phys = phys_to_virt(biosaddr); + if (init_orchid(host)) { /* Initialize orchid chip */ printk("inia100: initial orchid fail!!\n"); goto out_free_escb_array; } - shost->io_port = pHCB->HCS_Base; + shost->io_port = host->base; shost->n_io_port = 0xff; shost->can_queue = ORC_MAXQUEUE; shost->unique_id = shost->io_port; - shost->max_id = pHCB->HCS_MaxTar; + shost->max_id = host->max_targets; shost->max_lun = 16; - shost->irq = pHCB->HCS_Intr = pdev->irq; - shost->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */ + shost->irq = pdev->irq; + shost->this_id = host->scsi_id; /* Assign HCS index */ shost->sg_tablesize = TOTAL_SG_ENTRY; /* Initial orc chip */ @@ -1137,36 +1170,36 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev, scsi_scan_host(shost); return 0; - out_free_irq: +out_free_irq: free_irq(shost->irq, shost); - out_free_escb_array: - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB), - pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray); - out_free_scb_array: - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB), - pHCB->HCS_virScbArray, pHCB->HCS_physScbArray); - out_host_put: +out_free_escb_array: + pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb), + host->escb_virt, host->escb_phys); +out_free_scb_array: + pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb), + host->scb_virt, host->scb_phys); +out_host_put: scsi_host_put(shost); - out_release_region: +out_release_region: release_region(port, 256); - out_disable_device: +out_disable_device: pci_disable_device(pdev); - out: +out: return error; } static void __devexit inia100_remove_one(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); - ORC_HCS *pHCB = (ORC_HCS *)shost->hostdata; + struct orc_host *host = (struct orc_host *)shost->hostdata; scsi_remove_host(shost); free_irq(shost->irq, shost); - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB), - pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray); - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB), - pHCB->HCS_virScbArray, pHCB->HCS_physScbArray); + pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb), + host->escb_virt, host->escb_phys); + pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb), + host->scb_virt, host->scb_phys); release_region(shost->io_port, 256); scsi_host_put(shost);