diff options
-rw-r--r-- | drivers/scsi/a100u2w.c | 1215 | ||||
-rw-r--r-- | drivers/scsi/a100u2w.h | 297 |
2 files changed, 758 insertions, 754 deletions
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index 7cedc722fad..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 <hch@lst.de> * - merge the two source files * - remove internal queueing code + * 14/06/07 Alan Cox <alan@redhat.com> + * - Grand cleanup and Linuxisation */ #include <linux/module.h> @@ -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,815 +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 -------*/ + /* Load an EEProm copy into RAM */ + /* Assumes single threaded at this point */ + read_eeprom(host); - read_eeprom(hcsp); - - if (nvramp->Revision != 1) - return (-1); - - 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; - initAFlag(pHCB); - /* device reset */ + /* FIXME: is this safe if we then fail to issue the reset or race + a completion ? */ + init_alloc_map(host); + + /* 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(&(host->allocation_lock), flags); - spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); + scb = host->scb_virt; - pVirScb = hcsp->HCS_virScbArray; + /* Walk the queue until we find the SCB that belongs to the command |