diff -urN -urN src/sys/dev/ihaempty/README.iha src/sys/dev/iha/README.iha --- src/sys/dev/ihaempty/README.iha Thu Jan 1 02:00:00 1970 +++ src/sys/dev/iha/README.iha Fri Dec 10 10:02:56 1999 @@ -0,0 +1,57 @@ +README for the FreeBSD iha driver + +first the typical thing: all this here is work in progress - so please +be careful in using this and report any problems you discover back to me + +this driver is for the support of the initio scsi controller family in +FreeBSD ... the supported controllers are: the 9100 series of ultra and +ultra wide controllers and the a100 series of u2w controllers ... for +example the ones sold by nmc + +this driver is based (currently even more than based :-) on the FreeBSD +driver written by initio themself ... i have so far cleaned up the copyright +issue (now all the files have the proper BSD style copyright) and reordered +all a bit ... the next step will be a code review and cleanup and hopefully +then the commit into the FreeBSD source tree + +the driver sources install all into /sys/dev/iha and you then have to patch +your /sys/conf/files via + + patch -p0 < /sys/dev/iha/iha-sys_conf_files.diff + +(this patch is - like everything else here based on FreeBSD 3.3-RELEASE but +i'll move to -current soon - but will still try to maintain a -stable set +as well) + +now you have to add the following lines into your kernel config file: + + device iha0 + controller scbus0 + device da0 + device cd0 + device ch0 + device sa0 + device pass0 + +rebuild your kernel and reboot - this should give you the following bootup +output (or similar): + + ... + iha0: rev 0x01 int a irq 9 on pci0.19.0 + iha0: Resetting SCSI Bus ... + ... + da0 at iha0 bus 0 target 4 lun 0 + da0: Fixed Direct Access SCSI-2 device + da0: 20.000MB/s transfers (20.000MHz, offset 15), Tagged Queueing Enabled + da0: 4357MB (8925000 512 byte sectors: 255H 63S/T 555C) + ... + +if you have any questions about this just send me a mail to + + graichen@innominate.de + +or have a look at the web page + + http://www.innominate.org/~tgr/projects/FreeBSD/iha + +t diff -urN -urN src/sys/dev/ihaempty/a100.c src/sys/dev/iha/a100.c --- src/sys/dev/ihaempty/a100.c Thu Jan 1 02:00:00 1970 +++ src/sys/dev/iha/a100.c Fri Jun 22 16:28:52 2001 @@ -0,0 +1,1898 @@ +/*- + * Copyright (c) 1998 Initio Corporation + * All rights reserved. + * + * 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. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY INITIO CORPORATION ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL INITIO CORPORATION BE LIABLE FOR ANY DIRECT,INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: a100scsi.c v 1.00 1998/10/08 se Exp $ + */ + +#include + +#include +#include +#include +/* #include */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +/* #include */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +#include + + + + +#define INT32 int32 +#define U_INT32 u_int32 + +#ifdef __alpha__ +/* XXX */ +#undef vtophys +#define vtophys(va) (pmap_kextract(((vm_offset_t) (va))) \ + + 1*1024*1024*1024) +#endif + +/*========================================================== +** +** Access to the controller chip. +** +**========================================================== +*/ +#define OutB(val, port) outb(port, val) +#define OutW(val, port) outw(port, val) +#define OutL(val, port) outl(port, val) + +#define PCI_DEVICE_ID_INIC1060 0x10601101ul +#define PCI_DEVICE_ID_INIC850 0x08501101ul +#define PCI_BASEADDR0 0x10 + +#define ccb_a100_ptr spriv_ptr1 + +/* TTT static void a100_wakeup(A100_HCS *hcsp, u_long code); */ + +static const char* a100_probe( pcici_t tag, pcidi_t type); +static void a100_attach( pcici_t tag, int unit); + +static int orc_waitChipReady(A100_HCS *hcsp); +static int orc_waitFWReady(A100_HCS *hcsp); +#if 0 +static int orc_waitSCSIRSTdone(A100_HCS *hcsp); +static int orc_waitStopOn(A100_HCS *hcsp); +#endif +static int orc_waitHDOoff(A100_HCS *hcsp); +static int orc_waitHDIset(A100_HCS *hcsp,UCHAR *pData); + +static int orc_get_FW_version(A100_HCS *hcsp, unsigned short *version); +unsigned long orc_get_echo(A100_HCS *hcsp, unsigned long lValue); +static int orc_set_NVRAM(A100_HCS *hcsp, unsigned char address, unsigned char value); +unsigned char orc_get_NVRAM(A100_HCS *hcsp, unsigned char address,unsigned char *pDataIn); +unsigned char orc_get_Bus_Status(A100_HCS *hcsp); +unsigned char orc_abort_SCB(A100_HCS *hcsp, A100_SCB *pScb); +#if 0 +static int orc_push_SCB(A100_HCS *hcsp, A100_SCB *pScb); +#endif +static void orc_send_scb(A100_HCS *hcsp, A100_SCB *scbp); + + +static int orc_rd_all(A100_HCS *hcsp); +void orc_update_all(A100_HCS *hcsp); +void orc_read_eeprom(A100_HCS *hcsp); +static int orc_load_FW(A100_HCS *hcsp); +static void orc_isr (A100_HCS *pHcs); + + +static void orc_setup_SCBs(A100_HCS *hcsp); + +static int orc_init(A100_HCS *hcsp, A100_SCB *pScb,A100_SG *pSG); + +static void orc_append_pend_scb(A100_HCS *pHcs, A100_SCB *scbp); + +static A100_SCB *orc_abort_srb(A100_HCS *pHcs, ULONG srbp); + +static A100_SCB * orc_alloc_scb(A100_HCS *pHcs); +static void orc_release_scb(A100_HCS *pHcs, A100_SCB *pScb); + +static void a100_free_scb(A100_HCS *pHcs, A100_SCB *pScb); + +#if 0 +static int a100_wait_scb(A100_HCS *pHcs,A100_SCB *pScb,int time); +#endif + + +static void a100_send_scb(A100_HCS *pHcs); +static void a100_exec_scb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error); +static void a100_timeout( void *arg1); +static void a100_done(A100_HCS *pHcs, A100_SCB *pScb); + + + + +static void a100_action(struct cam_sim *sim, union ccb *ccb); +static void a100_poll(struct cam_sim *sim); +#if 0 +static void a100_min_phys( struct buf *pbuf); +#endif + + + + +/* + * The overrun buffer shared amongst all PCI adapters. + */ + +bus_dma_tag_t overrun_dmat; +bus_dmamap_t overrun_dmamap; +bus_addr_t overrun_physbase; + +static u_long a100_count; + + +struct pci_device a100_device = { + "ihb", + a100_probe, + a100_attach, + &a100_count, + NULL +}; + +#ifdef COMPAT_PCI_DRIVER +COMPAT_PCI_DRIVER(ihb, a100_device); +#else +DATA_SET (pcidevice_set, a100_device); +#endif /* COMPAT_PCI_DRIVER */ + + + + + + +static NVRAM nvram,*nvramp = &nvram; +static UCHAR dftNvRam[64] = { + 0x01, + 0x11, + 0x60, + 0x10, + 0x00, + 0x01, + 0x11, + 0x60, + 0x10, + 0x00, + 0x00, + 0x01, + + 0x01, + 0x01, + 0x00, + 0x00, + + 0x07, + 0x83, + 0x20, + 0x0A, + 0x00, + 0x00, + + 0xC8,0xC8,0xC8,0xC8, + 0xC8,0xC8,0xC8,0xC8, + 0xC8,0xC8,0xC8,0xC8, + 0xC8,0xC8,0xC8,0xC8, + + 0x07, + 0x83, + 0x20, + 0x0A, + 0x00, + 0x00, + + 0xC8,0xC8,0xC8,0xC8, + 0xC8,0xC8,0xC8,0xC8, + 0xC8,0xC8,0xC8,0xC8, + 0xC8,0xC8,0xC8,0xC8, + + 0x00, + 0x00, + 0x00, + 0x00 +}; + + + + + +static int orc_waitChipReady(A100_HCS *hcsp) +{ + int i; + for(i = 0;i<2000;i++) + { + if(inb(hcsp->HCS_Base+ORC_HCTRL) & HOSTSTOP) + return (TRUE); + DELAY(1000); /* 1 ms */ + } + return(FALSE); +} + + +static int orc_waitFWReady(A100_HCS *hcsp) +{ + int i; + for(i = 0;i<2000;i++) + { + if(inb(hcsp->HCS_Base+ORC_HSTUS) & RREADY) + return (TRUE); + DELAY(1000); /* 1 ms */ + } + return(FALSE); +} + + +#if 0 +static int orc_waitSCSIRSTdone(A100_HCS *hcsp) +{ + int i; + for(i = 0;i<2000;i++) + { + if(!(inb(hcsp->HCS_Base+ORC_HCTRL) & SCSIRST)) + return (TRUE); + DELAY(1000); /* 1 ms */ + } + return(FALSE); +} + + +static int orc_waitStopOn(A100_HCS *hcsp) +{ + int i; + for(i = 0;i<2000;i++) + { + if(!(inb(hcsp->HCS_Base+ORC_HCTRL) & SCSIRST)) + return (TRUE); + DELAY(1000); /* 1 ms */ + } + return(FALSE); +} +#endif + + +static int orc_waitHDOoff(A100_HCS *hcsp) +{ + int i; + for(i = 0;i<2000;i++) + { + if(!(inb(hcsp->HCS_Base+ORC_HCTRL) & HDO)) + return (TRUE); + DELAY(1000); /* 1 ms */ + } + return(FALSE); +} + + + +static int orc_waitHDIset(A100_HCS *hcsp,UCHAR *pData) +{ + int i; + for(i = 0;i<2000;i++) + { + if((*pData = inb(hcsp->HCS_Base+ORC_HSTUS)) & HDI) + return (TRUE); + DELAY(1000); /* 1 ms */ + } + return(FALSE); +} + + + +static int orc_get_FW_version(A100_HCS *hcsp, unsigned short *version) +{ + UCHAR *pVersion, bData; + + pVersion = (unsigned char *) version; + outb(hcsp->HCS_Base+ORC_HDATA, ORC_CMD_VERSION); + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + if (orc_waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + *pVersion++ = inb(hcsp->HCS_Base+ORC_HDATA); + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + if (orc_waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + *pVersion = inb(hcsp->HCS_Base+ORC_HDATA); + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + return (TRUE); +} + + +/***************************************************************************/ +unsigned long orc_get_echo(A100_HCS *hcsp, unsigned long lValue) +{ + unsigned long lDataIn, *pData; + UCHAR bData; + + pData = &lValue; + outb(hcsp->HCS_Base+ORC_HDATA, ORC_CMD_ECHO); + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HDATA, *pData++); /* Write byte 0 */ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HDATA, *pData++); /* Write byte 1 */ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HDATA, *pData++); /* Write byte 2 */ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HDATA, *pData++); /* Write byte 3 */ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + pData = &lDataIn; + + if (orc_waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + *pData++ = inb(hcsp->HCS_Base+ORC_HDATA); + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + + if (orc_waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + *pData++ = inb(hcsp->HCS_Base+ORC_HDATA); + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + + if (orc_waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + *pData++ = inb(hcsp->HCS_Base+ORC_HDATA); + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + + if (orc_waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + *pData++ = inb(hcsp->HCS_Base+ORC_HDATA); + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + return (lDataIn); +} + +/***************************************************************************/ +static int orc_set_NVRAM(A100_HCS *hcsp, unsigned char address, unsigned char value) +{ + + outb(hcsp->HCS_Base+ORC_HDATA, ORC_CMD_SET_NVM);/* Write command*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HDATA, address); /* Write address*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HDATA, value); /* Write value */ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + return (TRUE); +} + +/***************************************************************************/ +unsigned char orc_get_NVRAM(A100_HCS *hcsp, unsigned char address,unsigned char *pDataIn) +{ + unsigned char bData; + + outb(hcsp->HCS_Base+ORC_HDATA, ORC_CMD_GET_NVM);/* Write command*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HDATA, address); /* Write address*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + + if (orc_waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + *pDataIn = inb(hcsp->HCS_Base+ORC_HDATA); + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + return (TRUE); +} + + +/***************************************************************************/ +unsigned char orc_get_Bus_Status(A100_HCS *hcsp) +{ + unsigned char bStatus, bData; + + outb(hcsp->HCS_Base+ORC_HDATA, ORC_CMD_GET_BUS_STATUS);/* Write command*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ + return (FALSE); + + + if (orc_waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ + return (FALSE); + bStatus = inb(hcsp->HCS_Base+ORC_HDATA); + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + return (bStatus); +} + + +/***************************************************************************/ +unsigned char orc_abort_SCB(A100_HCS *hcsp, A100_SCB *pScb) +{ + unsigned char bStatus, bData; + + outb(hcsp->HCS_Base+ORC_HDATA, ORC_CMD_ABORT_SCB);/* Write command*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off*/ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HDATA, pScb->SCB_ScbIdx); /* Write address*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == FALSE) /* Wait HDO off*/ + return (FALSE); + + + if (orc_waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set*/ + return (FALSE); + bStatus = inb(hcsp->HCS_Base+ORC_HDATA); + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + if(bStatus == 0) + return (TRUE); + else + return (FALSE); +} + +#if 0 +/***************************************************************************/ +static int orc_push_SCB(A100_HCS *hcsp, A100_SCB *pScb) +{ + UCHAR bData; + + outb(hcsp->HCS_Base+ORC_HDATA, ORC_CMD_ISSUE_SCB);/* Write command*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == 0) /* Wait HDO off*/ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HDATA, pScb->SCB_ScbIdx);/* Write address*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); + if (orc_waitHDOoff(hcsp) == 0) /* Wait HDO off*/ + return (FALSE); + + + if (orc_waitHDIset(hcsp, &bData) == 0) /* Wait HDI set*/ + return (FALSE); + + outb(hcsp->HCS_Base+ORC_HSTUS, bData); /* Clear HDI */ + + return (TRUE); +} +#endif + +/***************************************************************************/ +static void orc_send_scb(A100_HCS *hcsp, A100_SCB *scbp) +{ + scbp->SCB_Status = SCB_POST; + + outb(hcsp->HCS_Base+ORC_PQUEUE, scbp->SCB_ScbIdx); + +} + + + +/*********************************************************************** + Read SCSI H/A configuration parameters from serial EEPROM +************************************************************************/ +static int orc_rd_all(A100_HCS *hcsp) +{ + int i; + UCHAR *np, chksum = 0; + + np = (UCHAR *) nvramp; + for (i = 0; i < 64; i++,np++) { + if(orc_get_NVRAM(hcsp, (unsigned char ) i,np) == FALSE) + return -1; + } + /*------ Is ckecksum ok ? ------*/ + np = (UCHAR *) nvramp; + for (i = 0; i < 63; i++) + chksum += *np++; + if (nvramp->CheckSum != (UCHAR) chksum) + return -1; + + return 1; +} + +/************************************************************************ + Update SCSI H/A configuration parameters from serial EEPROM +*************************************************************************/ +void orc_update_all(A100_HCS *hcsp) /* setup default pattern*/ +{ + int i; + UCHAR *np, *np1, chksum = 0; /* Calculate checksum first*/ + np = (UCHAR *) dftNvRam; + for (i = 0; i < 63; i++) + chksum += *np++; + *np = chksum; + + np = (UCHAR *) dftNvRam; + np1 = (UCHAR *) nvramp; + for (i = 0; i < 64; i++, np++, np1++) { + if (*np != *np1) { + orc_set_NVRAM(hcsp, (unsigned char) i, *np); + } + } + return; +} + +/************************************************************************* + Function name : read_eeprom +**************************************************************************/ +void orc_read_eeprom(A100_HCS *hcsp) +{ + if (orc_rd_all(hcsp) != 1) { + orc_update_all( hcsp); /* setup default pattern*/ + orc_rd_all(hcsp); /* load again */ + } +} + + +/***************************************************************************/ +static int orc_load_FW(A100_HCS *hcsp) +{ + unsigned long dData; + unsigned short wBIOSAddress, i; + unsigned char *pData, bData; + + + bData = inb(hcsp->HCS_Base+ORC_GCFG); + outb(hcsp->HCS_Base+ORC_GCFG, bData | EEPRG); /* Enable EEPROM programming */ + outb(hcsp->HCS_Base+ORC_EBIOSADR2, 0x00); + outw(hcsp->HCS_Base+ORC_EBIOSADR0, 0x00); + if (inb(hcsp->HCS_Base+ORC_EBIOSDATA) != 0x55) { + outb(hcsp->HCS_Base+ORC_GCFG, bData); /* Disable EEPROM programming */ + return (FALSE); + } + outw(hcsp->HCS_Base+ORC_EBIOSADR0, 0x01); + if (inb(hcsp->HCS_Base+ORC_EBIOSDATA) != 0xAA) { + outb(hcsp->HCS_Base+ORC_GCFG, bData); /* Disable EEPROM programming */ + return (FALSE); + } + + outb(hcsp->HCS_Base+ORC_RISCCTL, PRGMRST | DOWNLOAD);/* Enable SRAM programming */ + pData = (UCHAR *) &dData; + dData = 0; /* Initial FW address to 0 */ + outw(hcsp->HCS_Base+ORC_EBIOSADR0, 0x10); + *pData = inb(hcsp->HCS_Base+ORC_EBIOSDATA); /* Read from BIOS */ + outw(hcsp->HCS_Base+ORC_EBIOSADR0, 0x11); + *(pData + 1) = inb(hcsp->HCS_Base+ORC_EBIOSDATA);/* Read from BIOS */ + outw(hcsp->HCS_Base+ORC_EBIOSADR0, 0x12); + *(pData + 2) = inb(hcsp->HCS_Base+ORC_EBIOSDATA);/* Read from BIOS */ + outb(hcsp->HCS_Base+ORC_EBIOSADR2, *(pData+2)); + outl(hcsp->HCS_Base+ORC_FWBASEADR, dData); /* Write FW address */ + + wBIOSAddress = (unsigned short) dData; + for (i = 0, pData = (unsigned char *) &dData; /* Download the code*/ + i < 0x1000; /* Firmware code size = 4K */ + i++, wBIOSAddress++) { + outw(hcsp->HCS_Base+ORC_EBIOSADR0, wBIOSAddress); + *pData++ = inb(hcsp->HCS_Base+ORC_EBIOSDATA);/*Read from BIOS */ + if ((i % 4) == 3) { + outl(hcsp->HCS_Base+ORC_RISCRAM, dData); /* Write every 4 bytes */ + pData = (unsigned char *) &dData; + } + } + + outb(hcsp->HCS_Base+ORC_RISCCTL, PRGMRST | DOWNLOAD);/* Reset program count 0 */ + wBIOSAddress -= 0x1000; /* Reset the BIOS adddress */ + for (i = 0, pData = (unsigned char *) &dData; /* Check the code */ + i < 0x1000; /* Firmware code size = 4K */ + i++, wBIOSAddress++) { + outw(hcsp->HCS_Base+ORC_EBIOSADR0, wBIOSAddress); + *pData++ = inb(hcsp->HCS_Base+ORC_EBIOSDATA);/* Read from BIOS */ + if ((i % 4) == 3) { + if (inl(hcsp->HCS_Base+ORC_RISCRAM) != dData) { + outb(hcsp->HCS_Base+ORC_RISCCTL, PRGMRST);/* Reset program to 0 */ + outb(hcsp->HCS_Base+ORC_GCFG, bData); /*Disable EEPROM programming*/ + return (FALSE); + } + pData = (unsigned char *) &dData; + } + } + outb(hcsp->HCS_Base+ORC_RISCCTL, PRGMRST); /* Reset program to 0*/ + outb(hcsp->HCS_Base+ORC_GCFG, bData); /* Disable EEPROM programming */ + return (TRUE); +} + + +/***************************************************************************/ +static void orc_setup_SCBs(A100_HCS *hcsp) +{ + A100_SCB *pTmpScb, *pPrevScb; + int i; + + pPrevScb = NULL; + /* Setup SCB Base and SCB Size registers */ + outb(hcsp->HCS_Base+ORC_SCBSIZE, MAX_SCB ); /* Total number of SCBs */ + outl(hcsp->HCS_Base+ORC_SCBBASE0, hcsp->pPhyScbArray); /* SCB base address 0 */ + outl(hcsp->HCS_Base+ORC_SCBBASE1, hcsp->pPhyScbArray); /* SCB base address 1 */ + + for (i = 0, pTmpScb = hcsp->pScbArray; i < MAX_SCB ; i++, pTmpScb++) { + pTmpScb->SCB_ScbIdx = i; + pTmpScb->SCB_Reserved0 = 0; + pTmpScb->SCB_Reserved1 = 0; + pTmpScb->SCB_SGPAddrHigh = 0; + pTmpScb->SCB_Link = 0xff; + pTmpScb->SCB_Status = 0; + pTmpScb->SCB_TagMsg = 0; + pTmpScb->SCB_FreeFlag = 0; + if(i != 0) + pPrevScb->SCB_NextScb = pTmpScb; + pPrevScb = pTmpScb; + } + + pPrevScb->SCB_NextScb = NULL; + hcsp->HCS_FirstAvail = hcsp->pScbArray; + hcsp->HCS_LastAvail = pPrevScb; + + + return; +} + +/***************************************************************************/ +static int orc_init(A100_HCS *hcsp, A100_SCB *pScb,A100_SG *pSG) +{ + UBYTE *readBytep; + USHORT revision; + ULONG i; + + hcsp->pScbArray = pScb; + hcsp->pPhyScbArray = (ULONG) vtophys(pScb); + + hcsp->SGList = pSG; + hcsp->pPhySG = (ULONG) vtophys(pSG); + + hcsp->HCS_FirstPend = NULL; + hcsp->HCS_LastPend = NULL; + + + outb(hcsp->HCS_Base+ORC_GIMSK, 0xFF); /* Disable all interrupt*/ + if (inb(hcsp->HCS_Base+ORC_HSTUS) & RREADY) { + orc_get_FW_version(hcsp, &revision); + if (revision == 0xFFFF) { + outb(hcsp->HCS_Base+ORC_HCTRL, DEVRST); + if (orc_waitChipReady(hcsp) == FALSE) /* Wait HOSTSTOP reset */ + return (1); + orc_load_FW(hcsp); /* Download FW*/ + orc_setup_SCBs(hcsp); /* Setup SCB Base and SCB Size registers*/ + + outb(hcsp->HCS_Base+ORC_HCTRL, 0); /* clear HOSTSTOP */ + if (orc_waitFWReady(hcsp) == FALSE) + return (1); + } + else { + orc_setup_SCBs(hcsp); /* Setup SCB Base and SCB Size registers*/ + } + } + else { /* Orchid is not Ready */ + outb(hcsp->HCS_Base+ORC_HCTRL, DEVRST); /* Reset Host Adapter */ + if (orc_waitChipReady(hcsp) == FALSE) /* Wait HOSTSTOP reset */ + return (1); + orc_load_FW(hcsp); /* Download FW*/ + orc_setup_SCBs(hcsp); /* Setup SCB Base and SCB Size registers*/ + outb(hcsp->HCS_Base+ORC_HCTRL, HDO); /* Do Hardware Reset & */ + if (orc_waitFWReady(hcsp) == FALSE) + return (1); + + } + + /*------------- get serial EEProm settting -------*/ + + orc_read_eeprom(hcsp); + + if (nvramp->Revision != 1) + return(-1); + + hcsp->HCS_SCSI_ID = nvramp->SCSI0Id; + + if(inb(hcsp->HCS_Base+ORC_GSTAT) & WIDEBUS) + hcsp->HCS_MaxTar = 16; + else + hcsp->HCS_MaxTar = 8; + + readBytep = (UCHAR*) &(nvramp->Target00Config); + for (i = 0; i < 16; readBytep++, i++) { + hcsp->TargetFlag[i] = (*readBytep) & (~TCF_BUSY); + hcsp->MaximumTags[i] = MAX_SCB; + hcsp->ActiveTags[i] = 0; + } + + if (nvramp->SCSI0Config & NCC_BUSRESET) { /* Reset SCSI bus*/ + printf("ihb%d: Resetting SCSI Bus ...\n",hcsp->HCS_Unit); + outb(hcsp->HCS_Base+ORC_HCTRL, SCSIRST); /* Do Hardware Reset & */ + DELAY(50000); + } + outb(hcsp->HCS_Base+ORC_GIMSK, 0xFB); /* enable Reply FIFO interrupt */ + return (0); +} + + + + + + +static void orc_append_pend_scb(A100_HCS *pHcs, A100_SCB *scbp) +{ + int flags; + + scbp->SCB_NextScb = NULL; + + flags = splsoftcam(); + if (pHcs->HCS_LastPend != NULL) { + pHcs->HCS_LastPend->SCB_NextScb = scbp; + pHcs->HCS_LastPend = scbp; + } + else { + pHcs->HCS_FirstPend = scbp; + pHcs->HCS_LastPend = scbp; + } + splx(flags); +} + + + + + +static A100_SCB *orc_abort_srb(A100_HCS *pHcs, ULONG srbp) +{ + + A100_SCB *pScb, *pPrevScb; + ULONG i; + int flags; + + flags = splcam(); + pPrevScb = NULL; + pScb = pHcs->HCS_FirstPend; /* Check Pend queue */ + while (pScb != NULL) { + if (pScb->SCB_ccb == srbp) { + if (pPrevScb == NULL) { + if ((pHcs->HCS_FirstPend = pScb->SCB_NextScb) == NULL) + pHcs->HCS_LastPend = NULL; + } + else { + pPrevScb->SCB_NextScb = pScb->SCB_NextScb; + if (pScb == pHcs->HCS_LastPend) + pHcs->HCS_LastPend = pPrevScb; + } + pScb->SCB_NextScb = NULL; + a100_free_scb(pHcs, pScb); + splx(flags); + return (pScb); + } + + pPrevScb = pScb; + pScb = pScb->SCB_NextScb; + } + + for (i = 0, pScb = pHcs->pScbArray; i < MAX_SCB ; i++, pScb++) { + if ((pScb->SCB_Status) && (pScb->SCB_ccb == srbp)) { + orc_abort_SCB(pHcs, pScb); + a100_free_scb(pHcs, pScb); + splx(flags); + return (pScb); + } + } + splx(flags); + return (NULL); +} + + + + + + +static A100_SCB * orc_alloc_scb(A100_HCS *pHcs) +{ + A100_SCB *pScb; + int opri; + + opri = splcam(); + + if ((pScb = pHcs->HCS_FirstAvail) != NULL) { + if(pScb->SCB_NextScb == NULL) { + pHcs->HCS_FirstAvail = NULL; + pHcs->HCS_LastAvail = NULL; + } + else{ + pHcs->HCS_FirstAvail = pScb->SCB_NextScb; + } + pScb->SCB_NextScb = NULL; + pScb->SCB_FreeFlag = 1; + } + splx(opri); + return (pScb); +} + + + + +/* + * An scb (and hence an scb entry on the board) is put onto the + * free list. + */ +static void orc_release_scb(A100_HCS *pHcs, A100_SCB *pScb) +{ + + int opri; + + if(pScb->SCB_FreeFlag == 0) + return; + + pScb->SCB_FreeFlag = 0; + pScb->SCB_ccb = NULL; + pScb->SCB_NextScb = NULL; + + opri = splcam(); + if(pHcs->HCS_LastAvail != NULL) { + pHcs->HCS_LastAvail->SCB_NextScb = pScb; + pHcs->HCS_LastAvail = pScb; + } + else { + pHcs->HCS_FirstAvail = pScb; + pHcs->HCS_LastAvail = pScb; + } + splx(opri); +} + + +static void orc_isr (A100_HCS *pHcs) +{ + ULONG bScbIdx; + + if(inb(pHcs->HCS_Base+ORC_RQUEUECNT) == 0) + return ; + + do{ + bScbIdx = (ULONG)inb(pHcs->HCS_Base+ORC_RQUEUE); + a100_done(pHcs,&(pHcs->pScbArray[bScbIdx])); + }while(inb(pHcs->HCS_Base+ORC_RQUEUECNT)); + +} + + + +static void a100_free_scb(A100_HCS *pHcs, A100_SCB *pScb) +{ + orc_release_scb(pHcs, pScb); + /* + * Wake anybody waiting for one to come free. + */ + + wakeup((caddr_t)&pHcs->pScbArray); +} + + +/* + * We have a scb which has been processed by the + * adaptor, now we look to see how the operation + * went. + */ +static void +a100_done(A100_HCS *pHcs, A100_SCB *pScb) +{ + union ccb *ccb = (union ccb *)pScb->SCB_ccb; + + struct ccb_scsiio *csio = &ccb->csio; + + + pScb->SCB_Status = 0; + pScb->SCB_ccb = NULL; + +/*** printf("--Enter a100_done(%d-%d-%02x)--",pScb->SCB_Target,pScb->SCB_Lun,pScb->SCB_TaStat);***/ + if(pScb->SCB_TagMsg) { + if(pHcs->ActiveTags[pScb->SCB_Target] <= 1) + pHcs->ActiveTags[pScb->SCB_Target] = 0; + else + pHcs->ActiveTags[pScb->SCB_Target]--; + + if(pHcs->MaximumTags[pScb->SCB_Target] > pHcs->ActiveTags[pScb->SCB_Target]) + pHcs->TargetFlag[pScb->SCB_Target] &= ~TCF_BUSY; + } + else + pHcs->TargetFlag[pScb->SCB_Target] &= ~TCF_BUSY; + + if((ULONG)ccb == 0) { + printf("free scb while xs=0 in a100_done \n"); + a100_free_scb(pHcs, pScb); + return; + } + + /* + ** Check the status. + */ + if ( (pScb->SCB_HaStat == HOST_OK) + && (pScb->SCB_TaStat == TARGET_GOOD)) { + ccb->ccb_h.status = CAM_REQ_CMP; + csio->scsi_status = SCSI_STATUS_OK; + } else if ((pScb->SCB_HaStat== HOST_OK) + && (pScb->SCB_TaStat== TARGET_CHKCOND )) { + + +/*** bcopy(&pHcs->SGList[pScb->SCB_ScbIdx << 5], &csio->sense_data, SSD_FULL_SIZE);***/ + /* + ** Check condition code + */ + ccb->ccb_h.status |= CAM_AUTOSNS_VALID; + csio->scsi_status = SCSI_STATUS_CHECK_COND; + + } else if ((pScb->SCB_HaStat== HOST_OK) + && (pScb->SCB_TaStat== TARGET_BUSY)) { + + /* + ** Target is busy. + */ +/*** ccb->ccb_h.status = CAM_SCSI_BUSY;***/ + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + csio->scsi_status = SCSI_STATUS_BUSY; + + } else if ((pScb->SCB_HaStat== HOST_OK) + && (pScb->SCB_TaStat== TARGET_QFULL)) { + + if((pHcs->MaximumTags[pScb->SCB_Target] = pHcs->ActiveTags[pScb->SCB_Target]) < 1) + pHcs->MaximumTags[pScb->SCB_Target] = 1; + /* + ** Target is queue full. + */ +/*** ccb->ccb_h.status = CAM_SCSI_BUSY;***/ + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + csio->scsi_status = SCSI_STATUS_QUEUE_FULL; + + } else if (pScb->SCB_HaStat== HOST_SEL_TOUT ) { + + /* + ** Device failed selection + */ + ccb->ccb_h.status = CAM_SEL_TIMEOUT; + + } else if (pScb->SCB_HaStat == HOST_DO_DU) { + + /* + ** Data overrun(underrun) + */ + ccb->ccb_h.status = CAM_DATA_RUN_ERR; + + } else if (pScb->SCB_HaStat == HOST_BUS_FREE) { + + /* + ** Bus free + */ + ccb->ccb_h.status = CAM_UNEXP_BUSFREE; + + } else if (pScb->SCB_HaStat == HOST_BAD_PHAS) { + + /* + ** Bad phase + */ + ccb->ccb_h.status = CAM_SEQUENCE_FAIL; + + } else if (pScb->SCB_HaStat == HOST_INV_CMD) { + + /* + ** Invalid command + */ + ccb->ccb_h.status = CAM_REQ_INVALID; + + } else if (pScb->SCB_HaStat == HOST_SCSI_RST) { + + /* + ** SCSI bus reset + */ + ccb->ccb_h.status = CAM_SCSI_BUS_RESET; + + } else if (pScb->SCB_HaStat == HOST_DEV_RST) { + + /* + ** SCSI device reset + */ + ccb->ccb_h.status = CAM_SCSI_BUS_RESET; /* XXX right? */ + + } else { /* Other protocol messes */ + ccb->ccb_h.status = CAM_CMD_TIMEOUT; + } + + + untimeout(a100_timeout, (caddr_t) pScb,ccb->ccb_h.timeout_ch); + xpt_done(ccb); + + a100_free_scb(pHcs, pScb); + + /* check pending queue */ + a100_send_scb(pHcs); +} + +static void +a100_timeout(void *arg1) +{ + + union ccb *ccb; + A100_HCS *pHcs; + int s; + A100_SCB *pScb = (A100_SCB*) arg1; + ccb = (union ccb *)pScb->SCB_ccb; + + if (ccb == NULL) + return; + + pHcs = (A100_HCS *)xpt_path_sim(ccb->ccb_h.path)->softc; +/*** pHcs = (A100_HCS *)ccb->ccb_h.ccb_a100_ptr;***/ + + s = splcam(); + if (orc_abort_srb(pHcs, (ULONG) ccb)) { + printf("ihb: timed out\n"); + ccb->ccb_h.status |= CAM_REQ_ABORTED; + xpt_done(ccb); + } + splx(s); +} + + +#if 0 +static int a100_wait_scb(A100_HCS *pHcs,A100_SCB *pScb,int time) +{ + while(time >0) { + if(pScb->SCB_Status == 0) { + a100_done(pHcs,pScb); + return (TRUE); + } + DELAY(1000); /* 1 ms */ + time--; + } + + a100_free_scb(pHcs, pScb); + return (FALSE); + +} +#endif + + +static void a100_send_scb(A100_HCS *pHcs) +{ + A100_SCB *pScb, *pPrev; + + pScb = pHcs->HCS_FirstPend; + pPrev = pScb; + for (; pScb != NULL; pPrev = pScb, pScb = pScb->SCB_NextScb) { + + if (pHcs->TargetFlag[pScb->SCB_Target] & TCF_BUSY) + continue; + + if (pScb->SCB_TagMsg) { + pHcs->ActiveTags[pScb->SCB_Target]++; + if(pHcs->MaximumTags[pScb->SCB_Target] <= pHcs->ActiveTags[pScb->SCB_Target]) + pHcs->TargetFlag[pScb->SCB_Target] |= TCF_BUSY; + } + else + pHcs->TargetFlag[pScb->SCB_Target] |= TCF_BUSY; + + /* unlink pScb */ + if ( pScb == pHcs->HCS_FirstPend) { + if ((pHcs->HCS_FirstPend = pScb->SCB_NextScb) == NULL) + pHcs->HCS_LastPend = NULL; + } + else if ((pPrev->SCB_NextScb = pScb->SCB_NextScb) == NULL) { + pHcs->HCS_LastPend = pPrev; + } + +/*** printf("$$$To send scb$$$");***/ + orc_send_scb(pHcs, pScb); + } + +} + + + + + + +void a100_exec_scb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) +{ + A100_SCB * pScb; + union ccb *ccb; + A100_HCS *pHcs; + A100_SG *sg; + struct ccb_scsiio *csio; + int s; + + pScb = (A100_SCB *)arg; + ccb = (union ccb *)pScb->SCB_ccb; + csio = &ccb->csio; + pHcs = (A100_HCS *)xpt_path_sim(ccb->ccb_h.path)->softc; + + if(pScb->SCB_CDB[0] == 0x3) { + + /* disable SCSI DISCONNECT if it is "REQUEST SENSE" command */ + printf("--REQUEST SENSE--"); + pScb->SCB_Ident &= 0xBF; + + } + + + if (error != 0) { + if (error != EFBIG) + printf("a100: Unexepected error 0x%x returned from bus_dmamap_load\n", error); + if (ccb->ccb_h.status == CAM_REQ_INPROG) { + xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); + ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; + } + a100_free_scb(pHcs, pScb); + xpt_done(ccb); + return; + } + + + pScb->SCB_XferLen = 0; + pScb->SCB_SGLen = 0; + + sg =&pHcs->SGList[pScb->SCB_ScbIdx << 5]; + pScb->SCB_SGPAddr = (ULONG) vtophys(sg); + + sg->SG_Ptr = 0; + sg->SG_Len= 0; + +/*** printf("--exec(seg=%d,xferl=%d,cdl=%d,tag=%02x)--",nseg,csio->dxfer_len,pScb->SCB_CDBLen,pScb->SCB_TagMsg);***/ + if(csio->dxfer_len){ + pScb->SCB_XferLen = csio->dxfer_len; + + + if (nseg != 0) { +/*** + int seg; + vm_size_t datalen; + vm_offset_t vaddr; + u_int32_t paddr; + u_int32_t nextpaddr; + + seg = 0; + datalen = (vm_size_t)csio->dxfer_len; + vaddr = (vm_offset_t)csio->data_ptr, + paddr = vtophys(vaddr); + + while ((datalen > 0) && (seg < A100_SG_ENTRY)) { + sg->SG_Ptr = paddr; + sg->SG_Len= 0; + + nextpaddr = paddr; + + while ((datalen > 0) && (paddr == nextpaddr)) { + u_int32_t size; + nextpaddr = (paddr & (~PAGE_MASK)) + PAGE_SIZE; + + size = nextpaddr - paddr; + if (size > datalen) + size = datalen; + + + sg->SG_Len += size; + vaddr += size; + datalen -= size; + if (datalen > 0) + paddr = vtophys(vaddr); + } + seg++; + sg++; + } + + if (datalen) { + printf("ihb_scsi_cmd: more than supposed DMA segs exist \n"); + a100_free_scb(pHcs, pScb); + xpt_done(ccb); + return; + } + + pScb->SCB_SGLen = seg << 3; +***/ + + + + bus_dma_segment_t *end_seg; + + end_seg = dm_segs + nseg; + + while (dm_segs < end_seg) { + sg->SG_Len = dm_segs->ds_len; + sg->SG_Ptr = dm_segs->ds_addr; + sg++; + dm_segs++; + } + + pScb->SCB_SGLen = nseg << 3; + +/*** + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) + op = BUS_DMASYNC_PREREAD; + else + op = BUS_DMASYNC_PREWRITE; + + bus_dmamap_sync(pHcs->buffer_dmat, pHcs->dmamap, op); +***/ + + } else { + sg->SG_Len = csio->dxfer_len; + sg->SG_Ptr = (ULONG)csio->data_ptr; + pScb->SCB_SGLen = 8; + } + } + + s = splcam(); + ccb->ccb_h.timeout_ch = timeout(a100_timeout, (caddr_t)pScb, (ccb->ccb_h.timeout * hz)/1000); + /* alway append into pending queue */ + orc_append_pend_scb(pHcs, pScb); + + /* check pending queue */ + a100_send_scb(pHcs); + splx(s); +} + + +/*========================================================== +** +** +** Start execution of a SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ + +void a100_action(struct cam_sim *sim, union ccb *ccb) +{ + A100_HCS *pHcs; + A100_SCB *pScb; + int flags,flagio; + struct cam_path *path; + struct scsi_inquiry_data *inq_buf; + + path = ccb->ccb_h.path; + inq_buf = NULL; + pHcs = (A100_HCS *) cam_sim_softc(sim); + +/*** printf("--action(%d-%d-%02x-%08x)--",ccb->ccb_h.target_id,ccb->ccb_h.target_lun,ccb->ccb_h.func_code,ccb->ccb_h.flags); +***/ + switch (ccb->ccb_h.func_code) { + /* Common cases first */ + case XPT_SCSI_IO: /* Execute the requested I/O operation */ + case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ + { + struct ccb_scsiio *csio = &ccb->csio; + + flags = ccb->ccb_h.flags; + flagio = csio->ccb_h.flags; + + + /* + * Last time we need to check if this CCB needs to + * be aborted. + */ + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { + xpt_done(ccb); + return; + } + ccb->ccb_h.status |= CAM_SIM_QUEUED; + + /* + * get an scb to use. + */ + if ((pScb = orc_alloc_scb(pHcs)) == NULL) { +/*** printf("--!pScb--");***/ + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + return; + } + + + pScb->SCB_Target = ccb->ccb_h.target_id; + pScb->SCB_Lun = ccb->ccb_h.target_lun; + + + pScb->SCB_HaStat = 0; + pScb->SCB_TaStat = 0; + pScb->SCB_Status = 0; + pScb->SCB_Link = 0xFF; + + pScb->SCB_Reserved0 = 0; + pScb->SCB_Reserved1 = 0; + + pScb->SCB_ccb =(ULONG)ccb; + + pScb->SCB_Flags = 0; + if (ccb->ccb_h.func_code == XPT_RESET_DEV) { + pScb->SCB_Opcode = BusDevRst; + } + else{ + + + pScb->SCB_Opcode = ExecSCSI; + + if((flagio & CAM_DIR_MASK) == CAM_DIR_NONE) + pScb->SCB_Flags = SCF_NO_DCHK; + else if(flagio & CAM_DIR_IN) + pScb->SCB_Flags = SCF_DIN; + else if(flagio & CAM_DIR_OUT) + pScb->SCB_Flags = SCF_DOUT; + + pScb->SCB_Ident = pScb->SCB_Lun | DISC_ALLOW; + pScb->SCB_CDBLen = csio->cdb_len; + if(pScb->SCB_CDBLen > 14) + pScb->SCB_CDBLen = 14; + + + if ((flagio & CAM_CDB_POINTER) != 0) { + if ((flagio & CAM_CDB_PHYS) == 0) { + bcopy(csio->cdb_io.cdb_ptr, pScb->SCB_CDB, pScb->SCB_CDBLen); + } else { + ccb->ccb_h.status = CAM_REQ_INVALID; + a100_free_scb(pHcs, pScb); + xpt_done(ccb); + return; + } + } else { + bcopy(csio->cdb_io.cdb_bytes, pScb->SCB_CDB, pScb->SCB_CDBLen); + } + +/*** + inq_buf = &path->device->inq_data; + printf("*a100inq(%02x %02x %02x %02x %02x)*",inq_buf->device,inq_buf->dev_qual2,inq_buf->version,inq_buf->response_format,inq_buf->flags); +***/ + + + if((flags & CAM_TAG_ACTION_VALID) != 0 && (csio->tag_action != CAM_TAG_ACTION_NONE)){ + pScb->SCB_TagMsg = csio->tag_action; + pHcs->TargetFlag[pScb->SCB_Target] |= TCF_EN_TAG; + } + else{ + pScb->SCB_TagMsg = 0; + pHcs->TargetFlag[pScb->SCB_Target] &= ~TCF_EN_TAG; + } + + pScb->SCB_SenseLen = csio->sense_len; + pScb->SCB_SensePAddr = vtophys(&csio->sense_data); + + /*---------------------------------------------------- + ** + ** Build the data descriptors + ** + **---------------------------------------------------- + */ + + /* Only use S/G if there is a transfer */ + if ((flagio & CAM_DIR_MASK) != CAM_DIR_NONE) { + + + if ((flagio & CAM_SCATTER_VALID) == 0) { + /* + * We've been given a pointer + * to a single buffer. + */ + if ((flagio & CAM_DATA_PHYS)==0) { + int s; + int error; + +/*** printf("--CAM_DATA_PHYS=0--");***/ + s = splsoftvm(); + error = bus_dmamap_load( + pHcs->buffer_dmat, + pHcs->dmamap, + csio->data_ptr, + csio->dxfer_len, + a100_exec_scb, + pScb, + /*flags*/0); + if (error == EINPROGRESS) { + /* + * So as to maintain + * ordering, freeze the + * controller queue + * until our mapping is + * returned. + */ + xpt_freeze_simq(pHcs->sim, + 1); + csio->ccb_h.status |= + CAM_RELEASE_SIMQ; + } + splx(s); + } else { + struct bus_dma_segment seg; + + /* Pointer to physical buffer */ + seg.ds_addr = + (bus_addr_t)csio->data_ptr; + seg.ds_len = csio->dxfer_len; + a100_exec_scb(pScb,&seg,1,0); + } + } else { + struct bus_dma_segment *segs; + if ((flagio & CAM_DATA_PHYS) != 0) + panic("a100action - Physical " + "segment pointers " + "unsupported"); + + if ((flagio&CAM_SG_LIST_PHYS)==0) + panic("a100action - Virtual " + "segment addresses " + "unsupported"); + + segs = (struct bus_dma_segment *) + csio->data_ptr; + a100_exec_scb(pScb,segs,csio->sglist_cnt,0); + + } + } else { + a100_exec_scb(pScb,NULL,0,0); + } + } + + break; + } + + + case XPT_EN_LUN: /* Enable LUN as a target */ + case XPT_TARGET_IO: /* Execute target I/O request */ + case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ + case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ + case XPT_ABORT: /* Abort the specified CCB */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + case XPT_SET_TRAN_SETTINGS: + { + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + case XPT_GET_TRAN_SETTINGS: + /* Get default/user set transfer settings for the target */ + { + + struct ccb_trans_settings *cts; + + cts = &ccb->cts; + + cts->flags = 0; + cts->flags |= CCB_TRANS_DISC_ENB; + + cts->flags |= CCB_TRANS_TAG_ENB; + + cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; + + cts->sync_period = scsi_calc_syncparam(80); +/*** cts->sync_period = 80;***/ + cts->sync_offset = 15; + + cts->valid = CCB_TRANS_SYNC_RATE_VALID + | CCB_TRANS_SYNC_OFFSET_VALID + | CCB_TRANS_BUS_WIDTH_VALID + | CCB_TRANS_DISC_VALID + | CCB_TRANS_TQ_VALID; + + +/*** struct ccb_trans_settings *cts; + u_int target_mask; + + cts = &ccb->cts; + target_mask = 0x01 << ccb->ccb_h.target_id; + if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) { + cts->flags = 0; + if ((bt->disc_permitted & target_mask) != 0) + cts->flags |= CCB_TRANS_DISC_ENB; + if ((bt->tags_permitted & target_mask) != 0) + cts->flags |= CCB_TRANS_TAG_ENB; + if ((bt->wide_permitted & target_mask) != 0) + cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; + else + cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; + if ((bt->ultra_permitted & target_mask) != 0) + cts->sync_period = 12; + else if ((bt->fast_permitted & target_mask) != 0) + cts->sync_period = 25; + else if ((bt->sync_permitted & target_mask) != 0) + cts->sync_period = 50; + else + cts->sync_period = 0; + + if (cts->sync_period != 0) + cts->sync_offset = 15; + + cts->valid = CCB_TRANS_SYNC_RATE_VALID + | CCB_TRANS_SYNC_OFFSET_VALID + | CCB_TRANS_BUS_WIDTH_VALID + | CCB_TRANS_DISC_VALID + | CCB_TRANS_TQ_VALID; + } else { + btfetchtransinfo(bt, cts); + } +***/ + + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + case XPT_CALC_GEOMETRY: + { + struct ccb_calc_geometry *ccg; + u_int32_t size_mb; + u_int32_t secs_per_cylinder; + + ccg = &ccb->ccg; + size_mb = ccg->volume_size + / ((1024L * 1024L) / ccg->block_size); + + if (size_mb >= 1024 ) { + ccg->heads = 255; + ccg->secs_per_track = 63; + } else { + ccg->heads = 64; + ccg->secs_per_track = 32; + } + secs_per_cylinder = ccg->heads * ccg->secs_per_track; + ccg->cylinders = ccg->volume_size / secs_per_cylinder; + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + case XPT_RESET_BUS: /* Reset the specified SCSI bus */ + { + outb(pHcs->HCS_Base+ORC_HCTRL, SCSIRST); /* Do Hardware Reset & */ + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + case XPT_TERM_IO: /* Terminate the I/O process */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + case XPT_PATH_INQ: /* Path routing inquiry */ + { + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; /* XXX??? */ + cpi->hba_inquiry = PI_SDTR_ABLE; + if (ccb->csio.tag_action != 0) + cpi->hba_inquiry |= PI_TAG_ABLE; + if(pHcs->HCS_MaxTar == 16) + cpi->hba_inquiry |= PI_WIDE_16; + + cpi->target_sprt = 0; + cpi->hba_misc = 0; + cpi->hba_eng_cnt = 0; + cpi->max_target = pHcs->HCS_MaxTar-1; + cpi->max_lun = 7; + cpi->initiator_id = pHcs->HCS_SCSI_ID; + cpi->bus_id = cam_sim_bus(sim); + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(cpi->hba_vid, "Initio", HBA_IDLEN); + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + cpi->unit_number = cam_sim_unit(sim); + cpi->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + default: + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + + } +} + + +void a100_poll(struct cam_sim *sim) +{ + A100_HCS *pHcs; + + pHcs = (A100_HCS *) cam_sim_softc(sim); + + orc_isr(pHcs); + + +} + +#if 0 +void a100_min_phys( struct buf *bp ) +{ + if (bp->b_bcount > ((A100_SG_ENTRY - 1) * PAGELEN)) + bp->b_bcount = ((A100_SG_ENTRY - 1) * PAGELEN); + +#if defined(__NetBSD__) + minphys(bp); +#endif +} +#endif + + +/*========================================================== +** +** +** Auto configuration: attach and init a host adapter. +** +** +**========================================================== +*/ + +void +a100_attach (pcici_t config_id, int unit) +{ + u_int16_t io_port; + u_int32_t id; + A100_HCS *pHcs; + A100_SCB *pScb; + A100_SG *pSG; + int s,error,openings; + struct cam_devq *devq; + union ccb *work_ccb; + + if( unit >= MAX_SUPPORTED_ADAPTERS) + return; + + + io_port = 0; + if (pci_map_port(config_id, PCI_BASEADDR0, &io_port) == 0) + return; + + + pHcs = (A100_HCS *) malloc (sizeof(A100_HCS), M_DEVBUF, M_NOWAIT); + if( !pHcs ) { + printf("ihb: cannot allocate HCS !\n"); + return; + } + + bzero (pHcs, sizeof(A100_HCS)); + pHcs->HCS_Base = io_port; + pHcs->HCS_Unit = unit; + + + + switch ((id = pci_conf_read(config_id, PCI_ID_REG))) { + + case PCI_DEVICE_ID_INIC1060: + break; + + case PCI_DEVICE_ID_INIC850: + break; + + default: + free(pHcs, M_DEVBUF); + return; + } + + /* Allocate a dmatag for our transfer DMA maps */ + /* XXX Should be a child of the PCI bus dma tag */ + error = bus_dma_tag_create(/*parent*/ NULL, + /*alignment*/ 0, + /*boundary*/ 0, + /*lowaddr*/ (0xFFFFFFFFL), + /*highaddr*/ BUS_SPACE_MAXADDR, + /*filter*/ NULL, + /*filterarg*/ NULL, + /*maxsize*/ BUS_SPACE_MAXSIZE_32BIT, + /*nsegments*/ BUS_SPACE_UNRESTRICTED, + /*maxsegsz*/ (0xFFFFFFL), + /*flags*/ 0, + &pHcs->parent_dmat); + + if (error != 0) { + printf("ihb: Could not allocate DMA tag - error %d\n", + error); + free(pHcs, M_DEVBUF); + return; + } + + + pScb = (A100_SCB *) malloc (sizeof(A100_SCB)*MAX_SCB, M_DEVBUF, M_NOWAIT); + if( !pScb ) { + printf("ihb: cannot allocate SCB !\n"); + bus_dma_tag_destroy(pHcs->parent_dmat); + free(pHcs, M_DEVBUF); + return; + } + bzero (pScb, sizeof(A100_SCB)*MAX_SCB); + + pSG = (A100_SG *) malloc (sizeof(A100_SG)*MAX_SCB*MAX_SG, M_DEVBUF, M_NOWAIT); + if( !pSG ) { + printf("ihb: cannot allocate SG !\n"); + free(pScb, M_DEVBUF); + bus_dma_tag_destroy(pHcs->parent_dmat); + free(pHcs, M_DEVBUF); + return; + } + orc_init(pHcs, pScb,pSG); + + if (!(pci_map_int(config_id, (void *)orc_isr, (void *)pHcs, &cam_imask))) { + printf("Can't pci_map_int \n"); + bus_dma_tag_destroy(pHcs->parent_dmat); + free(pHcs, M_DEVBUF); + return; + } + + + /* DMA tag for mapping buffers into device visible space. */ + if (bus_dma_tag_create(pHcs->parent_dmat, /*alignment*/0, /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/MAXBSIZE, /*nsegments*/A100_SG_ENTRY, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/BUS_DMA_ALLOCNOW, + &pHcs->buffer_dmat) != 0) { + return; + } + + + /* + ** Create the device queue. We only allow MAX_START-1 concurrent + ** transactions so we can be sure to have one element free in our + ** start queue to reset to the idle loop. + */ + s = splcam(); + openings = MAX_SCB-1; + devq = cam_simq_alloc(openings); + if (devq == NULL){ + return; + splx(s); + } + + /* + ** Now tell the generic SCSI layer + ** about our bus. + */ + pHcs->sim = cam_sim_alloc(a100_action, a100_poll, "ihb", pHcs, + pHcs->HCS_Unit , + 1, openings, devq); + if (pHcs->sim == NULL) { + cam_simq_free(devq); + splx(s); + return; + } + + + + + if (xpt_bus_register(pHcs->sim, 0) != CAM_SUCCESS) { + cam_sim_free(pHcs->sim, TRUE); + splx(s); + return; + } + + + +#ifdef __alpha__ + alpha_register_pci_scsi(config_id->bus, config_id->slot, pHcs->sim); +#endif + + work_ccb = xpt_alloc_ccb(); + if (xpt_create_path(&pHcs->path, NULL, + cam_sim_path(pHcs->sim), CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_bus_deregister(cam_sim_path(pHcs->sim)); + cam_sim_free(pHcs->sim, TRUE); + xpt_free_ccb(work_ccb); + splx(s); + return; + } +/*** + xpt_setup_ccb(&work_ccb->ccb_h, pHcs->path, 1); + work_ccb->ccb_h.func_code = XPT_SCAN_BUS; + work_ccb->ccb_h.cbfcnp = NULL; + xpt_action(work_ccb); + xpt_finishconfig(NULL, work_ccb); +***/ +/*** xpt_config(NULL);***/ + + /* + * Register a callback for when interrupts are enabled. + */ +/*** + a100_config_hook = (struct intr_config_hook *)malloc(sizeof(struct intr_config_hook), M_TEMP, M_NOWAIT); + if (a100_config_hook == NULL) { + printf("Cannot malloc config hook failing attach\n"); + return; + } + bzero(a100_config_hook, sizeof(*a100_config_hook)); + + a100_config_hook->ich_func = xpt_config; + if (config_intrhook_establish(a100_config_hook) != 0) { + free (a100_config_hook, M_TEMP); + printf("config_intrhook_establish failed failing attach\n"); + } +***/ + + + + + splx(s); + return; + +} + + +/*---------------------------------------------------------- +** +** Probe the hostadapter. +** +**---------------------------------------------------------- +*/ + +static const char* +a100_probe (pcici_t tag, pcidi_t type) +{ + switch (type) { + case PCI_DEVICE_ID_INIC1060: + return ("Initio INI-A100U2W PCI SCSI adapter"); + case PCI_DEVICE_ID_INIC850: + return ("Initio INI-A100UW PCI SCSI adapter"); + } + return (NULL); +} diff -urN -urN src/sys/dev/ihaempty/a100.h src/sys/dev/iha/a100.h --- src/sys/dev/ihaempty/a100.h Thu Jan 1 02:00:00 1970 +++ src/sys/dev/iha/a100.h Sun Oct 24 12:16:18 1999 @@ -0,0 +1,549 @@ +/*- + * Copyright (c) 1998 Initio Corporation + * All rights reserved. + * + * 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. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY INITIO CORPORATION ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL INITIO CORPORATION BE LIABLE FOR ANY DIRECT,INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: a100scsi.h v 1.00 1998/10/08 se Exp $ + */ + + +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned long + +#define ULONG unsigned long +#define ulong unsigned long +#define uint unsigned long +#define USHORT unsigned short +#define ushort unsigned short +#define UWORD unsigned short +#define uword unsigned short +#define UCHAR unsigned char +#define uchar unsigned char +#define UBYTE unsigned char +#define ubyte unsigned char + +#ifndef NULL +#define NULL 0 /* zero */ +#endif +#ifndef TRUE +#define TRUE (1) /* boolean true */ +#endif +#ifndef FALSE +#define FALSE (0) /* boolean false */ +#endif + + +#define A100_SG_ENTRY 32 +#define MAX_SUPPORTED_ADAPTERS 8 +#define MAX_TARGETS 16 +#define MAX_SCB 32 +#define MAX_SG 32 + +#define PAGELEN 4096 +#define INI_VENDOR_ID 0x1101 + +typedef struct{ + unsigned short base; + unsigned short vec; +}a100_config; + + + + +typedef struct _NVRAM { + /*----------header ---------------*/ + UCHAR SubVendorID0; /* 00 - Sub Vendor ID */ + UCHAR SubVendorID1; /* 01 - Sub Vendor ID */ + UCHAR SubSysID0; /* 02 - Sub System ID */ + UCHAR SubSysID1; /* 03 - Sub System ID */ + UCHAR SubClass; /* 04 - Sub Class */ + UCHAR VendorID0; /* 05 - Vendor ID */ + UCHAR VendorID1; /* 06 - Vendor ID */ + UCHAR DeviceID0; /* 07 - Device ID */ + UCHAR DeviceID1; /* 08 - Device ID */ + UCHAR Reserved0[2]; /* 09 - Reserved */ + UCHAR Revision; /* 0B - Revision of data structure */ + /* ----Host Adapter Structure ----*/ + UCHAR NumOfCh; /* 0C - Number of SCSI channel */ + UCHAR BIOSConfig1; /* 0D - BIOS configuration 1 */ + UCHAR BIOSConfig2; /* 0E - BIOS boot channel&target ID */ + UCHAR BIOSConfig3; /* 0F - BIOS configuration 3 */ + /* ----SCSI channel Structure ---- */ + /* from "CTRL-I SCSI Host Adapter SetUp menu " */ + UCHAR SCSI0Id; /* 10 - Channel 0 SCSI ID */ + UCHAR SCSI0Config; /* 11 - Channel 0 SCSI configuration */ + UCHAR SCSI0MaxTags; /* 12 - Channel 0 Maximum tags */ + UCHAR SCSI0ResetTime; /* 13 - Channel 0 Reset recovering time */ + UCHAR ReservedforChannel0[2]; /* 14 - Reserved */ + + /* ----SCSI target Structure ---- */ + /* from "CTRL-I SCSI device SetUp menu " */ + UCHAR Target00Config; /* 16 - Channel 0 Target 0 config */ + UCHAR Target01Config; /* 17 - Channel 0 Target 1 config */ + UCHAR Target02Config; /* 18 - Channel 0 Target 2 config */ + UCHAR Target03Config; /* 19 - Channel 0 Target 3 config */ + UCHAR Target04Config; /* 1A - Channel 0 Target 4 config */ + UCHAR Target05Config; /* 1B - Channel 0 Target 5 config */ + UCHAR Target06Config; /* 1C - Channel 0 Target 6 config */ + UCHAR Target07Config; /* 1D - Channel 0 Target 7 config */ + UCHAR Target08Config; /* 1E - Channel 0 Target 8 config */ + UCHAR Target09Config; /* 1F - Channel 0 Target 9 config */ + UCHAR Target0AConfig; /* 20 - Channel 0 Target A config */ + UCHAR Target0BConfig; /* 21 - Channel 0 Target B config */ + UCHAR Target0CConfig; /* 22 - Channel 0 Target C config */ + UCHAR Target0DConfig; /* 23 - Channel 0 Target D config */ + UCHAR Target0EConfig; /* 24 - Channel 0 Target E config */ + UCHAR Target0FConfig; /* 25 - Channel 0 Target F config */ + + UCHAR SCSI1Id; /* 26 - Channel 1 SCSI ID */ + UCHAR SCSI1Config; /* 27 - Channel 1 SCSI configuration */ + UCHAR SCSI1MaxTags; /* 28 - Channel 1 Maximum tags */ + UCHAR SCSI1ResetTime; /* 29 - Channel 1 Reset recovering time */ + UCHAR ReservedforChannel1[2]; /* 2A - Reserved */ + + /* ----SCSI target Structure ---- */ + /* from "CTRL-I SCSI device SetUp menu " */ + UCHAR Target10Config; /* 2C - Channel 1 Target 0 config */ + UCHAR Target11Config; /* 2D - Channel 1 Target 1 config */ + UCHAR Target12Config; /* 2E - Channel 1 Target 2 config */ + UCHAR Target13Config; /* 2F - Channel 1 Target 3 config */ + UCHAR Target14Config; /* 30 - Channel 1 Target 4 config */ + UCHAR Target15Config; /* 31 - Channel 1 Target 5 config */ + UCHAR Target16Config; /* 32 - Channel 1 Target 6 config */ + UCHAR Target17Config; /* 33 - Channel 1 Target 7 config */ + UCHAR Target18Config; /* 34 - Channel 1 Target 8 config */ + UCHAR Target19Config; /* 35 - Channel 1 Target 9 config */ + UCHAR Target1AConfig; /* 36 - Channel 1 Target A config */ + UCHAR Target1BConfig; /* 37 - Channel 1 Target B config */ + UCHAR Target1CConfig; /* 38 - Channel 1 Target C config */ + UCHAR Target1DConfig; /* 39 - Channel 1 Target D config */ + UCHAR Target1EConfig; /* 3A - Channel 1 Target E config */ + UCHAR Target1FConfig; /* 3B - Channel 1 Target F config */ + UCHAR reserved[3]; /* 3C - Reserved */ + /* ---------- CheckSum ---------- */ + UCHAR CheckSum; /* 3F - Checksum of NVRam */ +} NVRAM, *PNVRAM; + +/* Bios Configuration for nvram->BIOSConfig1 */ +#define NBC_BIOSENABLE 0x01 /* BIOS enable */ +#define NBC_CDROM 0x02 /* Support bootable CDROM */ +#define NBC_REMOVABLE 0x04 /* Support removable drive */ + +/* Bios Configuration for nvram->BIOSConfig2 */ +#define NBB_TARGET_MASK 0x0F /* Boot SCSI target ID number */ +#define NBB_CHANL_MASK 0xF0 /* Boot SCSI channel number */ + +/* Bit definition for nvram->SCSIConfig */ +#define NCC_BUSRESET 0x01 /* Reset SCSI bus at power up */ +#define NCC_PARITYCHK 0x02 /* SCSI parity enable */ +#define NCC_LVDS 0x10 /* Enable LVDS */ +#define NCC_ACTTERM1 0x20 /* Enable active terminator 1 */ +#define NCC_ACTTERM2 0x40 /* Enable active terminator 2 */ +#define NCC_AUTOTERM 0x80 /* Enable auto termination */ + +/* Bit definition for nvram->TargetxConfig */ +#define NTC_PERIOD 0x07 /* Maximum Sync. Speed */ +#define NTC_1GIGA 0x08 /* 255 head / 63 sectors (64/32)*/ +#define NTC_NO_SYNC 0x10 /* NO SYNC. NEGO */ +#define NTC_NO_WIDESYNC 0x20 /* NO WIDE SYNC. NEGO */ +#define NTC_DISC_ENABLE 0x40 /* Enable SCSI disconnect */ +#define NTC_SPINUP 0x80 /* Start disk drive */ + +/* Default NVRam values */ +#define NBC_DEFAULT (NBC_ENABLE) +#define NCC_DEFAULT (NCC_BUSRESET | NCC_AUTOTERM | NCC_PARITYCHK) +#define NCC_MAX_TAGS 0x20 /* Maximum tags per target */ +#define NCC_RESET_TIME 0x0A /* SCSI RESET recovering time */ +#define NTC_DEFAULT (NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE) + +#define DISC_ALLOW 0xC0 +#define DISC_NOT_ALLOW 0x80 + + +/*------------------------------------------------------------------*/ +/* PCI */ +/*------------------------------------------------------------------*/ +#define PCI_FUNCTION_ID 0xB1 +#define PCI_BIOS_PRESENT 0x01 +#define FIND_PCI_DEVICE 0x02 +#define FIND_PCI_CLASS_CODE 0x03 +#define GENERATE_SPECIAL_CYCLE 0x06 +#define READ_CONFIG_BYTE 0x08 +#define READ_CONFIG_WORD 0x09 +#define READ_CONFIG_DWORD 0x0A +#define WRITE_CONFIG_BYTE 0x0B +#define WRITE_CONFIG_WORD 0x0C +#define WRITE_CONFIG_DWORD 0x0D + +#define SUCCESSFUL 0x00 +#define FUNC_NOT_SUPPORTED 0x81 +#define BAD_VENDOR_ID 0x83 /* Bad vendor ID */ +#define DEVICE_NOT_FOUND 0x86 /* PCI device not found */ +#define BAD_REGISTER_NUMBER 0x87 + +#define MAX_PCI_DEVICES 21 /* Maximum devices supportted */ + + +typedef struct _BIOS32_ENTRY_STRUCTURE { + DWORD Signatures; /* Should be "_32_" */ + DWORD BIOS32Entry; /* 32-bit physical address */ + BYTE Revision; /* Revision level, should be 0 */ + BYTE Length; /* Multiply of 16, should be 1 */ + BYTE CheckSum; /* Checksum of whole structure */ + BYTE Reserved[5]; /* Reserved */ +} BIOS32_ENTRY_STRUCTURE, *PBIOS32_ENTRY_STRUCTURE; + +typedef struct + { + union + { + unsigned int eax; + struct + { + unsigned short ax; + } word; + struct + { + unsigned char al; + unsigned char ah; + } byte; + } eax; + union + { + unsigned int ebx; + struct + { + unsigned short bx; + } word; + struct + { + unsigned char bl; + unsigned char bh; + } byte; + } ebx; + union + { + unsigned int ecx; + struct + { + unsigned short cx; + } word; + struct + { + unsigned char cl; + unsigned char ch; + } byte; + } ecx; + union + { + unsigned int edx; + struct + { + unsigned short dx; + } word; + struct + { + unsigned char dl; + unsigned char dh; + } byte; + } edx; + union + { + unsigned int edi; + struct + { + unsigned short di; + } word; + } edi; + union + { + unsigned int esi; + struct + { + unsigned short si; + } word; + } esi; + } REGS; + +typedef union /* Union define for mechanism 1 */ + { + struct + { + unsigned char RegNum; + unsigned char FcnNum:3; + unsigned char DeviceNum:5; + unsigned char BusNum; + unsigned char Reserved:7; + unsigned char Enable:1; + } sConfigAdr; + unsigned long lConfigAdr; + } CONFIG_ADR; + +typedef union /* Union define for mechanism 2 */ + { + struct + { + unsigned char RegNum; + unsigned char DeviceNum; + unsigned short Reserved; + } sHostAdr; + unsigned long lHostAdr; + } HOST_ADR; + +typedef struct _HCSinfo + { + ULONG base; + UCHAR vec; + UCHAR bios; /* High byte of BIOS address */ + USHORT BaseAndBios; /* high byte: pHcsInfo->bios,low byte:pHcsInfo->base */ + } HCSINFO ; + +/********************************************************/ +/* Configuration Register Set */ +/********************************************************/ +#define ORC_PVID 0x00 /* Vendor ID */ +#define ORC_VENDOR_ID 0x1101 /* Orchid vendor ID */ +#define ORC_PDID 0x02 /* Device ID */ +#define ORC_DEVICE_ID 0x1060 /* Orchid device ID */ +#define ORC_COMMAND 0x04 /* Command */ +#define BUSMS 0x04 /* BUS MASTER Enable */ +#define IOSPA 0x01 /* IO Space Enable */ +#define ORC_STATUS 0x06 /* Status register */ +#define ORC_REVISION 0x08 /* Revision number */ +#define ORC_BASE 0x10 /* Base address */ +#define ORC_BIOS 0x30 /* Expansion ROM base address */ +#define ORC_INT_NUM 0x3C /* Interrupt line */ +#define ORC_INT_PIN 0x3D /* Interrupt pin */ + + +/********************************************************/ +/* Host Command Set */ +/********************************************************/ +#define ORC_CMD_NOP 0x00 /* Host command - NOP */ +#define ORC_CMD_VERSION 0x01 /* Host command - Get F/W version */ +#define ORC_CMD_ECHO 0x02 /* Host command - ECHO */ +#define ORC_CMD_SET_NVM 0x03 /* Host command - Set NVRAM */ +#define ORC_CMD_GET_NVM 0x04 /* Host command - Get NVRAM */ +#define ORC_CMD_GET_BUS_STATUS 0x05 /* Host command - Get SCSI bus status */ +#define ORC_CMD_ABORT_SCB 0x06 /* Host command - Abort SCB */ +#define ORC_CMD_ISSUE_SCB 0x07 /* Host command - Issue SCB */ + +/********************************************************/ +/* Register Set */ +/********************************************************/ +#define ORC_GINTS 0xA0 /* Global Interrupt Status */ +#define QINT 0x04 /* Reply Queue Interrupt */ +#define ORC_GIMSK 0xA1 /* Global Interrupt MASK */ +#define MQINT 0x04 /* Mask Reply Queue Interrupt */ +#define ORC_GCFG 0xA2 /* Global Config */ +#define EEPRG 0x01 /* Enable EEPROM programming */ +#define ORC_GSTAT 0xA3 /* Global status */ +#define WIDEBUS 0x20 /* Wide SCSI Devices connected */ +#define ORC_HDATA 0xA4 /* Host Data */ +#define ORC_HCTRL 0xA5 /* Host Control */ +#define SCSIRST 0x80 /* SCSI bus reset */ +#define HDO 0x40 /* Host data out */ +#define HOSTSTOP 0x02 /* Host stop RISC engine */ +#define DEVRST 0x01 /* Device reset */ +#define ORC_HSTUS 0xA6 /* Host Status */ +#define HDI 0x02 /* Host data in */ +#define RREADY 0x01 /* RISC engine is ready to receive */ +#define ORC_NVRAM 0xA7 /* Nvram port address */ +#define SE2CS 0x008 +#define SE2CLK 0x004 +#define SE2DO 0x002 +#define SE2DI 0x001 +#define ORC_PQUEUE 0xA8 /* Posting queue FIFO */ +#define ORC_RQUEUE 0xAA /* Reply queue FIFO */ +#define ORC_RQUEUECNT 0xAB /* Reply queue FIFO count */ + +#define ORC_FWBASEADR 0xAC /* Firmware base address */ + +#define ORC_EBIOSADR0 0xB0 /* External BIOS address */ +#define ORC_EBIOSADR1 0xB1 /* External BIOS address */ +#define ORC_EBIOSADR2 0xB2 /* External BIOS address */ +#define ORC_EBIOSDATA 0xB3 /* External BIOS data */ + +#define ORC_SCBSIZE 0xB7 /* SCB size register */ +#define ORC_SCBBASE0 0xB8 /* SCB base address 0 */ +#define ORC_SCBBASE1 0xBC /* SCB base address 1 */ + +#define ORC_RISCCTL 0xE0 /* RISC Control */ +#define PRGMRST 0x02 /* Program Counter Reset */ +#define DOWNLOAD 0x01 /* Download Firmware */ + +#define ORC_RISCRAM 0xEC + +/*********************************************************************** + Scatter-Gather Element Structure +************************************************************************/ +typedef struct SG_Struc { + ULONG SG_Ptr; /* Data Pointer */ + ULONG SG_Len; /* Data Length */ +} A100_SG; + + + +/************************************************************************ + SCSI Control Block +*************************************************************************/ + +typedef struct A100_Scsi_Ctrl_Blk +{ /* Scsi_Ctrl_Blk */ + UBYTE SCB_Opcode; /*00 SCB command code&residual */ + UBYTE SCB_Flags; /*01 SCB Flags */ + UBYTE SCB_Target; /*02 Target Id */ + UBYTE SCB_Lun; /*03 Lun */ + ULONG SCB_Reserved0; /*04 Reserved for ORCHID must 0 */ + ULONG SCB_XferLen; /*08 Data Transfer Length */ + ULONG SCB_Reserved1; /*0C Reserved for ORCHID must 0 */ + ULONG SCB_SGLen; /*10 SG list # * 8 */ + ULONG SCB_SGPAddr; /*14 SG List Buf physical Addr */ + ULONG SCB_SGPAddrHigh; /*18 SG Buffer high physical Addr */ + UBYTE SCB_HaStat; /*1C Host Status */ + UBYTE SCB_TaStat; /*1D Target Status */ + UBYTE SCB_Status; /*1E SCB status */ + UBYTE SCB_Link; /*1F Link pointer, default 0xFF */ + + UBYTE SCB_SenseLen; /*20 Sense Allocation Length */ + UBYTE SCB_CDBLen; /*21 CDB Length */ + UBYTE SCB_Ident; /*22 Identify */ + UBYTE SCB_TagMsg; /*23 Tag Message */ + UBYTE SCB_CDB[14]; /*24 SCSI CDBs */ + + + UBYTE SCB_ScbIdx; /*32 Index for this ORCSCB */ + UBYTE SCB_FreeFlag; /*33 Free flag for this ORCSCB */ + ULONG SCB_SensePAddr; /*34 Sense Buffer physical Addr */ + + + ULONG SCB_ccb; + struct A100_Scsi_Ctrl_Blk *SCB_NextScb; + +} A100_SCB; + +/* Opcodes of ORCSCB_Opcode */ +#define ExecSCSI 0x00 /* SCSI initiator command with residual */ +#define BusDevRst 0x01 /* SCSI Bus Device Reset */ + +/* Status of ORCSCB_Status */ +#define SCB_COMPLETE 0x00 /* SCB request completed */ +#define SCB_POST 0x01 /* SCB is posted by the HOST */ + +/* Bit Definition for ORCSCB_Flags */ +#define SCF_NO_DCHK 0x00 /* Direction determined by SCSI */ +#define SCF_DIN 0x01 /* From Target to Initiator */ +#define SCF_DOUT 0x10 /* From Initiator to Target */ +#define SCF_NO_XF 0x11 /* No data transfer */ +#define SCF_POLL 0x40 /* No interrupt */ + + + +/* Error Codes for ORCSCB_HaStat */ +#define HOST_OK 0x00 +#define HOST_SEL_TOUT 0x11 +#define HOST_DO_DU 0x12 +#define HOST_BUS_FREE 0x13 +#define HOST_BAD_PHAS 0x14 +#define HOST_INV_CMD 0x16 +#define HOST_ABORTED 0x1A +#define HOST_SCSI_RST 0x1B +#define HOST_DEV_RST 0x1C + + +/* Error Codes for ORCSCB_TaStat */ +#define TARGET_GOOD 0x00 +#define TARGET_CHKCOND 0x02 +#define TARGET_BUSY 0x08 +#define TARGET_QFULL 0x28 + + +/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */ +#define MSG_STAG 0x20 +#define MSG_HTAG 0x21 +#define MSG_OTAG 0x22 + +#define MSG_IGNOREWIDE 0x23 + +#define MSG_IDENT 0x80 +#define MSG_DISC 0x40 /* Disconnect allowed */ + +/************************************************************************ + Host Adapter Control Structure +*************************************************************************/ + +typedef struct A100_Ha_Ctrl_Struc +{ /* Ha_Ctrl_Struc */ + ULONG HCS_Base; + UBYTE HCS_MaxTar; + UBYTE HCS_HaId; + UBYTE HCS_Intr; + UBYTE HCS_Unit; + UBYTE HCS_Flags; + UBYTE HCS_SCSI_ID; + + bus_dma_tag_t parent_dmat; + bus_dma_tag_t buffer_dmat; + bus_dmamap_t dmamap; + struct cam_sim *sim; + struct cam_path *path; + + A100_SCB *HCS_FirstAvail; + A100_SCB *HCS_LastAvail; + A100_SCB *HCS_FirstPend; + A100_SCB *HCS_LastPend; + + + + A100_SCB *pScbArray; + ULONG pPhyScbArray; + + A100_SG *SGList; + ULONG pPhySG; + + UBYTE TargetFlag[16]; + UBYTE MaximumTags[16]; + UBYTE ActiveTags[16]; + + +} A100_HCS; + + +/* Bit Definition for TargetFlag */ + +#define TCF_EN_TAG 0x10 +#define TCF_BUSY 0x20 + + +/* INI1060 specific port driver device object extension. */ +typedef struct A100_Adpt_Struc{ + UWORD ADPT_BIOS; + UWORD ADPT_BASE; + UBYTE ADPT_Bus; + UBYTE ADPT_Device; + UBYTE ADPT_INTR; +}INI_ADPT_STRUCT; + + + + diff -urN -urN src/sys/dev/ihaempty/i91u.c src/sys/dev/iha/i91u.c --- src/sys/dev/ihaempty/i91u.c Thu Jan 1 02:00:00 1970 +++ src/sys/dev/iha/i91u.c Fri Jun 22 16:28:55 2001 @@ -0,0 +1,862 @@ +/*- + * Copyright (c) 1997-99 Initio Corporation + * All rights reserved. + * + * 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. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY INITIO CORPORATION ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL INITIO CORPORATION BE LIABLE FOR ANY DIRECT,INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: i91u.c,v 1.82.2.9 1998/01/08 12:04:00 se Exp $ + */ + +#include + +#ifdef _KERNEL +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* _KERNEL */ + +#include +#include + +#include +/* #include */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +/* #include */ + +#define INT32 int32 +#define U_INT32 u_int32 + +#ifdef __alpha__ +/* XXX */ +#undef vtophys +#define vtophys(va) (pmap_kextract(((vm_offset_t) (va))) \ + + 1*1024*1024*1024) +#endif + +#define OutB(val, port) outb(port, val) +#define OutW(val, port) outw(port, val) +#define OutL(val, port) outl(port, val) + +#define PCI_DEVICE_ID_INIC940 0x94001101ul +#define PCI_DEVICE_ID_INIC941 0x94011101ul +#define PCI_DEVICE_ID_INIC950 0x95001101ul +#define PCI_BASEADDR0 0x10 + + +#ifdef _KERNEL + +/* static void i91u_Interrupt (I91U_HCS *pHcs); */ + + +static const char* i91u_probe( pcici_t tag, pcidi_t type); +static void i91u_attach( pcici_t tag, int unit); + +static void i91u_timeout( void *arg1); + + + +static void i91u_action(struct cam_sim *sim, union ccb *ccb); +static void i91u_poll(struct cam_sim *sim); + + + +#endif /* _KERNEL */ + + + + +static u_long i91u_count; + +struct pci_device i91u_device = { + "iha", + i91u_probe, + i91u_attach, + &i91u_count, + NULL +}; + +#ifdef COMPAT_PCI_DRIVER +COMPAT_PCI_DRIVER(iha, i91u_device); +#else +DATA_SET (pcidevice_set, i91u_device); +#endif /* COMPAT_PCI_DRIVER */ + + + + + + +/* TTT #include */ +#include +#include + + + + + +/* + * We have a scb which has been processed by the + * adaptor, now we look to see how the operation + * went. + */ +static void +i91u_done(I91U_HCS *pHcs, I91U_SCB *pScb) +{ + union ccb *ccb = (union ccb *)pScb->SCB_ccb; + struct ccb_scsiio *csio; + + pScb->SCB_ccb = NULL; +#if 0 +printf("done:hs=%x ts=%x\n",pScb->SCB_HaStat ,pScb->SCB_TaStat ); +tul_do_pause(1000); +#endif + + if((ULONG)ccb == 0) { + printf("free scb while ccb=0 in i91u_done \n"); + tul_release_scb(pHcs, pScb); + return; + } + + untimeout(i91u_timeout, (caddr_t) pScb,ccb->ccb_h.timeout_ch); +#if 0 + if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { + bus_dmasync_op_t op; + + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) + op = BUS_DMASYNC_POSTREAD; + else + op = BUS_DMASYNC_POSTWRITE; + bus_dmamap_sync(pHcs->dmat, pScb->SCB_dmamap, op); + bus_dmamap_unload(pHcs->buffer_dmat, pScb->SCB_dmamap); + } +#endif + + csio = &ccb->csio; + /* + ** Check the status. + */ + if ( (pScb->SCB_HaStat == HOST_OK) + && (pScb->SCB_TaStat == TARGET_GOOD)) { + + ccb->ccb_h.status = CAM_REQ_CMP; + csio->scsi_status = SCSI_STATUS_OK; + + } else if ( (pScb->SCB_HaStat == HOST_OK) + && (pScb->SCB_TaStat== TARGET_CHKCOND )) { + + /* + ** Check condition code + */ + ccb->ccb_h.status |= CAM_AUTOSNS_VALID; + csio->scsi_status = SCSI_STATUS_CHECK_COND; + + } else if ((pScb->SCB_HaStat== HOST_OK) + && (pScb->SCB_TaStat== TARGET_BUSY)) { + /* + ** Target is busy. + */ + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + csio->scsi_status = SCSI_STATUS_BUSY; + + } else if ((pScb->SCB_HaStat== HOST_OK) + && (pScb->SCB_TaStat== TARGET_QFULL)) { + + /* + ** Target is queue full. + */ + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + csio->scsi_status = SCSI_STATUS_QUEUE_FULL; + + + } else if (pScb->SCB_HaStat== HOST_SEL_TOUT ) { + + /* + ** Device failed selection + */ + ccb->ccb_h.status = CAM_SEL_TIMEOUT; + + } else if (pScb->SCB_HaStat == HOST_DO_DU) { + + /* + ** Data overrun(underrun) + */ + ccb->ccb_h.status = CAM_DATA_RUN_ERR; + + } else if (pScb->SCB_HaStat == HOST_BUS_FREE) { + + /* + ** Bus free + */ + ccb->ccb_h.status = CAM_UNEXP_BUSFREE; + + } else if (pScb->SCB_HaStat == HOST_BAD_PHAS) { + + /* + ** Bad phase + */ + ccb->ccb_h.status = CAM_SEQUENCE_FAIL; + + } else if (pScb->SCB_HaStat == HOST_INV_CMD) { + + /* + ** Invalid command + */ + ccb->ccb_h.status = CAM_REQ_INVALID; + + } else if (pScb->SCB_HaStat == HOST_SCSI_RST) { + + /* + ** SCSI bus reset + */ + ccb->ccb_h.status = CAM_SCSI_BUS_RESET; + + } else if (pScb->SCB_HaStat == HOST_DEV_RST) { + + /* + ** SCSI device reset + */ + ccb->ccb_h.status = CAM_SCSI_BUS_RESET; /* XXX right? */ + + } else { /* Other protocol messes */ + ccb->ccb_h.status = CAM_CMD_TIMEOUT; + } + + + tul_release_scb(pHcs, pScb); + xpt_done(ccb); +} + +static void +i91u_timeout(void *arg1) +{ + + I91U_SCB *pScb = (I91U_SCB*) arg1; + I91U_HCS *pHcs; + union ccb *ccb; + int s; + + + ccb = (union ccb *)pScb->SCB_ccb; + if (ccb == NULL) + return; + + pHcs = (I91U_HCS *)xpt_path_sim(ccb->ccb_h.path)->softc; + + + s = splcam(); + if (tul_abort_ccb(pHcs, (ULONG) ccb)) { + printf("iha: timed out\n"); + + ccb->ccb_h.status |= CAM_REQ_ABORTED; + xpt_done(ccb); + } + splx(s); +} + +static void i91u_exec_scb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error) +{ + I91U_SCB * pScb; + union ccb *ccb; + I91U_HCS *pHcs; + I91U_SG *sg; + struct ccb_scsiio *csio; + int s; + + pScb = (I91U_SCB *)arg; + ccb = (union ccb *)pScb->SCB_ccb; + csio = &ccb->csio; + pHcs = (I91U_HCS *)xpt_path_sim(ccb->ccb_h.path)->softc; + + if(pScb->SCB_CDB[0] == 0x3) { + + /* disable SCSI DISCONNECT if it is "REQUEST SENSE" command */ + printf("--REQUEST SENSE--"); + pScb->SCB_Ident &= 0xBF; + + } + + + if (error != 0) { + if (error != EFBIG) + printf("iha: Unexepected error 0x%x returned from bus_dmamap_load\n", error); + if (ccb->ccb_h.status == CAM_REQ_INPROG) { + xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); + ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN; + } + tul_release_scb(pHcs, pScb); + xpt_done(ccb); + return; + } + + + + + +/*** printf("--exec(seg=%d,xferl=%d,cdl=%d,tag=%02x)--",nseg,csio->dxfer_len,pScb->SCB_CDBLen,pScb->SCB_TagMsg);***/ + + pScb->SCB_BufLen = csio->dxfer_len; + + if (nseg == 1) { + pScb->SCB_BufPtr = (ULONG)dm_segs->ds_addr; + } + else if (nseg != 0) { + bus_dma_segment_t *end_seg; + + sg = pScb->SCB_SGList; + end_seg = dm_segs + nseg; + + while (dm_segs < end_seg) { + sg->SG_Len = dm_segs->ds_len; + sg->SG_Ptr = dm_segs->ds_addr; + sg++; + dm_segs++; + } + + pScb->SCB_Flags |= SCF_SG; + pScb->SCB_BufPtr = (ULONG)pScb->SCB_SGPAddr; + pScb->SCB_SGLen = nseg; + +#if 0 + if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) + op = BUS_DMASYNC_PREREAD; + else + op = BUS_DMASYNC_PREWRITE; + + bus_dmamap_sync(pHcs->buffer_dmat, pScb->SCB_dmamap, op); +#endif + + } + + s = splcam(); + ccb->ccb_h.timeout_ch = timeout(i91u_timeout, (caddr_t)pScb, (ccb->ccb_h.timeout * hz)/1000); + + tul_exec_scb(pHcs, pScb); + splx(s); +} + +/*========================================================== +** +** +** Start execution of a SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +void i91u_action(struct cam_sim *sim, union ccb *ccb) +{ + I91U_SCB *pScb; + I91U_HCS *pHcs; + int flags; +/* struct scsi_inquiry_data *inq_buf; */ + + pHcs = (I91U_HCS *) cam_sim_softc(sim); + + switch (ccb->ccb_h.func_code) { + /* Common cases first */ + case XPT_SCSI_IO: /* Execute the requested I/O operation */ + case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ + { + struct ccb_scsiio *csio = &ccb->csio; + + flags = ccb->ccb_h.flags; + + + /* + * Last time we need to check if this CCB needs to + * be aborted. + */ + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { + xpt_done(ccb); + return; + } + ccb->ccb_h.status |= CAM_SIM_QUEUED; + + /* + * get an scb to use. If the transfer + * is from a buf (possibly from interrupt time) + * then we can't allow it to sleep + */ + if ((pScb = tul_alloc_scb(pHcs)) == NULL) { +/*** printf("--!pScb--");***/ + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + return; + } + + pScb->SCB_ccb =(ULONG)ccb; + + pScb->SCB_Target = ccb->ccb_h.target_id; + pScb->SCB_Lun = ccb->ccb_h.target_lun; + pScb->SCB_Flags = SCF_POST; + /* After SCSI done, call post routine*/ + pScb->SCB_Post = (void *)i91u_done; + + *((UWORD *)&pScb->SCB_HaStat) = 0; + + if (ccb->ccb_h.func_code == XPT_RESET_DEV) { + pScb->SCB_Opcode = BusDevRst; + tul_exec_scb(pHcs, pScb); + } + else { + pScb->SCB_Opcode = ExecSCSI; + + if((flags & CAM_DIR_MASK) == CAM_DIR_NONE) + pScb->SCB_Flags |= SCF_NO_XF; + else if(flags & CAM_DIR_IN) + pScb->SCB_Flags |= SCF_DIN; + else if(flags & CAM_DIR_OUT) + pScb->SCB_Flags |= SCF_DOUT; + + pScb->SCB_Ident = pScb->SCB_Lun | DISC_ALLOW; + pScb->SCB_CDBLen = csio->cdb_len; + if (pScb->SCB_CDBLen > 12) { + ccb->ccb_h.status = CAM_REQ_INVALID; + tul_release_scb(pHcs, pScb); + xpt_done(ccb); + } + + if ((flags & CAM_CDB_POINTER) != 0) { + if ((flags & CAM_CDB_PHYS) == 0) { + bcopy(csio->cdb_io.cdb_ptr, pScb->SCB_CDB, pScb->SCB_CDBLen); + } else { + ccb->ccb_h.status = CAM_REQ_INVALID; + tul_release_scb(pHcs, pScb); + xpt_done(ccb); + return; + } + } else { + bcopy(csio->cdb_io.cdb_bytes, pScb->SCB_CDB, pScb->SCB_CDBLen); + } + + if (!(ccb->ccb_h.flags & CAM_DIS_AUTOSENSE)) { + pScb->SCB_Flags |= SCF_SENSE; + pScb->SCB_SenseLen = csio->sense_len; + pScb->SCB_SensePtr = vtophys(&csio->sense_data); + } + + if((flags & CAM_TAG_ACTION_VALID) != 0 && (csio->tag_action != CAM_TAG_ACTION_NONE)){ + pScb->SCB_TagMsg = csio->tag_action; + } + else{ + pScb->SCB_TagMsg = 0; + } + + + + /* Only use S/G if there is a transfer */ + if ((flags & CAM_DIR_MASK) != CAM_DIR_NONE) { + + if ((flags & CAM_SCATTER_VALID) == 0) { + /* + * We've been given a pointer + * to a single buffer. + */ + if ((flags & CAM_DATA_PHYS)==0) { + int s; + int error; + +/*** printf("--CAM_DATA_PHYS=0--");***/ + s = splsoftvm(); + error = bus_dmamap_load( + pHcs->dmat, +#if 0 + pScb->SCB_dmamap, +#else + pHcs->dmamap, +#endif + csio->data_ptr, + csio->dxfer_len, + i91u_exec_scb, + pScb, + /*flags*/0); + if (error == EINPROGRESS) { + /* + * So as to maintain + * ordering, freeze the + * controller queue + * until our mapping is + * returned. + */ + xpt_freeze_simq(pHcs->sim, + 1); + csio->ccb_h.status |= + CAM_RELEASE_SIMQ; + } + splx(s); + } else { + struct bus_dma_segment seg; + + /* Pointer to physical buffer */ + seg.ds_addr = + (bus_addr_t)csio->data_ptr; + seg.ds_len = csio->dxfer_len; + i91u_exec_scb(pScb,&seg,1,0); + } + } else { + struct bus_dma_segment *segs; + + if ((flags & CAM_DATA_PHYS) != 0) + panic("i91u_action - Physical " + "segment pointers " + "unsupported"); + + if ((flags&CAM_SG_LIST_PHYS)==0) + panic("i91u_action - Virtual " + "segment addresses " + "unsupported"); + + segs = (struct bus_dma_segment *) + csio->data_ptr; + i91u_exec_scb(pScb,segs,csio->sglist_cnt,0); + + } + } else { + int s; + + s = splcam(); + ccb->ccb_h.timeout_ch = timeout(i91u_timeout, (caddr_t)pScb, (ccb->ccb_h.timeout * hz)/1000); + + tul_exec_scb(pHcs, pScb); + splx(s); + } + } + break; + } + + case XPT_EN_LUN: /* Enable LUN as a target */ + case XPT_TARGET_IO: /* Execute target I/O request */ + case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ + case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ + case XPT_ABORT: /* Abort the specified CCB */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + + case XPT_SET_TRAN_SETTINGS: + { + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + + case XPT_GET_TRAN_SETTINGS: + /* Get default/user set transfer settings for the target */ + { + + struct ccb_trans_settings *cts; + + cts = &ccb->cts; + + cts->flags = 0; + cts->flags |= CCB_TRANS_DISC_ENB; + + cts->flags |= CCB_TRANS_TAG_ENB; + + cts->bus_width = (pHcs->HCS_MaxTar == 16) ? + MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT; + + cts->sync_period = 12; + cts->sync_offset = 15; + + cts->valid = CCB_TRANS_SYNC_RATE_VALID + | CCB_TRANS_SYNC_OFFSET_VALID + | CCB_TRANS_BUS_WIDTH_VALID + | CCB_TRANS_DISC_VALID + | CCB_TRANS_TQ_VALID; + + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + + case XPT_CALC_GEOMETRY: + { + struct ccb_calc_geometry *ccg; + u_int32_t size_mb; + u_int32_t secs_per_cylinder; + + ccg = &ccb->ccg; + size_mb = ccg->volume_size + / ((1024L * 1024L) / ccg->block_size); + + if (size_mb >= 1024 ) { + ccg->heads = 255; + ccg->secs_per_track = 63; + } else { + ccg->heads = 64; + ccg->secs_per_track = 32; + } + secs_per_cylinder = ccg->heads * ccg->secs_per_track; + ccg->cylinders = ccg->volume_size / secs_per_cylinder; + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + + case XPT_RESET_BUS: /* Reset the specified SCSI bus */ + { + tul_reset_scsi(pHcs); /* Do Hardware Reset & */ + ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + case XPT_TERM_IO: /* Terminate the I/O process */ + /* XXX Implement */ + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + case XPT_PATH_INQ: /* Path routing inquiry */ + { + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; /* XXX??? */ + cpi->hba_inquiry = PI_SDTR_ABLE; + if (ccb->csio.tag_action != 0) + cpi->hba_inquiry |= PI_TAG_ABLE; + if(pHcs->HCS_MaxTar == 16) + cpi->hba_inquiry |= PI_WIDE_16; + + cpi->target_sprt = 0; + cpi->hba_misc = 0; + cpi->hba_eng_cnt = 0; + cpi->max_target = pHcs->HCS_MaxTar-1; + cpi->max_lun = 7; + cpi->initiator_id = pHcs->HCS_SCSI_ID; + cpi->bus_id = cam_sim_bus(sim); + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(cpi->hba_vid, "Initio", HBA_IDLEN); + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + cpi->unit_number = cam_sim_unit(sim); + cpi->ccb_h.status = CAM_REQ_CMP; + xpt_done(ccb); + break; + } + default: + ccb->ccb_h.status = CAM_REQ_INVALID; + xpt_done(ccb); + break; + + } +} + +void i91u_poll(struct cam_sim *sim) +{ + I91U_HCS *pHcs; + + pHcs = (I91U_HCS *) cam_sim_softc(sim); + + tul_isr(pHcs); +} + + +void +i91u_attach (pcici_t config_id, int unit) +{ + + u_int16_t io_port; + u_int32_t id; + + I91U_HCS *pHcs = 0; + I91U_SCB *pScb; + int error; + int s; + int openings; + struct cam_devq *devq; + union ccb *work_ccb; + + if( unit >= MAX_SUPPORTED_ADAPTERS) + return; + +#if 0 + if( pHCS[unit] ) + return; +#endif + + io_port = 0; + if (pci_map_port(config_id, PCI_BASEADDR0, &io_port) == 0) + return; + + + pHcs = (I91U_HCS *) malloc (sizeof (I91U_HCS), M_DEVBUF, M_NOWAIT); + if( !pHcs ) { + printf("iha%d: cannot allocate HCS !\n", unit); + return; + } + + bzero (pHcs, sizeof (I91U_HCS)); + pHcs->HCS_Base = io_port; + pHcs->HCS_Unit = unit; + +/* XXX commented out. This line causes + XXX "resource_list_alloc: resource entry is busy" + if (!(pci_map_int(config_id, (void *)tul_isr, (void *)pHcs, &bio_imask))) { + free(pHcs, M_DEVBUF); + return; + } +*/ + + + switch ((id = pci_conf_read(config_id, PCI_ID_REG))) { + + case PCI_DEVICE_ID_INIC940: + case PCI_DEVICE_ID_INIC941: + case PCI_DEVICE_ID_INIC950: + break; + + default: + free(pHcs, M_DEVBUF); + return; + } + + /* Allocate a dmatag for our transfer DMA maps */ + /* DMA tag for mapping buffers into device visible space. */ + /* XXX Should be a child of the PCI bus dma tag */ + error = bus_dma_tag_create(/*parent*/ NULL, + /*alignment*/ 0, + /*boundary*/ 0, + /*lowaddr*/ (0xFFFFFFFFL), + /*highaddr*/ BUS_SPACE_MAXADDR, + /*filter*/ NULL, + /*filterarg*/ NULL, + /*maxsize*/ MAXBSIZE, + /*nsegments*/ I91U_SG_ENTRY , + /*maxsegsz*/ BUS_SPACE_MAXSIZE_24BIT, + /*flags*/ BUS_DMA_ALLOCNOW, + &pHcs->dmat); + + if (error != 0) { + printf("iha: Could not allocate DMA tag - error %d\n", + error); + free(pHcs, M_DEVBUF); + return; + } + + pScb = (I91U_SCB *) malloc (sizeof (I91U_SCB)*MAX_SCB, M_DEVBUF, M_NOWAIT); + if( !pScb ) { + printf("iha%d: cannot allocate SCB !\n", unit); + bus_dma_tag_destroy(pHcs->dmat); + free(pHcs, M_DEVBUF); + return; + } + bzero (pScb, sizeof (I91U_HCS)*MAX_SCB); + + init_tulip(pHcs, pScb, MAX_SCB); + + if (!(pci_map_int(config_id, (void *)tul_isr, (void *)pHcs, &cam_imask))) { + printf("iha%d: Can't pci_map_int \n", unit); + bus_dma_tag_destroy(pHcs->dmat); + free(pScb, M_DEVBUF); + free(pHcs, M_DEVBUF); + return; + } + + + /* + ** Create the device queue. We only allow MAX_START-1 concurrent + ** transactions so we can be sure to have one element free in our + ** start queue to reset to the idle loop. + */ + s = splcam(); + openings = MAX_SCB-1; + devq = cam_simq_alloc(openings); + if (devq == NULL){ + splx(s); + return; + } + + /* + ** Now tell the generic SCSI layer + ** about our bus. + */ + pHcs->sim = cam_sim_alloc(i91u_action, i91u_poll, "iha", pHcs, + pHcs->HCS_Unit , + 1, openings, devq); + if (pHcs->sim == NULL) { + cam_simq_free(devq); + splx(s); + return; + } + + if (xpt_bus_register(pHcs->sim, 0) != CAM_SUCCESS) { + cam_sim_free(pHcs->sim, TRUE); + splx(s); + return; + } + +#ifdef __alpha__ + alpha_register_pci_scsi(config_id->bus, config_id->slot, pHcs->sim); +#endif + + work_ccb = xpt_alloc_ccb(); + if (xpt_create_path(&pHcs->path, NULL, + cam_sim_path(pHcs->sim), CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_bus_deregister(cam_sim_path(pHcs->sim)); + cam_sim_free(pHcs->sim, TRUE); + xpt_free_ccb(work_ccb); + splx(s); + return; + } + + splx(s); + return; + +} + + + + + +static const char* +i91u_probe (pcici_t tag, pcidi_t type) +{ + switch (type) { + case PCI_DEVICE_ID_INIC940: + return ("Initio INIC-941 PCI SCSI adapter"); + case PCI_DEVICE_ID_INIC941: + return ("Initio INIC-940 PCI SCSI adapter"); + case PCI_DEVICE_ID_INIC950: + return ("Initio INI-9XXXU/UW PCI SCSI adapter"); + } + return (NULL); +} diff -urN -urN src/sys/dev/ihaempty/i91u.h src/sys/dev/iha/i91u.h --- src/sys/dev/ihaempty/i91u.h Thu Jan 1 02:00:00 1970 +++ src/sys/dev/iha/i91u.h Fri Dec 10 09:38:34 1999 @@ -0,0 +1,1047 @@ +/*- + * Copyright (c) 1997-99 Initio Corporation + * All rights reserved. + * + * 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. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY INITIO CORPORATION ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL INITIO CORPORATION BE LIABLE FOR ANY DIRECT,INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: i91u.c,v 1.82.2.9 1998/01/08 12:04:00 se Exp $ + */ + +#define ULONG unsigned long + +#define USHORT unsigned short + +#define UCHAR unsigned char + +#define BYTE unsigned char + +#define WORD unsigned short + +#define DWORD unsigned long + +#define UBYTE unsigned char + +#define UWORD unsigned short + +#define UDWORD unsigned long + + + +#ifndef NULL + +#define NULL 0 /* zero */ + +#endif + +#ifndef TRUE + +#define TRUE (1) /* boolean true */ + +#endif + +#ifndef FALSE + +#define FALSE (0) /* boolean false */ + +#endif + +#ifndef FAILURE + +#define FAILURE (-1) + +#endif + +/*#endif*/ + + + +#define I91U_SG_ENTRY 33 +#define MAX_SUPPORTED_ADAPTERS 8 +#define MAX_OFFSET 15 +#define MAX_TARGETS 16 +#define MAX_SCB 32 + +#define PAGELEN 4096 + +#define INI_VENDOR_ID 0x1101 /* Initio's PCI vendor ID */ + +#define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */ + +#define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */ + +#define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */ + + + +#define _I91USCSI_H + + +/***************************************/ + +/* Tulip Configuration Register Set */ + +/***************************************/ + +#define TUL_PVID 0x00 /* Vendor ID */ + +#define TUL_PDID 0x02 /* Device ID */ + +#define TUL_PCMD 0x04 /* Command */ + +#define TUL_PSTUS 0x06 /* Status */ + +#define TUL_PRID 0x08 /* Revision number */ + +#define TUL_PPI 0x09 /* Programming interface */ + +#define TUL_PSC 0x0A /* Sub Class */ + +#define TUL_PBC 0x0B /* Base Class */ + +#define TUL_PCLS 0x0C /* Cache line size */ + +#define TUL_PLTR 0x0D /* Latency timer */ + +#define TUL_PHDT 0x0E /* Header type */ + +#define TUL_PBIST 0x0F /* BIST */ + +#define TUL_PBAD 0x10 /* Base address */ + +#define TUL_PBAD1 0x14 /* Base address */ + +#define TUL_PBAD2 0x18 /* Base address */ + +#define TUL_PBAD3 0x1C /* Base address */ + +#define TUL_PBAD4 0x20 /* Base address */ + +#define TUL_PBAD5 0x24 /* Base address */ + +#define TUL_PRSVD 0x28 /* Reserved */ + +#define TUL_PRSVD1 0x2C /* Reserved */ + +#define TUL_PRAD 0x30 /* Expansion ROM base address */ + +#define TUL_PRSVD2 0x34 /* Reserved */ + +#define TUL_PRSVD3 0x38 /* Reserved */ + +#define TUL_PINTL 0x3C /* Interrupt line */ + +#define TUL_PINTP 0x3D /* Interrupt pin */ + +#define TUL_PIGNT 0x3E /* MIN_GNT */ + +#define TUL_PMGNT 0x3F /* MAX_GNT */ + + +/************************/ + +/* Tulip Register Set */ + +/************************/ + +#define TUL_HACFG0 0x40 /* H/A Configuration Register 0 */ + +#define TUL_HACFG1 0x41 /* H/A Configuration Register 1 */ + +#define TUL_HACFG2 0x42 /* H/A Configuration Register 2 */ + + +#define TUL_SDCFG0 0x44 /* SCSI Device Configuration 0 */ + +#define TUL_SDCFG1 0x45 /* SCSI Device Configuration 1 */ + +#define TUL_SDCFG2 0x46 /* SCSI Device Configuration 2 */ + +#define TUL_SDCFG3 0x47 /* SCSI Device Configuration 3 */ + + +#define TUL_GINTS 0x50 /* Global Interrupt Status Register */ + +#define TUL_GIMSK 0x52 /* Global Interrupt MASK Register */ + +#define TUL_GCTRL 0x54 /* Global Control Register */ + + #define TUL_GCTRL_EEPROM_BIT 0x04 + +#define TUL_GCTRL1 0x55 /* Global Control Register */ + +#define TUL_DMACFG 0x5B /* DMA configuration */ + +#define TUL_NVRAM 0x5D /* Non-volatile RAM port */ + + +#define TUL_SCnt0 0x80 /* 00 R/W Transfer Counter Low */ + +#define TUL_SCnt1 0x81 /* 01 R/W Transfer Counter Mid */ + +#define TUL_SCnt2 0x82 /* 02 R/W Transfer Count High */ + +#define TUL_SFifoCnt 0x83 /* 03 R FIFO counter */ + +#define TUL_SIntEnable 0x84 /* 03 W Interrupt enble */ + +#define TUL_SInt 0x84 /* 04 R Interrupt Register */ + +#define TUL_SCtrl0 0x85 /* 05 W Control 0 */ + +#define TUL_SStatus0 0x85 /* 05 R Status 0 */ + +#define TUL_SCtrl1 0x86 /* 06 W Control 1 */ + +#define TUL_SStatus1 0x86 /* 06 R Status 1 */ + +#define TUL_SConfig 0x87 /* 07 W Configuration */ + +#define TUL_SStatus2 0x87 /* 07 R Status 2 */ + +#define TUL_SPeriod 0x88 /* 08 W Sync. Transfer Period & Offset*/ + +#define TUL_SOffset 0x88 /* 08 R Offset */ + +#define TUL_SScsiId 0x89 /* 09 W SCSI ID */ + +#define TUL_SBusId 0x89 /* 09 R SCSI BUS ID */ + +#define TUL_STimeOut 0x8A /* 0A W Sel/Resel Time Out Register */ + +#define TUL_SIdent 0x8A /* 0A R Identify Message Register */ + +#define TUL_SAvail 0x8A /* 0A R Availiable Counter Register */ + +#define TUL_SData 0x8B /* 0B R/W SCSI data in/out */ + +#define TUL_SFifo 0x8C /* 0C R/W FIFO */ + +#define TUL_SSignal 0x90 /* 10 R/W SCSI signal in/out */ + +#define TUL_SCmd 0x91 /* 11 R/W Command */ + +#define TUL_STest0 0x92 /* 12 R/W Test0 */ + +#define TUL_STest1 0x93 /* 13 R/W Test1 */ + + + +#define TUL_XAddH 0xC0 /*DMA Transfer Physical Address */ + +#define TUL_XAddW 0xC8 /*DMA Current Transfer Physical Address */ + +#define TUL_XCntH 0xD0 /*DMA Transfer Counter */ + +#define TUL_XCntW 0xD4 /*DMA Current Transfer Counter */ + +#define TUL_XCmd 0xD8 /*DMA Command Register */ + +#define TUL_Int 0xDC /*Interrupt Register */ + +#define TUL_XStatus 0xDD /*DMA status Register */ + +#define TUL_Mask 0xE0 /*Interrupt Mask Register */ + +#define TUL_XCtrl 0xE4 /*DMA Control Register */ + +#define TUL_XCtrl1 0xE5 /*DMA Control Register 1 */ + +#define TUL_XFifo 0xE8 /*DMA FIFO */ + + +#define TUL_WCtrl 0xF7 /*Bus master wait state control */ + +#define TUL_DCtrl 0xFB /*DMA delay control */ + + +/*----------------------------------------------------------------------*/ + +/* bit definition for Command register of Configuration Space Header */ + +/*----------------------------------------------------------------------*/ + +#define BUSMS 0x04 /* BUS MASTER Enable */ + +#define IOSPA 0x01 /* IO Space Enable */ + + +/*----------------------------------------------------------------------*/ + +/* Command Codes of Tulip SCSI Command register */ + +/*----------------------------------------------------------------------*/ + +#define TSC_EN_RESEL 0x80 /* Enable Reselection */ + +#define TSC_CMD_COMP 0x84 /* Command Complete Sequence */ + +#define TSC_SEL 0x01 /* Select Without ATN Sequence */ + +#define TSC_SEL_ATN 0x11 /* Select With ATN Sequence */ + +#define TSC_SEL_ATN3 0x31 /* Select With ATN3 Sequence */ + +#define TSC_SEL_ATNSTOP 0x12 /* Select With ATN and Stop Sequence */ + +#define TSC_SELATNSTOP 0x1E /* Select With ATN and Stop Sequence */ + + + +#define TSC_SEL_ATN_DIRECT_IN 0x95 /* Select With ATN Sequence */ + +#define TSC_SEL_ATN_DIRECT_OUT 0x15 /* Select With ATN Sequence */ + +#define TSC_SEL_ATN3_DIRECT_IN 0xB5 /* Select With ATN3 Sequence */ + +#define TSC_SEL_ATN3_DIRECT_OUT 0x35 /* Select With ATN3 Sequence */ + +#define TSC_XF_DMA_OUT_DIRECT 0x06 /* DMA Xfer Infomation out */ + +#define TSC_XF_DMA_IN_DIRECT 0x86 /* DMA Xfer Infomation in */ + + +#define TSC_XF_DMA_OUT 0x43 /* DMA Xfer Infomation out */ + +#define TSC_XF_DMA_IN 0xC3 /* DMA Xfer Infomation in */ + +#define TSC_XF_FIFO_OUT 0x03 /* FIFO Xfer Infomation out */ + +#define TSC_XF_FIFO_IN 0x83 /* FIFO Xfer Infomation in */ + + +#define TSC_MSG_ACCEPT 0x0F /* Message Accept */ + + +/*----------------------------------------------------------------------*/ + +/* bit definition for Tulip SCSI Control 0 Register */ + +/*----------------------------------------------------------------------*/ + +#define TSC_RST_SEQ 0x20 /* Reset sequence counter */ + +#define TSC_FLUSH_FIFO 0x10 /* Flush FIFO */ + +#define TSC_ABT_CMD 0x04 /* Abort command (sequence) */ + +#define TSC_RST_CHIP 0x02 /* Reset SCSI Chip */ + +#define TSC_RST_BUS 0x01 /* Reset SCSI Bus */ + + + +/*----------------------------------------------------------------------*/ + +/* bit definition for Tulip SCSI Control 1 Register */ + +/*----------------------------------------------------------------------*/ + +#define TSC_EN_SCAM 0x80 /* Enable SCAM */ + +#define TSC_TIMER 0x40 /* Select timeout unit */ + +#define TSC_EN_SCSI2 0x20 /* SCSI-2 mode */ + +#define TSC_PWDN 0x10 /* Power down mode */ + +#define TSC_WIDE_CPU 0x08 /* Wide CPU */ + +#define TSC_HW_RESELECT 0x04 /* Enable HW reselect */ + +#define TSC_EN_BUS_OUT 0x02 /* Enable SCSI data bus out latch */ + +#define TSC_EN_BUS_IN 0x01 /* Enable SCSI data bus in latch */ + + + +/*----------------------------------------------------------------------*/ + +/* bit definition for Tulip SCSI Configuration Register */ + +/*----------------------------------------------------------------------*/ + +#define TSC_EN_LATCH 0x80 /* Enable phase latch */ + +#define TSC_INITIATOR 0x40 /* Initiator mode */ + +#define TSC_EN_SCSI_PAR 0x20 /* Enable SCSI parity */ + +#define TSC_DMA_8BIT 0x10 /* Alternate dma 8-bits mode */ + +#define TSC_DMA_16BIT 0x08 /* Alternate dma 16-bits mode */ + +#define TSC_EN_WDACK 0x04 /* Enable DACK while wide SCSI xfer */ + +#define TSC_ALT_PERIOD 0x02 /* Alternate sync period mode */ + +#define TSC_DIS_SCSIRST 0x01 /* Disable SCSI bus reset us */ + + + +#define TSC_INITDEFAULT (TSC_INITIATOR | TSC_EN_LATCH | TSC_ALT_PERIOD | TSC_DIS_SCSIRST) + + + +#define TSC_WIDE_SCSI 0x80 /* Enable Wide SCSI */ + + + +/*----------------------------------------------------------------------*/ + +/* bit definition for Tulip SCSI signal Register */ + +/*----------------------------------------------------------------------*/ + +#define TSC_RST_ACK 0x00 /* Release ACK signal */ + +#define TSC_RST_ATN 0x00 /* Release ATN signal */ + +#define TSC_RST_BSY 0x00 /* Release BSY signal */ + + + +#define TSC_SET_ACK 0x40 /* ACK signal */ + +#define TSC_SET_ATN 0x08 /* ATN signal */ + + + +#define TSC_REQI 0x80 /* REQ signal */ + +#define TSC_ACKI 0x40 /* ACK signal */ + +#define TSC_BSYI 0x20 /* BSY signal */ + +#define TSC_SELI 0x10 /* SEL signal */ + +#define TSC_ATNI 0x08 /* ATN signal */ + +#define TSC_MSGI 0x04 /* MSG signal */ + +#define TSC_CDI 0x02 /* C/D signal */ + +#define TSC_IOI 0x01 /* I/O signal */ + + + +/*----------------------------------------------------------------------*/ + +/* bit definition for Tulip SCSI Status 0 Register */ + +/*----------------------------------------------------------------------*/ + +#define TSS_INT_PENDING 0x80 /* Interrupt pending */ + +#define TSS_SEQ_ACTIVE 0x40 /* Sequencer active */ + +#define TSS_XFER_CNT 0x20 /* Transfer counter zero */ + +#define TSS_FIFO_EMPTY 0x10 /* FIFO empty */ + +#define TSS_PAR_ERROR 0x08 /* SCSI parity error */ + +#define TSS_PH_MASK 0x07 /* SCSI phase mask */ + + + +/*----------------------------------------------------------------------*/ + +/* bit definition for Tulip SCSI Status 1 Register */ + +/*----------------------------------------------------------------------*/ + +#define TSS_STATUS_RCV 0x08 /* Status received */ + +#define TSS_MSG_SEND 0x40 /* Message sent */ + +#define TSS_CMD_PH_CMP 0x20 /* Data phase done */ + +#define TSS_DATA_PH_CMP 0x10 /* Data phase done */ + +#define TSS_STATUS_SEND 0x08 /* Status sent */ + +#define TSS_XFER_CMP 0x04 /* Transfer completed */ + +#define TSS_SEL_CMP 0x02 /* Selection completed */ + +#define TSS_ARB_CMP 0x01 /* Arbitration completed */ + + +/*----------------------------------------------------------------------*/ + +/* bit definition for Tulip SCSI Status 2 Register */ + +/*----------------------------------------------------------------------*/ + +#define TSS_CMD_ABTED 0x80 /* Command aborted */ + +#define TSS_OFFSET_0 0x40 /* Offset counter zero */ + +#define TSS_FIFO_FULL 0x20 /* FIFO full */ + +#define TSS_TIMEOUT_0 0x10 /* Timeout counter zero */ + +#define TSS_BUSY_RLS 0x08 /* Busy release */ + +#define TSS_PH_MISMATCH 0x04 /* Phase mismatch */ + +#define TSS_SCSI_BUS_EN 0x02 /* SCSI data bus enable */ + +#define TSS_SCSIRST 0x01 /* SCSI bus reset in progress */ + + +/*----------------------------------------------------------------------*/ + +/* bit definition for Tulip SCSI Interrupt Register */ + +/*----------------------------------------------------------------------*/ + +#define TSS_RESEL_INT 0x80 /* Reselected interrupt */ + +#define TSS_SEL_TIMEOUT 0x40 /* Selected/reselected timeout */ + +#define TSS_BUS_SERV 0x20 + +#define TSS_SCSIRST_INT 0x10 /* SCSI bus reset detected */ + +#define TSS_DISC_INT 0x08 /* Disconnected interrupt */ + +#define TSS_SEL_INT 0x04 /* Select interrupt */ + +#define TSS_SCAM_SEL 0x02 /* SCAM selected */ + +#define TSS_FUNC_COMP 0x01 + + +/*----------------------------------------------------------------------*/ + +/* SCSI Phase Codes. */ + +/*----------------------------------------------------------------------*/ + +#define DATA_OUT 0 +#define DATA_IN 1 /* 4 */ + +#define CMD_OUT 2 +#define STATUS_IN 3 /* 6 */ + +#define MSG_OUT 6 /* 3 */ + +#define MSG_IN 7 + + + +/*----------------------------------------------------------------------*/ + +/* Command Codes of Tulip xfer Command register */ + +/*----------------------------------------------------------------------*/ + +#define TAX_X_ABT 0x04 + + +#define TAX_X_IN 0x21 + +#define TAX_X_OUT 0x01 + +#define TAX_SG_IN 0xA1 + +#define TAX_SG_OUT 0x81 + + +/*----------------------------------------------------------------------*/ + +/* Tulip Interrupt Register */ + +/*----------------------------------------------------------------------*/ + +#define XCMP 0x01 + +#define XABT 0x04 + +#define XERR 0x08 + +#define SCMP 0x10 + +#define IPEND 0x80 + + +/*----------------------------------------------------------------------*/ + +/* Tulip DMA Status Register */ + +/*----------------------------------------------------------------------*/ + +#define XPEND 0x01 /* Transfer pending */ + +#define FEMPTY 0x02 /* FIFO empty */ + + + + +/*----------------------------------------------------------------------*/ + +/* bit definition for TUL_GCTRL */ + +/*----------------------------------------------------------------------*/ + +#define EEPRG 0x04 + +#define MRMUL 0x02 + + +/*----------------------------------------------------------------------*/ + +/* bit definition for TUL_NVRAM */ + +/*----------------------------------------------------------------------*/ + +#define SE2CS 0x08 + +#define SE2CLK 0x04 + +#define SE2DO 0x02 + +#define SE2DI 0x01 + + + +/************************************************************************/ +/* Scatter-Gather Element Structure */ +/************************************************************************/ +typedef struct SG_Struc { + ULONG SG_Ptr; /* Data Pointer */ + ULONG SG_Len; /* Data Length */ +} I91U_SG; + +/*********************************************************************** + SCSI Control Block +************************************************************************/ +typedef struct I91U_Scsi_Ctrl_Blk { + struct I91U_Scsi_Ctrl_Blk *SCB_NxtScb; + UBYTE SCB_Status; /*4 */ + UBYTE SCB_NxtStat; /*5 */ + UBYTE SCB_Mode; /*6 */ + UBYTE SCB_Msgin; /*7 SCB_Res0 */ + UWORD SCB_SGIdx; /*8 */ + UWORD SCB_SGMax; /*A */ +#if 0 + bus_dmamap_t SCB_dmamap; /*C */ +#endif + + UBYTE SCB_Opcode; /*10 SCB command code */ + UBYTE SCB_Flags; /*11 SCB Flags */ + UBYTE SCB_Target; /*12 Target Id */ + UBYTE SCB_Lun; /*13 Lun */ + ULONG SCB_BufPtr; /*14 Data Buffer Pointer */ + ULONG SCB_BufLen; /*18 Data Allocation Length */ + UBYTE SCB_HaStat; /*1c */ + UBYTE SCB_TaStat; /*1d */ + UBYTE SCB_SGLen; /*1e SG list # */ + UBYTE SCB_SenseLen; /*1f Sense Allocation Length */ + UBYTE SCB_CDBLen; /*20 CDB Length */ + UBYTE SCB_Ident; /*21 Identify */ + UBYTE SCB_TagMsg; /*22 Tag Message */ + UBYTE SCB_TagId; /*23 Queue Tag */ + UBYTE SCB_CDB[12]; /*24 */ + ULONG SCB_SGPAddr; /*30 SG List/Sense Buf phy. Addr. */ + ULONG SCB_SensePtr; /*34 Sense data pointer */ + void (* SCB_Post)(BYTE *, BYTE *); /*38 POST routine */ + ULONG SCB_ccb; /*3c ccb Pointer */ + I91U_SG SCB_SGList[I91U_SG_ENTRY]; /*40 Start of SG list */ + +} I91U_SCB; + + + +/* Bit Definition for SCB_Status */ + +#define SCB_RENT 0x01 + +#define SCB_PEND 0x02 + +#define SCB_CONTIG 0x04 /* Contigent Allegiance */ + +#define SCB_SELECT 0x08 + +#define SCB_BUSY 0x10 + +#define SCB_DONE 0x20 + + + +/* Opcodes of SCB_Opcode */ + +#define ExecSCSI 0x1 + +#define BusDevRst 0x2 + +#define AbortCmd 0x3 + + + +/* Bit Definition for SCB_Mode */ + +#define SCM_RSENS 0x01 /* request sense mode */ + + + +/* Bit Definition for SCB_Flags */ + +#define SCF_DONE 0x01 + +#define SCF_POST 0x02 + +#define SCF_SENSE 0x04 + +#define SCF_DIR 0x18 + +#define SCF_NO_DCHK 0x00 + +#define SCF_DIN 0x08 + +#define SCF_DOUT 0x10 + +#define SCF_NO_XF 0x18 + +#define SCF_WR_VF 0x20 /* Write verify turn on */ + +#define SCF_POLL 0x40 +#define SCF_SG 0x80 + +/* Error Codes for SCB_HaStat */ + +#define HOST_OK 0x00 +#define HOST_SEL_TOUT 0x11 +#define HOST_DO_DU 0x12 +#define HOST_BUS_FREE 0x13 +#define HOST_BAD_PHAS 0x14 +#define HOST_INV_CMD 0x16 +#define HOST_SCSI_RST 0x1B +#define HOST_DEV_RST 0x1C + +/* Error Codes for SCB_TaStat */ + +#define TARGET_GOOD 0x00 +#define TARGET_CHKCOND 0x02 +#define TARGET_BUSY 0x08 +#define TARGET_QFULL 0x28 + +/* SCSI MESSAGE */ +#define MSG_COMP 0x00 + +#define MSG_EXTEND 0x01 + +#define MSG_SDP 0x02 + +#define MSG_RESTORE 0x03 + +#define MSG_DISC 0x04 + +#define MSG_IDE 0x05 + +#define MSG_ABORT 0x06 + +#define MSG_REJ 0x07 + +#define MSG_NOP 0x08 + +#define MSG_PARITY 0x09 + +#define MSG_LINK_COMP 0x0A + +#define MSG_LINK_FLAG 0x0B + +#define MSG_DEVRST 0x0C + +/* TTT #define MSG_ABORT_TAG 0x0D + */ + +/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */ + +#define MSG_STAG 0x20 + +#define MSG_HTAG 0x21 + +#define MSG_OTAG 0x22 + + +#define MSG_IGNOREWIDE 0x23 + + +#define MSG_IDENT 0x80 + + +/*********************************************************************** + Target Device Control Structure +**********************************************************************/ + +typedef struct Tar_Ctrl_Struc { + UWORD TCS_Flags; /* 0 */ + UBYTE TCS_JS_Period; /* 2 */ + UBYTE TCS_SConfig0; /* 3 */ + + UWORD TCS_DrvFlags; /* 4 */ + UBYTE TCS_DrvHead; /* 6 */ + UBYTE TCS_TagCnt; /* 7 */ + I91U_SCB *TCS_NonTagScb; /* 8 */ +} TCS; + +/*********************************************************************** + + Target Device Control Structure +**********************************************************************/ + + +/* Bit Definition for TCS_Flags */ + +#define TCF_SCSI_RATE 0x0007 +#define TCF_EN_DISC 0x0008 +#define TCF_NO_SYNC_NEGO 0x0010 +#define TCF_NO_WDTR 0x0020 +#define TCF_WDTR_DONE 0x0100 +#define TCF_SYNC_DONE 0x0200 +#define TCF_BUSY 0x0400 + + +/* Bit Definition for TCS_DrvFlags */ + +#define TCF_DRV_BUSY 0x01 /* Indicate target busy(driver) */ + +#define TCF_DRV_EN_TAG 0x0800 + + + + +/*********************************************************************** + + Host Adapter Control Structure +************************************************************************/ + +typedef struct I91U_Ha_Ctrl_Struc { + ULONG HCS_Base; /* 00 */ + ULONG HCS_SFifo; /* 04 */ + ULONG HCS_SCmd; /* 08 */ + UBYTE HCS_Intr; /* 14 */ + UBYTE HCS_SCSI_ID; /* 05 */ + UBYTE HCS_MaxTar; /* 06 */ + UBYTE HCS_NumScbs; /* 07 */ + + UBYTE HCS_Unit; /* 08 */ + UBYTE HCS_HaId; /* 09 */ + UBYTE HCS_Config; /* 0A */ + UBYTE HCS_Flags; /* 0B */ + UBYTE HCS_Semaph; /* 0C */ + UBYTE HCS_Phase; /* 0D */ + UBYTE HCS_JSStatus0; /* 0E */ + UBYTE HCS_JSInt; /* 0F */ + UBYTE HCS_JSStatus1; /* 10 */ + UBYTE HCS_SConf1; /* 11 */ + + UBYTE HCS_Msg[6]; /* 12 */ + I91U_SCB *HCS_Scb; /* 18 */ + I91U_SCB *HCS_ActScb; /* 1C */ + TCS *HCS_ActTcs; /* 20 */ + + I91U_SCB *HCS_FirstAvail;/* 24 */ + I91U_SCB *HCS_LastAvail; /* 28 */ + I91U_SCB *HCS_FirstPend; /* 2C */ + I91U_SCB *HCS_LastPend; /* 30 */ + I91U_SCB *HCS_FirstDone; /* 34 */ + I91U_SCB *HCS_LastDone; /* 38 */ + + bus_dma_tag_t dmat; + bus_dmamap_t dmamap; + struct cam_sim *sim; + struct cam_path *path; + + TCS HCS_Tcs[MAX_TARGETS]; /* 40 */ +} I91U_HCS; + +/* Bit Definition for HCB_Config */ + +#define HCC_SCSI_RESET 0x01 + +#define HCC_EN_PAR 0x02 + +#define HCC_ACT_TERM1 0x04 + +#define HCC_ACT_TERM2 0x08 + +#define HCC_AUTO_TERM 0x10 + +#define HCC_EN_PWR 0x80 + + + +/* Bit Definition for HCB_Flags */ + +#define HCF_EXPECT_DISC 0x01 + +#define HCF_EXPECT_SELECT 0x02 + +#define HCF_EXPECT_RESET 0x10 + +#define HCF_EXPECT_DONE_DISC 0x20 + + + +/****************************************************************** + + Serial EEProm + +*******************************************************************/ + + + +typedef struct _NVRAM_SCSI { /* SCSI channel configuration */ + + UCHAR NVM_ChSCSIID; /* 0Ch -> Channel SCSI ID */ + + UCHAR NVM_ChConfig1; /* 0Dh -> Channel config 1 */ + + UCHAR NVM_ChConfig2; /* 0Eh -> Channel config 2 */ + + UCHAR NVM_NumOfTarg; /* 0Fh -> Number of SCSI target */ + + /* SCSI target configuration */ + + UCHAR NVM_Targ0Config; /* 10h -> Target 0 configuration*/ + + UCHAR NVM_Targ1Config; /* 11h -> Target 1 configuration*/ + + UCHAR NVM_Targ2Config; /* 12h -> Target 2 configuration*/ + + UCHAR NVM_Targ3Config; /* 13h -> Target 3 configuration*/ + + UCHAR NVM_Targ4Config; /* 14h -> Target 4 configuration*/ + + UCHAR NVM_Targ5Config; /* 15h -> Target 5 configuration*/ + + UCHAR NVM_Targ6Config; /* 16h -> Target 6 configuration*/ + + UCHAR NVM_Targ7Config; /* 17h -> Target 7 configuration*/ + + UCHAR NVM_Targ8Config; /* 18h -> Target 8 configuration*/ + + UCHAR NVM_Targ9Config; /* 19h -> Target 9 configuration*/ + + UCHAR NVM_TargAConfig; /* 1Ah -> Target A configuration*/ + + UCHAR NVM_TargBConfig; /* 1Bh -> Target B configuration*/ + + UCHAR NVM_TargCConfig; /* 1Ch -> Target C configuration*/ + + UCHAR NVM_TargDConfig; /* 1Dh -> Target D configuration*/ + + UCHAR NVM_TargEConfig; /* 1Eh -> Target E configuration*/ + + UCHAR NVM_TargFConfig; /* 1Fh -> Target F configuration*/ + +} NVRAM_SCSI; + +typedef struct _NVRAM { + /*----------header ---------------*/ + USHORT NVM_Signature; /* 0,1: Signature */ + UCHAR NVM_Size; /* 2: Size of data structure */ + UCHAR NVM_Revision; /* 3: Revision of data structure */ + /* ----Host Adapter Structure ----*/ + UCHAR NVM_ModelByte0; /* 4: Model number (byte 0) */ + UCHAR NVM_ModelByte1; /* 5: Model number (byte 1) */ + UCHAR NVM_ModelInfo; /* 6: Model information */ + UCHAR NVM_NumOfCh; /* 7: Number of SCSI channel*/ + UCHAR NVM_BIOSConfig1; /* 8: BIOS configuration 1 */ + UCHAR NVM_BIOSConfig2; /* 9: BIOS configuration 2 */ + UCHAR NVM_HAConfig1; /* A: Hoat adapter configuration 1 */ + UCHAR NVM_HAConfig2; /* B: Hoat adapter configuration 2 */ + NVRAM_SCSI NVM_SCSIInfo[2]; + UCHAR NVM_reserved[10]; + /* ---------- CheckSum ---------- */ + USHORT NVM_CheckSum; /* 0x3E, 0x3F: Checksum of NVRam */ + } NVRAM, *PNVRAM; + +/* Bios Configuration for nvram->BIOSConfig1 */ +#define NBC1_ENABLE 0x01 /* BIOS enable */ +#define NBC1_8DRIVE 0x02 /* Support more than 2 drives */ +#define NBC1_REMOVABLE 0x04 /* Support removable drive */ +#define NBC1_INT19 0x08 /* Intercept int 19h */ +#define NBC1_BIOSSCAN 0x10 /* Dynamic BIOS scan */ +#define NBC1_LUNSUPPORT 0x40 /* Support LUN */ + +/* HA Configuration Byte 1 */ + +#define NHC1_BOOTIDMASK 0x0F /* Boot ID number */ + +#define NHC1_LUNMASK 0x70 /* Boot LUN number */ + +#define NHC1_CHANMASK 0x80 /* Boot Channel number */ + + + +/* Bit definition for nvram->SCSIconfig1 */ + +#define NCC1_BUSRESET 0x01 /* Reset SCSI bus at power up */ + +#define NCC1_PARITYCHK 0x02 /* SCSI parity enable */ + +#define NCC1_ACTTERM1 0x04 /* Enable active terminator 1 */ + +#define NCC1_ACTTERM2 0x08 /* Enable active terminator 2 */ + +#define NCC1_AUTOTERM 0x10 /* Enable auto terminator */ + +#define NCC1_PWRMGR 0x80 /* Enable power management */ + + +/* Bit definition for SCSI Target configuration byte */ + +#define NTC_DISCONNECT 0x08 /* Enable SCSI disconnect */ + +#define NTC_SYNC 0x10 /* SYNC_NEGO */ + +#define NTC_NO_WDTR 0x20 /* SYNC_NEGO */ + +#define NTC_1GIGA 0x40 /* 255 head / 63 sectors (64/32)*/ + +#define NTC_SPINUP 0x80 /* Start disk drive */ + + +/* Default NVRam values */ + +#define INI_SIGNATURE 0xC925 +#define NBC1_DEFAULT (NBC1_ENABLE) +#define NCC1_DEFAULT (NCC1_BUSRESET | NCC1_AUTOTERM | NCC1_PARITYCHK) +#define NTC_DEFAULT (NTC_NO_WDTR | NTC_1GIGA | NTC_DISCONNECT) + +/* SCSI related definition */ +#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */ +#define DISC_ALLOW 0xC0 /* Disconnect is allowed */ +#define SCSICMD_RequestSense 0x03 + + + + +#define TUL_RD(adr) ( (UCHAR) inb( (ULONG)(adr) ) ) +#define TUL_RDLONG(adr) ( (ULONG) inl( (ULONG)(adr) ) ) +#define TUL_WR( adr,data) outb( (ULONG)(adr), (UCHAR)(data)) +#define TUL_WRSHORT(adr,data) outw( (ULONG)(adr), (UWORD)(data)) +#define TUL_WRLONG( adr,data) outl( (ULONG)(adr), (ULONG)(data)) + diff -urN -urN src/sys/dev/ihaempty/i91utmp.c src/sys/dev/iha/i91utmp.c --- src/sys/dev/ihaempty/i91utmp.c Thu Jan 1 02:00:00 1970 +++ src/sys/dev/iha/i91utmp.c Fri Jun 22 16:28:57 2001 @@ -0,0 +1,3308 @@ +/*- + * Copyright (c) 1997-99 Initio Corporation + * All rights reserved. + * + * 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. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY INITIO CORPORATION ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL INITIO CORPORATION BE LIABLE FOR ANY DIRECT,INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define DEBUG_INTERRUPT 0 +#define DEBUG_QUEUE 0 +#define DEBUG_STATE 0 + + + + + +/*--- external functions --*/ +static void tul_se2_wait(void); + +#if 0 +static void tul_do_pause(ULONG amount ); +#endif + + +/*--- forward refrence ---*/ + +static long tulip_main(I91U_HCS *pHcs); + +static I91U_SCB *tul_alloc_scb(I91U_HCS *pHcs); +static void tul_release_scb(I91U_HCS *pHcs, I91U_SCB *pScb); +static void tul_append_pend_scb(I91U_HCS *pHcs, I91U_SCB *scbp); +static void tul_push_pend_scb(I91U_HCS *pHcs, I91U_SCB *scbp); +static I91U_SCB *tul_find_pend_scb(I91U_HCS *pHcs); +static I91U_SCB *tul_pop_pend_scb(I91U_HCS *pHcs, I91U_SCB *pActScb); +static void tul_append_busy_scb(I91U_HCS *pHcs, I91U_SCB *scbp); +static void tul_unlink_busy_scb(I91U_HCS *pHcs, I91U_SCB *pScb); +static void tul_append_done_scb(I91U_HCS *pHcs, I91U_SCB *scbp); +static I91U_SCB *tul_find_done_scb(I91U_HCS *pHcs); +static I91U_SCB *tul_abort_ccb(I91U_HCS *pHcs, ULONG ccb); + +static long tul_next_state(I91U_HCS *pHcs); +static long tul_state_5(I91U_HCS *pHcs); +static long tul_xfer_data_in(I91U_HCS *pHcs); +static long tul_xfer_data_out(I91U_HCS *pHcs); +static long tul_xpad_in(I91U_HCS *pHcs); +static long tul_xpad_out(I91U_HCS *pHcs); +static long tul_status_msg(I91U_HCS *pHcs); +/*static long tul_bad_seq(I91U_HCS *pHcs); 10/13/97 */ + +static long tul_msgin(I91U_HCS *pHcs); +static long tul_msgin_sync(I91U_HCS *pHcs); +static long tul_msgin_discon(I91U_HCS *pHcs); +static long tul_msgin_accept(I91U_HCS *pHcs); +static long tul_msgout_reject(I91U_HCS *pHcs); +static long tul_msgin_extend(I91U_HCS *pHcs); +static long tul_msgin_ignore_wid_resid(I91U_HCS *pHcs); + +static long tul_msgout_sync(I91U_HCS *pHcs); +static long tul_msgout_nop(I91U_HCS *pHcs); +static long tul_msgout_ide(I91U_HCS *pHcs); +static long tul_msgout_abort_targ(I91U_HCS *pHcs); +static long tul_msgout_abort_tag(I91U_HCS *pHcs); + +static void tul_select_atn(I91U_HCS *pHcs, I91U_SCB *pScb); +static void tul_select_atn3(I91U_HCS *pHcs, I91U_SCB *pScb); +static void tul_select_atn_stop(I91U_HCS *pHcs, I91U_SCB *pScb); +static long tul_reset_scsi(I91U_HCS *pHcs); +static long int_tul_busfree(I91U_HCS *pHcs); +static long int_tul_scsi_rst(I91U_HCS *pHcs); +static long int_tul_resel(I91U_HCS *pHcs); +static void tul_sync_done(I91U_HCS *pHcs); +static void tul_wdtr_done(I91U_HCS *pHcs); +static long wait_tulip(I91U_HCS *pHcs); +/*static long tul_msgin_par_err(I91U_HCS *pHcs);*/ +static void tulip_scsi(I91U_HCS *pHcs); +static long tul_post_scsi_rst(I91U_HCS *pHcs); + +static void tul_se2_ew_en(DWORD port); +static void tul_se2_ew_ds(DWORD port); +static long tul_se2_rd_all(DWORD port); +static void tul_se2_update_all(DWORD port); /* setup default pattern */ +static void tul_read_eeprom(DWORD CurBase); + + + /* ---- INTERNAL VARIABLES ---- */ + +/*NVRAM nvram, *nvramp = &nvram;*/ +static NVRAM i91unvram; +static NVRAM *i91unvramp; + + + +static UCHAR i91udftNvRam[64] = { /*----------- header -----------*/ + 0x25, 0xc9, /* Signature */ + 0x40, /* Size */ + 0x01, /* Revision */ + /* -- Host Adapter Structure -- */ + 0x95, /* ModelByte0 */ + 0x00, /* ModelByte1 */ + 0x00, /* ModelInfo */ + 0x01, /* NumOfCh */ + NBC1_DEFAULT, /* BIOSConfig1 */ + 0, /* BIOSConfig2 */ + 0, /* HAConfig1 */ + 0, /* HAConfig2 */ + /* SCSI channel 0 and target Structure */ + 7, /* SCSIid */ + NCC1_DEFAULT, /* SCSIconfig1 */ + 0, /* SCSIconfig2 */ + 8, /* NumSCSItarget*/ + + NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, + NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, + NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, + NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, + + /* SCSI channel 1 and target Structure */ + 7, /* SCSIid */ + NCC1_DEFAULT, /* SCSIconfig1 */ + 0, /* SCSIconfig2 */ + 8, /* NumSCSItarget*/ + + NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, + NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, + NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, + NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 }; /* - CheckSum - */ + + +static UCHAR tul_rate_tbl[8] = /* fast 20 */ + { + /* nanosecond devide by 4 */ + 12, /* 50ns, 20M */ + 18, /* 75ns, 13.3M */ + 25, /* 100ns, 10M */ + 31, /* 125ns, 8M */ + 37, /* 150ns, 6.6M */ + 43, /* 175ns, 5.7M */ + 50, /* 200ns, 5M */ + 62 /* 250ns, 4M */ + }; + + + +#if 0 +static void tul_do_pause( ULONG amount ) /* Pause for amount*1 milliseconds */ +{ + ULONG i; + + for (i = 0; i < amount; i++) /* wait */ + DELAY (1000); /* delay 1 msec */ +} +#endif + +/*-- forward reference --*/ +#if 0 +static void tul_snapdump(ULONG *ptr, int length) +{ + int col, row; + int i, idx; + + row = length / 16 + ((length % 16) ? 1 : 0); + idx = 0; + printk("\n\r"); + for (i = 0; i < row; i++) + { + printf("Offset %04x at %08lx : ", idx, (ULONG) ptr); + for (col = 0; (col < 2) & (idx < length); col++, idx+=4) + { + printf(" %08lx", *ptr++); + } + printk(" -"); + for (col = 0; (col < 2) & (idx < length); col++, idx+=4) + { + printk(" %08lx", *ptr++); + } + printk("\n\r"); + } +} +#endif +/*--- forward reference ---*/ + +/******************************************************************* + Use memeory refresh time ~ 15us * 2 +********************************************************************/ +static void tul_se2_wait() +{ +#if 1 + DELAY (5); /* delay 5 usec */ +#else + UCHAR readByte; + + readByte = TUL_RD( 0x61 ); + if ( (readByte & 0x10) == 0x10) { + for (; ;) { + readByte = TUL_RD( 0x61 ); + if ( (readByte & 0x10) == 0x10) + break; + } + for (;;) { + readByte = TUL_RD( 0x61 ); + if ( (readByte & 0x10) != 0x10) + break; + } + } else { + for (; ; ) { + readByte = TUL_RD( 0x61 ); + if ( (readByte & 0x10) == 0x10) + break; + } + for (; ; ) { + readByte = TUL_RD( 0x61 ); + if ( (readByte & 0x10) != 0x10) + break; + } + } +#endif +} + + +/****************************************************************** + Input: instruction for Serial E2PROM + +******************************************************************/ +static void tul_se2_instr(DWORD port, UCHAR instr) +{ + int i; + UCHAR b; + + TUL_WR(port, SE2CS | SE2DO); /* cs+start bit */ + tul_se2_wait(); + TUL_WR(port, SE2CS | SE2CLK | SE2DO); /* +CLK */ + tul_se2_wait(); + + for ( i = 0; i < 8; i++) { + if (instr & 0x80) + b = SE2CS | SE2DO; /* -CLK+dataBit */ + else + b = SE2CS ; /* -CLK */ + TUL_WR(port, b); + tul_se2_wait(); + TUL_WR(port, b | SE2CLK); /* +CLK */ + tul_se2_wait(); + instr <<= 1; + } + TUL_WR(port, SE2CS ); /* -CLK */ + tul_se2_wait(); + return; +} + + +/****************************************************************** + Function name : tul_se2_ew_en + Description : Enable erase/write state of serial EEPROM +******************************************************************/ +static void tul_se2_ew_en(DWORD port) +{ + tul_se2_instr(port, 0x30); /* EWEN */ + TUL_WR(port, 0); /* -CS */ + tul_se2_wait(); +} + + +/************************************************************************ + Disable erase/write state of serial EEPROM +*************************************************************************/ +static void tul_se2_ew_ds(DWORD port) +{ + tul_se2_instr(port, 0); /* EWDS */ + TUL_WR(port, 0); /* -CS */ + tul_se2_wait(); +} + + +/****************************************************************** + Input :address of Serial E2PROM + Output :value stored in Serial E2PROM +*******************************************************************/ +static USHORT tul_se2_rd(DWORD port, ULONG adr) +{ + UCHAR instr, readByte; + + USHORT readWord; + + int i; + + + + instr = (UCHAR)( adr | 0x80 ); + + tul_se2_instr(port, instr); /* READ INSTR */ + + readWord = 0; + + + + for ( i = 15; i >= 0; i--) { + + TUL_WR(port, SE2CS | SE2CLK ); /* +CLK */ + + tul_se2_wait(); + + TUL_WR(port, SE2CS ); /* -CLK */ + + + + /* sample data after the following edge of clock */ + + readByte = TUL_RD(port); + + readByte &= SE2DI; + + readWord += (readByte << i); + + tul_se2_wait(); /* 6/20/95 */ + + } + + + + TUL_WR(port, 0 ); /* no chip select */ + + tul_se2_wait(); + + return readWord; + +} + + +/****************************************************************** + + Input: new value in Serial E2PROM, address of Serial E2PROM + +*******************************************************************/ + +static void tul_se2_wr(DWORD port, UCHAR adr, USHORT writeWord) + +{ + + UCHAR readByte; + + UCHAR instr; + + int i; + + + + instr = (UCHAR)( adr | 0x40 ); + + tul_se2_instr(port, instr); /* WRITE INSTR */ + + for ( i = 15; i >= 0; i--) { + + if (writeWord & 0x8000) + + TUL_WR(port , SE2CS | SE2DO); /* -CLK+dataBit 1 */ + + else + + TUL_WR(port , SE2CS ); /* -CLK+dataBit 0 */ + + tul_se2_wait(); + + TUL_WR(port , SE2CS | SE2CLK ); /* +CLK */ + + tul_se2_wait(); + + writeWord <<= 1; + + } + + TUL_WR(port , SE2CS); /* -CLK */ + + tul_se2_wait(); + + TUL_WR(port , 0); /* -CS */ + + tul_se2_wait(); + + + + TUL_WR(port , SE2CS); /* +CS */ + + tul_se2_wait(); + + + + for (; ; ) { + + TUL_WR(port, SE2CS | SE2CLK); /* +CLK */ + + tul_se2_wait(); + + TUL_WR(port, SE2CS ); /* -CLK */ + + tul_se2_wait(); + + if ((readByte = TUL_RD(port)) & SE2DI ) + + break; /* write complete */ + + } + + TUL_WR(port, 0); /* -CS */ + + return; + +} + + + + + +/*********************************************************************** + + Read SCSI H/A configuration parameters from serial EEPROM + +************************************************************************/ + +static long tul_se2_rd_all(DWORD port) + +{ + int i; + + ULONG chksum = 0; + + USHORT *np; + + + i91unvramp = &i91unvram; + + np = (USHORT * )i91unvramp; + + for ( i = 0; i < 32; i++) { + *np++ = tul_se2_rd(port, i); + + } + + /*--------------------Is signature "ini" ok ? ----------------*/ + + if ( i91unvramp->NVM_Signature != INI_SIGNATURE ) + + return - 1; + +#if 0 + + /*--------------------Is Model# byte 1 "91" ok ? ----------------*/ + +// if ( i91unvramp->ModelByte0 != 0x91) /* 4: Model number (byte 0) */ + +// return - 1; + +#endif + + /*---------------------- Is ckecksum ok ? ----------------------*/ + + np = (USHORT * )i91unvramp; + + for ( i = 0; i < 31; i++) + + chksum += *np++; + + if ( i91unvramp->NVM_CheckSum != (USHORT)chksum ) + + return - 1; + + return 1; + +} + + + + + +/*********************************************************************** + + Update SCSI H/A configuration parameters from serial EEPROM + +************************************************************************/ + +static void tul_se2_update_all(DWORD port) /* setup default pattern */ + +{ + + int i; + + ULONG chksum = 0; + + USHORT * np, *np1; + + + + i91unvramp = &i91unvram; + + /* Calculate checksum first */ + + np = (USHORT * )i91udftNvRam; + + for ( i = 0; i < 31; i++) + + chksum += *np++; + + *np = (USHORT)chksum; + + tul_se2_ew_en(port); /* Enable write */ + + + + np = (USHORT * )i91udftNvRam; + + np1 = (USHORT * )i91unvramp; + + for ( i = 0; i < 32; i++, np++, np1++) { + + if (*np != *np1) { + + tul_se2_wr(port, i, *np); + + } + + } + + + + tul_se2_ew_ds(port); /* Disable write */ + + return; + +} + + + +/************************************************************************* + + Function name : read_eeprom + +**************************************************************************/ + +static void tul_read_eeprom(DWORD CurBase) + +{ + UCHAR gctrl; + + + i91unvramp = &i91unvram; + + /*------Enable EEProm programming ---*/ + + gctrl = TUL_RD(CurBase + TUL_GCTRL); + + TUL_WR(CurBase + TUL_GCTRL, gctrl | TUL_GCTRL_EEPROM_BIT ); + + + if ( tul_se2_rd_all(CurBase+ TUL_NVRAM) != 1 ) { + + tul_se2_update_all(CurBase+ TUL_NVRAM); /* setup default pattern */ + tul_se2_rd_all(CurBase+ TUL_NVRAM); /* load again */ + } + + /*------ Disable EEProm programming ---*/ + + gctrl = TUL_RD(CurBase + TUL_GCTRL); + + TUL_WR(CurBase + TUL_GCTRL, gctrl & ~TUL_GCTRL_EEPROM_BIT ); + +} /* read_eeprom */ + + +static void tul_stop_bm(I91U_HCS *pHcs) + +{ + + if (TUL_RD(pHcs->HCS_Base + TUL_XStatus) & XPEND) + + { /* if DMA xfer is pending, abort DMA xfer */ + + TUL_WR(pHcs->HCS_Base+ TUL_XCmd, TAX_X_ABT ); + + /* wait Abort DMA xfer done */ + + while ((TUL_RD(pHcs->HCS_Base + TUL_Int) & XABT) == 0); + + } + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + +} + + +/***************************************************************************/ + +static long init_tulip(I91U_HCS *pHcs, I91U_SCB *scbp, int num_scb) +{ + int i; + WORD *pwFlags; + I91U_SCB *pTmpScb; + I91U_SCB *pPrevScb = NULL; + TCS *pTcb; + + pHcs->HCS_SFifo = pHcs->HCS_Base + TUL_SFifo; + pHcs->HCS_SCmd = pHcs->HCS_Base + TUL_SCmd; + + pHcs->HCS_NumScbs = num_scb; + pHcs->HCS_Semaph = 1; + pHcs->HCS_JSStatus0 = 0; + pHcs->HCS_Scb = scbp; + for (i = 0, pTmpScb = scbp; i < num_scb; i++, pTmpScb++) { + pTmpScb->SCB_TagId = i; + pTmpScb->SCB_SGPAddr = (ULONG) vtophys(pTmpScb->SCB_SGList); + if (i != 0) + pPrevScb->SCB_NxtScb = pTmpScb; + pPrevScb = pTmpScb; + } + pPrevScb->SCB_NxtScb = NULL; + + + pHcs->HCS_FirstAvail = scbp; + + pHcs->HCS_LastAvail = pPrevScb; + + + pHcs->HCS_FirstPend = NULL; + pHcs->HCS_LastPend = NULL; + pHcs->HCS_FirstDone = NULL; + pHcs->HCS_LastDone = NULL; + pHcs->HCS_ActScb = NULL; + pHcs->HCS_ActTcs = NULL; + + pHcs->HCS_Intr = TUL_RD(pHcs->HCS_Base + TUL_PINTL); + + tul_read_eeprom( pHcs->HCS_Base ); + /*---------- get H/A configuration -------------*/ + + if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 16) + pHcs->HCS_MaxTar = 16; + else + pHcs->HCS_MaxTar = 8; + + pHcs->HCS_Config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1; + + pHcs->HCS_SCSI_ID = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID; + +#if CHK_PARITY + /* Enable parity error response */ + TUL_WR(pHcs->HCS_Base + TUL_PCMD, TUL_RD(pHcs->HCS_Base + TUL_PCMD) | 0x40); +#endif + + /* Mask all the interrupt */ + TUL_WR(pHcs->HCS_Base + TUL_Mask, 0x1F); + + tul_stop_bm(pHcs); + /* --- Initialize the tulip --- */ + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_RST_CHIP); + + /* program HBA's SCSI ID */ + TUL_WR(pHcs->HCS_Base + TUL_SScsiId, pHcs->HCS_SCSI_ID << 4); + + + /* Enable Initiator Mode ,phase latch,alternate sync period mode, + disable SCSI reset */ + if (pHcs->HCS_Config & HCC_EN_PAR) + pHcs->HCS_SConf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR); + else + pHcs->HCS_SConf1 = (TSC_INITDEFAULT); + TUL_WR(pHcs->HCS_Base + TUL_SConfig, pHcs->HCS_SConf1); + + + + /* selection time out = 250 ms */ + TUL_WR(pHcs->HCS_Base + TUL_STimeOut, 153); + + /*--------- Enable SCSI terminator -----*/ + + TUL_WR(pHcs->HCS_Base + TUL_XCtrl, (pHcs->HCS_Config & (HCC_ACT_TERM1 | HCC_ACT_TERM2))); + TUL_WR(pHcs->HCS_Base + TUL_GCTRL1, + ((pHcs->HCS_Config & HCC_AUTO_TERM) >> 4) | (TUL_RD(pHcs->HCS_Base + TUL_GCTRL1) & 0xFE)); + + pTcb = &pHcs->HCS_Tcs[0]; + for (i = 0, + pwFlags = (WORD *) &(i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config); + i < pHcs->HCS_MaxTar; + i++, pwFlags++, pTcb++ ) + { + pTcb->TCS_Flags = *pwFlags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE); + pTcb->TCS_JS_Period = 0; + pTcb->TCS_SConfig0 = pHcs->HCS_SConf1; + pTcb->TCS_DrvFlags = 0; + pTcb->TCS_TagCnt = 0; + pTcb->TCS_NonTagScb = NULL; + + } /* for */ +#if 0 + printf("iha%d: PCI Base=0x%x, IRQ=%d, SCSI ID=%d\n", + pHcs->HCS_Unit, pHcs->HCS_Base + pHcs->HCS_Intr, + pHcs->HCS_SCSI_ID); +#endif + + /*------------------- reset SCSI Bus ---------------------------*/ + +#if 1 + printf("iha%d: Resetting SCSI Bus ...\n", pHcs->HCS_Unit); + + tul_reset_scsi(pHcs); +#endif + + TUL_WR(pHcs->HCS_Base + TUL_SIntEnable, 0xFF); + return(0); +} + +/***************************************************************************/ + +static I91U_SCB *tul_alloc_scb(I91U_HCS *pHcs) +{ + I91U_SCB *pTmpScb; + ULONG flags; + + flags = splcam(); + if ((pTmpScb = pHcs->HCS_FirstAvail) != NULL) + + { +#if DEBUG_QUEUE + + printf("find scb at %08lx\n", (ULONG) pTmpScb); +#endif + + if ((pHcs->HCS_FirstAvail = pTmpScb->SCB_NxtScb) == NULL) + + pHcs->HCS_LastAvail = NULL; + pTmpScb->SCB_NxtScb = NULL; + pTmpScb->SCB_Status = SCB_RENT; + } + splx(flags); + return (pTmpScb); +} + +/***************************************************************************/ + +static void tul_release_scb(I91U_HCS *pHcs, I91U_SCB *pScb) +{ + ULONG flags; + +#if DEBUG_QUEUE + +printf("Release SCB %lx; ", (ULONG) pScb); + +#endif + + pScb->SCB_Status = 0; + pScb->SCB_NxtScb = NULL; + + flags = splcam(); + if (pHcs->HCS_LastAvail != NULL) { + pHcs->HCS_LastAvail->SCB_NxtScb = pScb; + pHcs->HCS_LastAvail =pScb; + } + else { + pHcs->HCS_FirstAvail = pScb; + pHcs->HCS_LastAvail = pScb; + } + splx(flags); +} + +/***************************************************************************/ + +static void tul_append_pend_scb(I91U_HCS *pHcs, I91U_SCB *scbp) +{ + ULONG flags; + +#if DEBUG_QUEUE + +printf("Append pend SCB %lx; ", (ULONG) scbp); + +#endif + + + scbp->SCB_Status = SCB_PEND; + + scbp->SCB_NxtScb = NULL; + + + flags = splcam(); + if (pHcs->HCS_LastPend != NULL) { + pHcs->HCS_LastPend->SCB_NxtScb = scbp; + + pHcs->HCS_LastPend = scbp; + + } + else { + pHcs->HCS_FirstPend = scbp; + + pHcs->HCS_LastPend = scbp; + + } + splx(flags); +} + +/***************************************************************************/ + +static void tul_push_pend_scb(I91U_HCS *pHcs, I91U_SCB *scbp) + +{ + ULONG flags; + +#if DEBUG_QUEUE + +printf("Push pend SCB %lx; ", (ULONG) scbp); + +#endif + + scbp->SCB_Status = SCB_PEND; + + flags = splcam(); + + if ((scbp->SCB_NxtScb = pHcs->HCS_FirstPend) != NULL) { + pHcs->HCS_FirstPend = scbp; + } + else { + pHcs->HCS_FirstPend = scbp; + pHcs->HCS_LastPend = scbp; + } + splx(flags); +} + +/***************************************************************************/ + +static I91U_SCB *tul_find_pend_scb(I91U_HCS *pHcs) +{ + I91U_SCB *pScb; + TCS *pTcb; + ULONG flags; + + + flags = splcam(); + + pScb = pHcs->HCS_FirstPend; + for ( ;pScb != NULL; pScb = pScb->SCB_NxtScb) + { + pTcb = &pHcs->HCS_Tcs[pScb->SCB_Target]; + + if (pScb->SCB_Opcode == BusDevRst) { + break; + } + if (pScb->SCB_TagMsg) { + if (pTcb->TCS_NonTagScb == NULL) { + break; + } + } + else if (pScb->SCB_Mode == SCM_RSENS) { + break; + } + else if (pScb->SCB_CDB[0] == 0x3) { + break; + } + else if (pTcb->TCS_TagCnt == 0) { + if (pTcb->TCS_NonTagScb == NULL) { + break; + } + } + } /* for */ + + splx(flags); + + return (pScb); +} + + +/***************************************************************************/ + +static I91U_SCB *tul_pop_pend_scb(I91U_HCS *pHcs, I91U_SCB *pActScb) +{ + I91U_SCB *pScb; + I91U_SCB *pNxtScb; + ULONG flags; + + + + flags = splcam(); + + pNxtScb = pActScb->SCB_NxtScb; + pActScb->SCB_NxtScb = NULL; + + pScb = pHcs->HCS_FirstPend; + if (pScb == pActScb) { + if (pNxtScb == NULL) + pHcs->HCS_LastPend = NULL; + pHcs->HCS_FirstPend = pNxtScb; + } + else { + while (pScb) { + if (pScb->SCB_NxtScb == pActScb) { + pScb->SCB_NxtScb = pNxtScb; + if (pActScb == pHcs->HCS_LastPend) + pHcs->HCS_LastPend = pScb; + pScb = pActScb; + break; + } + pScb = pScb->SCB_NxtScb; + } + } + splx(flags); +#if DEBUG_QUEUE +printf("Pop pend SCB %lx; ", (ULONG) pScb); +#endif + return (pScb); +} + +/***************************************************************************/ + +static void tul_append_busy_scb(I91U_HCS *pHcs, I91U_SCB *scbp) +{ + TCS *pTcb = pHcs->HCS_ActTcs; + +#if DEBUG_QUEUE + +printf("append busy SCB %lx; ", (ULONG) scbp); + +#endif + + scbp->SCB_Status = SCB_BUSY; + scbp->SCB_NxtScb = NULL; + + if (scbp->SCB_TagMsg) { + pTcb->TCS_TagCnt++; + } + else { + pTcb->TCS_NonTagScb = scbp; + } +} + +/***************************************************************************/ + +static void tul_unlink_busy_scb(I91U_HCS *pHcs, I91U_SCB *pScb) +{ + TCS *pTcb = &pHcs->HCS_Tcs[pScb->SCB_Target]; + +#if DEBUG_QUEUE +printf("unlink busy SCBs=%x ", (ULONG) pScb); +#endif + + if (pScb->SCB_TagMsg) { + if (pTcb->TCS_TagCnt) + pTcb->TCS_TagCnt--; + } + else if (pTcb->TCS_NonTagScb == pScb) { + pTcb->TCS_NonTagScb = 0; + } + +} + +/***************************************************************************/ + +static void tul_append_done_scb(I91U_HCS *pHcs, I91U_SCB *scbp) +{ +#if 0 + ULONG flags; +#endif + +#if DEBUG_QUEUE +printf("append done SCB %lx; ", (ULONG) scbp); +#endif + + scbp->SCB_Status = SCB_DONE; + +#if 0 + flags = splcam(); +#endif + scbp->SCB_NxtScb = NULL; + if (pHcs->HCS_LastDone != NULL) + { + pHcs->HCS_LastDone->SCB_NxtScb = scbp; + pHcs->HCS_LastDone = scbp; + } + else + { + pHcs->HCS_FirstDone = scbp; + pHcs->HCS_LastDone = scbp; + } +/* splx(flags); */ +} + +/***************************************************************************/ + +static I91U_SCB *tul_find_done_scb(I91U_HCS *pHcs) + +{ + I91U_SCB *pTmpScb; + +#if 0 + + ULONG flags; + + + flags = splcam(); +#endif + + if ((pTmpScb = pHcs->HCS_FirstDone) != NULL) + + { + if ((pHcs->HCS_FirstDone = pTmpScb->SCB_NxtScb) == NULL) + + pHcs->HCS_LastDone = NULL; + pTmpScb->SCB_NxtScb = NULL; + } + +#if 0 + splx(flags); +#endif + +#if DEBUG_QUEUE +printf("find done SCB %lx; ", (ULONG) pTmpScb); +#endif + return (pTmpScb); +} + +/***************************************************************************/ +static I91U_SCB *tul_abort_ccb(I91U_HCS *pHcs, ULONG ccb) + +{ + I91U_SCB *pScb, *pPrevScb; + ULONG i; + int flags; + + flags = splcam(); + + pPrevScb = NULL; + pScb = pHcs->HCS_FirstPend; /* Check Pend queue */ + while (pScb != NULL) { + if (pScb->SCB_ccb == ccb) { + if (pPrevScb == NULL) { + if ((pHcs->HCS_FirstPend = pScb->SCB_NxtScb) == NULL) + + pHcs->HCS_LastPend = NULL; + + } + else { + pPrevScb->SCB_NxtScb = pScb->SCB_NxtScb; + if (pScb == pHcs->HCS_LastPend) + pHcs->HCS_LastPend = pPrevScb; + } + + pScb->SCB_NxtScb = NULL; + tul_release_scb(pHcs, pScb); + + splx(flags); + return (pScb); + } + + pPrevScb = pScb; + pScb = pScb->SCB_NxtScb; + + } + + pScb = pHcs->HCS_Scb ; + for (i = 0; i < pHcs->HCS_NumScbs; i++, pScb++) { + if (pScb->SCB_Status & SCB_BUSY) + if (pScb->SCB_ccb == ccb) { + tul_unlink_busy_scb(pHcs, pScb); + + tul_release_scb(pHcs, pScb); + splx(flags); + return (pScb); + } + } + splx(flags); + return (NULL); +} + +/***************************************************************************/ + +static long tul_bad_seq(I91U_HCS *pHcs) + +{ + I91U_SCB *pScb; + + if ((pScb = pHcs->HCS_ActScb) != NULL) + + { + + + tul_unlink_busy_scb(pHcs, pScb); + + + pScb->SCB_HaStat = HOST_BAD_PHAS; + + pScb->SCB_TaStat = 0; + + + tul_append_done_scb(pHcs, pScb); + + } + + tul_stop_bm(pHcs); + + tul_reset_scsi(pHcs); + + return (tul_post_scsi_rst(pHcs)); +} + +/************************************************************************/ +static void tul_exec_scb(I91U_HCS *pHcs, I91U_SCB *pScb) +{ + ULONG flags; + + +#if 0 +printf("Enter tul_exec_scb %x %x ", pScb->SCB_Target, pScb->SCB_CDB[0]); +tul_do_pause(1000); +#endif + + pScb->SCB_Mode = 0; + + pScb->SCB_SGIdx = 0; + pScb->SCB_SGMax = pScb->SCB_SGLen; + + if (pScb->SCB_Opcode == BusDevRst) { /* bus_dev_reset */ + + tul_push_pend_scb(pHcs, pScb); /* Insert this SCB to Pending queue */ + } + else if (pScb->SCB_CDB[0] == 0x3) { /* request sense command */ + + pScb->SCB_Ident &= 0xBF; /* no disconnect */ + + tul_push_pend_scb(pHcs, pScb); /* Insert this SCB to Pending queue */ + } + else { + + tul_append_pend_scb(pHcs, pScb); /* Append this SCB to Pending queue */ + } + + + flags = splcam(); + if (pHcs->HCS_Semaph == 1) { + TUL_WR(pHcs->HCS_Base + TUL_Mask, 0x1F); + /* disable SCSI Int */ + pHcs->HCS_Semaph = 0; + + splx(flags); + + tulip_main(pHcs); + + flags = splcam(); + pHcs->HCS_Semaph = 1; + TUL_WR(pHcs->HCS_Base + TUL_Mask, 0x0F); + /* Enable SCSI Int */ + } + splx(flags); +} + +/***************************************************************************/ + +static long tul_isr(I91U_HCS *pHcs) + +{ + BYTE stat; + + + + stat = TUL_RD(pHcs->HCS_Base + TUL_SStatus0); +#if DEBUG_INTERRUPT + printf("SCSI status = %x", stat); + +#endif + if (stat & TSS_INT_PENDING) { + if (pHcs->HCS_Semaph == 1) { + TUL_WR(pHcs->HCS_Base + TUL_Mask, 0x1F); /* Disable SCSI Int */ + pHcs->HCS_Semaph = 0; + + tulip_main(pHcs); + + pHcs->HCS_Semaph = 1; + TUL_WR(pHcs->HCS_Base + TUL_Mask, 0x0F); + /* Enable SCSI Int */ + + return 1; + } + return 0; /* 08/11/95 */ + } + return 0; /* 08/11/95 */ +} + +/***************************************************************************/ + +static long tulip_main(I91U_HCS *pHcs) +{ + I91U_SCB *pScb; + TCS *pTcb; + +/*printf("Enter tulip_main\n");*/ + for (;;) { + tulip_scsi(pHcs); /* Call tulip_scsi */ + while ((pScb = tul_find_done_scb(pHcs)) != NULL) + {/* find done entry */ + if (!(pScb->SCB_Mode & SCM_RSENS)) + { /* not in auto req. sense mode*/ + + if (pScb->SCB_TaStat == 2) + { + pTcb = &pHcs->HCS_Tcs[pScb->SCB_Target]; + pTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE); /* clr sync. nego flag */ + if (pScb->SCB_Flags & SCF_SENSE) + { + pScb->SCB_BufLen = pScb->SCB_SenseLen; + pScb->SCB_BufPtr = pScb->SCB_SensePtr; + pScb->SCB_Flags &= ~(SCF_SG|SCF_DIR); /* for xfer_data_in */ + /* so, we won't report worng direction in xfer_data_in, + and won't report HOST_DO_DU in state_6 */ + pScb->SCB_Ident &= 0xBF; /* disconnect disable */ + pScb->SCB_TagMsg = 0; /* non-tag */ + pScb->SCB_Mode = SCM_RSENS; + pScb->SCB_TaStat = 0; + pScb->SCB_CDBLen = 6; + pScb->SCB_CDB[0] = SCSICMD_RequestSense; + pScb->SCB_CDB[1] = 0; + pScb->SCB_CDB[2] = 0; + pScb->SCB_CDB[3] = 0; + pScb->SCB_CDB[4] = pScb->SCB_SenseLen; + pScb->SCB_CDB[5] = 0; + tul_push_pend_scb(pHcs, pScb); + break; + } + } + } + else + { /* in request sense mode */ + + if (pScb->SCB_TaStat == 2) + { /* check contition status again after sending + requset sense cmd 0x3*/ + + pScb->SCB_HaStat = HOST_BAD_PHAS; + + } + pScb->SCB_TaStat = 2; + } + pScb->SCB_Flags |= SCF_DONE; + if (pScb->SCB_Flags & SCF_POST) + (*pScb->SCB_Post)((BYTE *) pHcs, (BYTE *) pScb); + } /* while */ + /* find_active: */ + if (TUL_RD(pHcs->HCS_Base + TUL_SStatus0) & TSS_INT_PENDING) + continue; + + if (pHcs->HCS_ActScb) /* return to OS and wait for xfer_done_ISR/Selected_ISR */ + return 1; /* return to OS, enable interrupt */ + /* Check pending I91U_SCB */ + if (tul_find_pend_scb(pHcs) == NULL) { + return 1; /* return to OS, enable interrupt */ + } + } /* End of for loop */ + /* statement won't reach here */ + +} + + + + + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +/***************************************************************************/ + +/***************************************************************************/ + +/***************************************************************************/ + +/***************************************************************************/ + + +/***************************************************************************/ + +static void tulip_scsi(I91U_HCS *pHcs) +{ + I91U_SCB *pScb; + + TCS *pTcb; + BYTE stat; + +/* printf("Enter tulip_scsi()\n");*/ + /* make sure to service interrupt asap */ + if ((stat = TUL_RD(pHcs->HCS_Base + TUL_SStatus0)) & TSS_INT_PENDING) { + pHcs->HCS_JSStatus0 = stat; + pHcs->HCS_Phase = stat & TSS_PH_MASK; + pHcs->HCS_JSStatus1 = TUL_RD(pHcs->HCS_Base + TUL_SStatus1); + pHcs->HCS_JSInt = TUL_RD(pHcs->HCS_Base + TUL_SInt); +/* printf("SCSI status = %x\n", stat); + printf("SCSI status 1 = %x\n", pHcs->HCS_JSStatus1); + printf("SCSI interrupt = %x\n", pHcs->HCS_JSInt);*/ + if (pHcs->HCS_JSInt & TSS_SCSIRST_INT) + + { /* SCSI bus reset detected */ + + int_tul_scsi_rst(pHcs); + + return; + + } + + if (pHcs->HCS_JSInt & TSS_RESEL_INT) { /* reselected interrupt */ + int_tul_resel(pHcs); + return; + } + + if (pHcs->HCS_JSInt & TSS_SEL_TIMEOUT) { + int_tul_busfree(pHcs); + return; + } + + if (pHcs->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */ + int_tul_busfree(pHcs); /* unexpected bus free or sel timeout */ + return; + } + + if (pHcs->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) { /* func complete or Bus service */ + + if ((pScb = pHcs->HCS_ActScb) != NULL) + tul_next_state(pHcs); + return; + } + + if (pHcs->HCS_JSInt & TSS_SEL_INT) { /* */ + TUL_WR(pHcs->HCS_Base + TUL_SSignal, 0); + } + } + + if (pHcs->HCS_ActScb != NULL) + return; + + if ((pScb = tul_find_pend_scb(pHcs)) == NULL) + return; + + pTcb = &pHcs->HCS_Tcs[pScb->SCB_Target]; + /* program HBA's SCSI ID & target SCSI ID */ + pHcs->HCS_ActTcs = pTcb ; + TUL_WR( pHcs->HCS_Base + TUL_SScsiId, + (pHcs->HCS_SCSI_ID << 4) | (pScb->SCB_Target & 0x0F) ); + if (pScb->SCB_Opcode == ExecSCSI) { + + TUL_WR(pHcs->HCS_Base + TUL_SPeriod, pTcb->TCS_JS_Period); +/*printf("TCS_Flags = %x\n", pTcb->TCS_Flags); + +do_pause(15000);*/ + + if ((pTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) { /* do wdtr negotiation */ + + tul_select_atn_stop(pHcs, pScb); + + } + else if ((pTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { /* do sync negotiation */ + + tul_select_atn_stop(pHcs, pScb); + + } + else if (pScb->SCB_TagMsg) + tul_select_atn3(pHcs, pScb); + else + tul_select_atn(pHcs, pScb); + + if (pScb->SCB_Flags & SCF_POLL) { + while (wait_tulip(pHcs) != -1) { + if (tul_next_state(pHcs) == -1) + break; + } + } + + } + else if (pScb->SCB_Opcode == BusDevRst) { + tul_select_atn_stop(pHcs, pScb); + pScb->SCB_NxtStat = 8; + if (pScb->SCB_Flags & SCF_POLL) { + while (wait_tulip(pHcs) != -1) { + if (tul_next_state(pHcs) == -1) + break; + + } + } + } + else { + tul_pop_pend_scb(pHcs, pScb); + + pScb->SCB_HaStat = HOST_INV_CMD ; /* bad command */ + + tul_append_done_scb(pHcs, pScb); + + } +} + + +/***************************************************************************/ + +static long tul_next_state(I91U_HCS *pHcs) +{ + I91U_SCB *pScb = pHcs->HCS_ActScb; + TCS *pTcb = pHcs->HCS_ActTcs; + int next = pScb->SCB_NxtStat; +#if 0 + int i; +#endif + + switch (next) { + + case 1: { + if (pScb != tul_pop_pend_scb(pHcs, pScb)) { + printf("iha:Differnet SCB state 1\n"); + + } + tul_append_busy_scb(pHcs, pScb); + + TUL_WR(pHcs->HCS_Base + TUL_SConfig, pTcb->TCS_SConfig0); + /* ATN on */ + if (pHcs->HCS_Phase == MSG_OUT) { + TUL_WR(pHcs->HCS_Base+TUL_SCtrl1, (TSC_EN_BUS_IN|TSC_HW_RESELECT)); + + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_Ident); + + if (pScb->SCB_TagMsg) { + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_TagMsg); + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_TagId); + } + + if ((pTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) { + pTcb->TCS_Flags |= TCF_WDTR_DONE; + TUL_WR(pHcs->HCS_SFifo, MSG_EXTEND); + TUL_WR(pHcs->HCS_SFifo, 2); /* Extended message length*/ + TUL_WR(pHcs->HCS_SFifo, 3); /* Sync request*/ + TUL_WR(pHcs->HCS_SFifo, 1); /* Start from 16 bits xfer*/ + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + if (wait_tulip(pHcs) == -1) + return(-1); + else { + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + TUL_WR(pHcs->HCS_Base + TUL_SSignal, (TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7))); + goto state_3; + } + } + else { + if ((pTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { + if (tul_msgout_sync(pHcs) == -1) + return(-1); + } + goto state_3; + } + } + else { + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + TUL_WR(pHcs->HCS_Base + TUL_SSignal, (TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7))); + goto state_3; + } + } + + case 2: { +#if DEBUG_STATE +printf("-s2-"); +#endif + if (pScb != tul_pop_pend_scb(pHcs, pScb)) { + printf("iha: Differnet SCB state 2\n"); + } +/* pScb->SCB_Status = SCB_BUSY; */ + tul_append_busy_scb(pHcs, pScb); + + TUL_WR(pHcs->HCS_Base + TUL_SConfig, pTcb->TCS_SConfig0); + + if ( pHcs->HCS_JSStatus1 & TSS_CMD_PH_CMP) { + goto state_4; + } + /* clear ATN */ + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, (TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7))); +/* goto state_3; */ + } + + case 3: { +state_3: + +#if DEBUG_STATE +print("-s3-"); +#endif + for (;;) { + switch (pHcs->HCS_Phase) { + + case CMD_OUT: /* Command out phase */ +#if 0 + for ( i = 0; i < (int) pScb->SCB_CDBLen; i++) + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_CDB[i]); +#else + outsb(pHcs->HCS_SFifo, pScb->SCB_CDB, pScb->SCB_CDBLen); +#endif + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + if (wait_tulip(pHcs) == -1) + return (-1); + + if (pHcs->HCS_Phase == CMD_OUT) { + + return (tul_bad_seq(pHcs)); + + } + + goto state_4; + + case MSG_IN: /* Message in phase */ + pScb->SCB_NxtStat = 3; + if (tul_msgin(pHcs) == -1) + return (-1); + break; + + case STATUS_IN: /* Status phase */ + if (tul_status_msg(pHcs) == -1) + return (-1); + break; + + case MSG_OUT: /* Message out phase */ + if (pTcb->TCS_Flags & (TCF_SYNC_DONE|TCF_NO_SYNC_NEGO)) { + if (tul_msgout_nop(pHcs) == -1) + return (-1); + } else { + if (tul_msgout_sync(pHcs) == -1) + return(-1); + } + break; + + default: + return (tul_bad_seq(pHcs)); + } + } + } + + case 4: +state_4: +#if DEBUG_STATE +print("-s4-"); +#endif + if ((pScb->SCB_Flags & SCF_DIR) == SCF_NO_XF) { + goto state_6; /* Go to state 6 */ + } + + for (;;) { + if (pScb->SCB_BufLen == 0) + goto state_6; /* Go to state 6 */ + switch (pHcs->HCS_Phase) { + case STATUS_IN: /* Status phase */ + if ((pScb->SCB_Flags & SCF_DIR) != 0) { + /* if direction bit set then report data underrun */ + + /* XXX commented out to avoid CAM error */ + /* XXX when booting with NO media in CD-ROM. */ + /* XXX Is this right? */ + /* pScb->SCB_HaStat = HOST_DO_DU; */ + + } + if ((tul_status_msg(pHcs)) == -1) + + return (-1); + + break; + case MSG_IN: /* Message in phase */ + pScb->SCB_NxtStat = 4; + + if (tul_msgin(pHcs) == -1) + return (-1); + break; + + case MSG_OUT: /* Message out phase */ + if (pHcs->HCS_JSStatus0 & TSS_PAR_ERROR) { + pScb->SCB_BufLen = 0; + pScb->SCB_HaStat = HOST_DO_DU; + if (tul_msgout_ide(pHcs) == -1) + return (-1); + goto state_6; /* Go to state 6 */ + } else { + if (tul_msgout_nop(pHcs) == -1) + return (-1); + } + break; + + case DATA_IN: /* Data in phase */ + return (tul_xfer_data_in(pHcs)); + + case DATA_OUT: /* Data out phase */ + return (tul_xfer_data_out(pHcs)); + case CMD_OUT: /* Command out phase */ + default: + return (tul_bad_seq(pHcs)); + } + } + + case 5: + if ((next = tul_state_5(pHcs)) == -1) + return -1; + if (next == 4) + goto state_4; + + case 6: +state_6: +#if DEBUG_STATE + +print("-s6-"); + +#endif + + for (;;) { + switch (pHcs->HCS_Phase) { + case STATUS_IN: /* Status phase */ + if (tul_status_msg(pHcs) == -1) + return (-1); + break; + + case MSG_IN: /* Message in phase */ + pScb->SCB_NxtStat = 6; + if ((tul_msgin(pHcs)) == -1) + return (-1); + break; + case MSG_OUT: /* Message out phase */ + if ((tul_msgout_nop(pHcs)) == -1) + + return (-1); + break; + + case DATA_IN: /* Data in phase */ + if (tul_xpad_in(pHcs) == -1) + return (-1); + break; + + case DATA_OUT: /* Data out phase */ + if (tul_xpad_out(pHcs) == -1) + return (-1); + break; + + default: + return (tul_bad_seq(pHcs)); + } + } + + case 8: { + ULONG i; + BYTE tar; + + if (pScb != tul_pop_pend_scb(pHcs, pScb)) { + printf("Differnet SCB state 1\n"); + + } + + if (pHcs->HCS_Phase != MSG_OUT) { + return (tul_bad_seq(pHcs)); /* Unexpected phase */ + } + + TUL_WR(pHcs->HCS_SFifo, MSG_DEVRST); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + + pScb->SCB_HaStat = 0; + tul_append_done_scb(pHcs, pScb); + + pTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE); + pTcb->TCS_JS_Period = 0; + pTcb->TCS_SConfig0 = pHcs->HCS_SConf1; + pTcb->TCS_TagCnt = 0; + pTcb->TCS_NonTagScb = NULL; + + /* abort all SCB with same target */ + + tar = pScb->SCB_Target; /* target */ + + pScb = pHcs->HCS_Scb ; + for (i = 0; i < pHcs->HCS_NumScbs; i++, pScb++) { + if ((pScb->SCB_Status & SCB_BUSY) && + (pScb->SCB_Target == tar) ) { + tul_unlink_busy_scb(pHcs, pScb); + + pScb->SCB_HaStat = HOST_DEV_RST; + tul_append_done_scb(pHcs, pScb); + } + } + + pHcs->HCS_Flags |= HCF_EXPECT_DISC; + if (wait_tulip(pHcs) == -1) { + return (-1); + } + /* Unexpected phase */ + } + + default: + return (tul_bad_seq(pHcs)); + } +} + + + +/***************************************************************************/ +/* state after dma xfer done or phase change before xfer done */ +static long tul_state_5(I91U_HCS *pHcs) +{ + + I91U_SCB *pScb = pHcs->HCS_ActScb; + TCS *pTcb = pHcs->HCS_ActTcs; + long cnt, xcnt; /* cannot use unsigned !! code: if (xcnt < 0) */ + + + +#if DEBUG_STATE + +print("-s5-"); + +#endif + + + /*------ get remaining count -------*/ + + cnt = TUL_RDLONG(pHcs->HCS_Base + TUL_SCnt0) & 0x0FFFFFF; + +/*print("Remaining SCSI Count = %lx\n", cnt);*/ + if (TUL_RD(pHcs->HCS_Base + TUL_XCmd) & 0x20) + + { + + /* ----------------------- DATA_IN -----------------------------*/ + + /* check scsi parity error */ + + if (pHcs->HCS_JSStatus0 & TSS_PAR_ERROR) { + pScb->SCB_HaStat = HOST_DO_DU; + } + + if (TUL_RD(pHcs->HCS_Base + TUL_XStatus) & XPEND) + + { /* DMA xfer pending, Send STOP */ + + /* tell Hardware scsi xfer has been terminated */ + + TUL_WR(pHcs->HCS_Base + TUL_XCtrl, TUL_RD(pHcs->HCS_Base + TUL_XCtrl) | 0x80); + + /* wait until DMA xfer not pending */ + + while (TUL_RD(pHcs->HCS_Base + TUL_XStatus) & XPEND ); + + } + + } + + else + + { /*-------- DATA OUT -----------*/ + + if ((TUL_RD(pHcs->HCS_Base + TUL_SStatus1) & TSS_XFER_CMP) == 0) + + { + + if (pTcb->TCS_JS_Period & TSC_WIDE_SCSI) + + cnt += (TUL_RD(pHcs->HCS_Base + TUL_SFifoCnt) & 0x1F) << 1; + + else + + cnt += (TUL_RD(pHcs->HCS_Base + TUL_SFifoCnt) & 0x1F); + + } + + if (TUL_RD(pHcs->HCS_Base + TUL_XStatus) & XPEND) + + { /* if DMA xfer is pending, abort DMA xfer */ + + TUL_WR(pHcs->HCS_Base + TUL_XCmd, TAX_X_ABT ); + + /* wait Abort DMA xfer done */ + + while ((TUL_RD(pHcs->HCS_Base + TUL_Int) & XABT) == 0); + + } + + if ((cnt == 1) && (pHcs->HCS_Phase == DATA_OUT)) { + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + if (wait_tulip(pHcs) == -1) { + return (-1); + } + + cnt = 0; + } + + else + + { + + if ((TUL_RD(pHcs->HCS_Base + TUL_SStatus1) & TSS_XFER_CMP) == 0) + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + + } + + } + + + + if (cnt == 0) { + pScb->SCB_BufLen = 0; + return (6); /* Go to state 6 */ + + } + /* Update active data pointer */ + + xcnt = pScb->SCB_BufLen - cnt; /* xcnt== bytes already xferred */ + + pScb->SCB_BufLen = cnt; /* cnt == bytes left to be xferred */ + + if (pScb->SCB_Flags & SCF_SG) + { + register I91U_SG *sgp; + + ULONG i; + + + sgp = &pScb->SCB_SGList[pScb->SCB_SGIdx]; + + for (i = pScb->SCB_SGIdx; i < pScb->SCB_SGMax; sgp++, i++) + + { + + xcnt -= sgp->SG_Len; + + if (xcnt < 0) + + { /* this sgp xfer half done */ + + xcnt += sgp->SG_Len; /* xcnt == bytes xferred in this sgp */ + + sgp->SG_Ptr += (ULONG)xcnt; /* new ptr to be xfer */ + + sgp->SG_Len -= (ULONG)xcnt; /* new len to be xfer */ + + pScb->SCB_BufPtr += ((ULONG)(i - pScb->SCB_SGIdx) << 3); + + /* new SG table ptr */ + + pScb->SCB_SGLen = (BYTE)(pScb->SCB_SGMax - i); + + /* new SG table len */ + + pScb->SCB_SGIdx = (WORD)i; + + /* for next disc and come in this loop*/ + + return (4); /* Go to state 4 */ + + } + + /* else (xcnt >= 0 , i.e. this sgp already xferred */ + + } /* for */ + + return (6); /* Go to state 6 */ + + } + else { + pScb->SCB_BufPtr += xcnt; + + } + return (4); /* Go to state 4 */ + +} + + +/***************************************************************************/ + +static long tul_xfer_data_in(I91U_HCS *pHcs) + +{ + + I91U_SCB *pScb = pHcs->HCS_ActScb; + + +/*print("\nEnter xfer data in; ptr = %lx; cnt = %lx\n", pScb->SCB_BufPtr, + + pScb->SCB_BufLen);*/ + + if ((pScb->SCB_Flags & SCF_DIR) == SCF_DOUT) { + + return (6); /* wrong direction */ + + } + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, pScb->SCB_BufLen); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_DMA_IN); /* 7/25/95 */ + + + if (pScb->SCB_Flags & SCF_SG) { /* S/G xfer */ + TUL_WRLONG(pHcs->HCS_Base + TUL_XCntH, ((ULONG)pScb->SCB_SGLen) << 3); + + TUL_WRLONG(pHcs->HCS_Base + TUL_XAddH, pScb->SCB_BufPtr); + + TUL_WR(pHcs->HCS_Base + TUL_XCmd, TAX_SG_IN); + + } else { + + TUL_WRLONG(pHcs->HCS_Base + TUL_XCntH, pScb->SCB_BufLen); + + TUL_WRLONG(pHcs->HCS_Base + TUL_XAddH, pScb->SCB_BufPtr); + + TUL_WR(pHcs->HCS_Base + TUL_XCmd, TAX_X_IN); + + } + + pScb->SCB_NxtStat = 5; + return (0); /* return to OS, wait xfer done , let jas_isr come in */ + +} + + +/***************************************************************************/ + +static long tul_xfer_data_out(I91U_HCS *pHcs) + +{ + + I91U_SCB *pScb = pHcs->HCS_ActScb; + + +/*print("Enter xfer data out\n");*/ + + if ((pScb->SCB_Flags & SCF_DIR) == SCF_DIN) { + + return (6); /* wrong direction */ + + } + + + + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, pScb->SCB_BufLen); + + + if (pScb->SCB_Flags & SCF_SG) { /* S/G xfer */ + + TUL_WRLONG(pHcs->HCS_Base + TUL_XCntH, ((ULONG)pScb->SCB_SGLen) << 3); + + TUL_WRLONG(pHcs->HCS_Base + TUL_XAddH, pScb->SCB_BufPtr); + + TUL_WR(pHcs->HCS_Base + TUL_XCmd, TAX_SG_OUT); + + } else { + + TUL_WRLONG(pHcs->HCS_Base + TUL_XCntH, pScb->SCB_BufLen); + + TUL_WRLONG(pHcs->HCS_Base + TUL_XAddH, pScb->SCB_BufPtr); + + TUL_WR(pHcs->HCS_Base + TUL_XCmd, TAX_X_OUT); + + } + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_DMA_OUT); + + pScb->SCB_NxtStat = 5; + return (0); /* return to OS, wait xfer done , let jas_isr come in */ +} + + +/***************************************************************************/ + +static long tul_xpad_in(I91U_HCS *pHcs) +{ + I91U_SCB *pScb = pHcs->HCS_ActScb; + TCS *pTcb = pHcs->HCS_ActTcs; + int phase; + + + if ((pScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) { + pScb->SCB_HaStat = HOST_DO_DU; /* over run */ + + } + + for (;;) { + + if (pTcb->TCS_JS_Period & TSC_WIDE_SCSI) + + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 2); + + else + + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 1); + + + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_IN); + + if ((phase = wait_tulip(pHcs)) == -1) + return (-1); + + if (phase != DATA_IN) { + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + return (6); + } +/* TTT TUL_RD(pHcs->HCS_SFifo); */ + + } + +} + +static long tul_xpad_out(I91U_HCS *pHcs) +{ + I91U_SCB *pScb = pHcs->HCS_ActScb; + TCS *pTcb = pHcs->HCS_ActTcs; + int phase; + + if ((pScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) { + pScb->SCB_HaStat = HOST_DO_DU; /* over run */ + } + for (;;) { + if (pTcb->TCS_JS_Period & TSC_WIDE_SCSI) + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 2); + else + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 1); + + TUL_WR(pHcs->HCS_SFifo, 0); + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + if ((phase = wait_tulip(pHcs)) == -1) + return (-1); + + if (phase != DATA_OUT) + { /* Disable wide CPU to allow read 16 bits */ + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + return (6); + } + } +} + + +/***************************************************************************/ + +static long tul_status_msg(I91U_HCS *pHcs) /* status & MSG_IN */ +{ + I91U_SCB *pScb = pHcs->HCS_ActScb; + char phase; + BYTE msg; + + TUL_WR(pHcs->HCS_SCmd, TSC_CMD_COMP); + if ((phase = wait_tulip(pHcs)) == -1) { + return (-1); + } + + /* get status */ + pScb->SCB_TaStat = TUL_RD(pHcs->HCS_SFifo); +#if 0 + phase = pHcs->HCS_Phase = TUL_RD(pHcs->HCS_Base + TUL_SSignal) & 0x07; + +#endif + + if (phase == MSG_OUT) { + if (pHcs->HCS_JSStatus0 & TSS_PAR_ERROR) { + TUL_WR(pHcs->HCS_SFifo, MSG_PARITY); + } + else { + TUL_WR(pHcs->HCS_SFifo, MSG_NOP); + + } + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + return (wait_tulip(pHcs)); + + } + + if (phase == MSG_IN) { + msg = TUL_RD(pHcs->HCS_SFifo); + + if (pHcs->HCS_JSStatus0 & TSS_PAR_ERROR) { /* Parity error */ + if ((phase = tul_msgin_accept(pHcs)) == -1) + return (-1); + if (phase != MSG_OUT) + return (tul_bad_seq(pHcs)); + TUL_WR(pHcs->HCS_SFifo, MSG_PARITY); + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + return (wait_tulip(pHcs)); + } + + if (msg == 0) { /* Command complete */ + if ((pScb->SCB_TaStat & 0x18) == 0x10) { /* No link support */ + return (tul_bad_seq(pHcs)); + } + pHcs->HCS_Flags |= HCF_EXPECT_DONE_DISC; + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + + TUL_WR(pHcs->HCS_SCmd, TSC_MSG_ACCEPT); + + return(wait_tulip(pHcs)); + + } + + if ((msg == MSG_LINK_COMP) || (msg == MSG_LINK_FLAG)) + + { + + if ((pScb->SCB_TaStat & 0x18) == 0x10) + + return (tul_msgin_accept(pHcs)); + + } + + } + + return (tul_bad_seq(pHcs)); + +} + + + + + +/***************************************************************************/ + +/* scsi bus free */ +static long int_tul_busfree(I91U_HCS *pHcs) +{ + I91U_SCB *pScb = pHcs->HCS_ActScb; + + if (pScb != NULL) + { + if (pScb->SCB_Status & SCB_SELECT) { /* selection timeout */ + if (pScb != tul_pop_pend_scb(pHcs, pScb)) { + printf("iha: Differnet SCB\n"); + } + pScb->SCB_HaStat = HOST_SEL_TOUT; + tul_append_done_scb(pHcs, pScb); + } + else { /* Unexpected bus free */ + tul_unlink_busy_scb(pHcs, pScb); + + pScb->SCB_HaStat = HOST_BUS_FREE; + tul_append_done_scb(pHcs, pScb); + } + + pHcs->HCS_ActScb = NULL; +/* pHcs->HCS_ActTcs = NULL; */ + } + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */ + TUL_WR(pHcs->HCS_Base + TUL_SConfig, TSC_INITDEFAULT); + TUL_WR(pHcs->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);/* Enable HW reselect */ + return (-1); +} + + +/***************************************************************************/ + +/* scsi bus reset */ +static long int_tul_scsi_rst(I91U_HCS *pHcs) +{ + I91U_SCB *pScb; + + int i; + TCS *pTcb; + + /* if DMA xfer is pending, abort DMA xfer */ + + if (TUL_RD(pHcs->HCS_Base + TUL_XStatus) & 0x01) + + { + + TUL_WR(pHcs->HCS_Base + TUL_XCmd, TAX_X_ABT ); + + /* wait Abort DMA xfer done */ + + while ((TUL_RD(pHcs->HCS_Base + TUL_Int) & 0x04) == 0) + + ; + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + + } + + + /* Abort all active & disconnected scb */ + pScb = pHcs->HCS_Scb ; + for (i = 0; i < pHcs->HCS_NumScbs; i++, pScb++) + { + if (pScb->SCB_Status & SCB_BUSY ) + { + tul_unlink_busy_scb(pHcs, pScb); + + pScb->SCB_HaStat = HOST_SCSI_RST; + tul_append_done_scb(pHcs, pScb); + } + } + + pHcs->HCS_ActScb = NULL; + + + /* clr sync nego. done flag */ + + pTcb = &pHcs->HCS_Tcs[0]; + + for (i = 0; i < pHcs->HCS_MaxTar; i++,pTcb++ ) + { + pTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE); + pTcb->TCS_JS_Period = 0; + pTcb->TCS_SConfig0 = pHcs->HCS_SConf1; + pTcb->TCS_TagCnt = 0; + pTcb->TCS_NonTagScb = NULL; + } + return(-1); +} + +#if 0 +/***************************************************************************/ + +static long tul_msgin_par_err(I91U_HCS *pHcs) + +{ + + int phase = 0; + + + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + + if ((phase = tul_msgin_accept(pHcs)) == -1) + + return (-1); + + if (phase == MSG_OUT) + + { /* Assert attention */ + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, ((TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN)); + + TUL_WR(pHcs->HCS_SFifo, MSG_PARITY); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + if ((phase = wait_tulip(pHcs)) == -1) + + return (-1); + + if (phase == MSG_IN) + + { + + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 1); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_IN); + + if ((phase = wait_tulip(pHcs)) == -1) + + return (-1); + + if ((pHcs->HCS_JSStatus0 & TSS_PAR_ERROR) == 0) + + return (phase); + + } + + } + + return (tul_bad_seq(pHcs)); + +} + +#endif + + +/***************************************************************************/ + +/* scsi reselection */ + +static long int_tul_resel(I91U_HCS *pHcs) + +{ + I91U_SCB *pScb; + TCS *pTcb; + int phase; + + BYTE tag; + + BYTE msg = 0; + + WORD tar, lun; + + if ((pScb = pHcs->HCS_ActScb) != NULL) + { + if (pScb->SCB_Status & SCB_SELECT) + { /* if waiting for selection complete*/ + pScb->SCB_Status &= ~SCB_SELECT; + } + pHcs->HCS_ActScb = NULL; + } + + /* --------- get target id---------------------- */ + tar = TUL_RD(pHcs->HCS_Base + TUL_SBusId); + /* ------ get LUN from Identify message----------- */ + lun = TUL_RD(pHcs->HCS_Base + TUL_SIdent) & 0x1F; /* 10/21/97 from 0x07 -> 0x1f */ + + pTcb = &pHcs->HCS_Tcs[tar]; + pHcs->HCS_ActTcs = pTcb; + TUL_WR(pHcs->HCS_Base + TUL_SConfig, pTcb->TCS_SConfig0); + TUL_WR(pHcs->HCS_Base + TUL_SPeriod, pTcb->TCS_JS_Period); + + + /* ------------- tag queueing ? ------------------- */ + if (pTcb->TCS_NonTagScb == NULL) { +/*printf("Tag enabled\n");*/ + if ((phase = tul_msgin_accept(pHcs)) == -1) + return (-1); + if (phase != MSG_IN) + goto no_tag; + + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 1); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_IN); + if ((phase = wait_tulip(pHcs)) == -1) + return (-1); + msg = TUL_RD(pHcs->HCS_SFifo); /* Read Tag Message */ + + if ((msg < MSG_STAG) || (msg > MSG_OTAG)) /* Is simple Tag */ + goto no_tag; + + if ((phase = tul_msgin_accept(pHcs)) == -1) + return (-1); + + if (phase != MSG_IN) + goto no_tag; + + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 1); + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_IN); + if ((phase = wait_tulip(pHcs)) == -1) + return (-1); + tag = TUL_RD(pHcs->HCS_SFifo); /* Read Tag ID */ + pScb = pHcs->HCS_Scb + tag; + if ((pScb->SCB_Target != tar) || (pScb->SCB_Lun != lun)) + { + return tul_msgout_abort_tag(pHcs); + } + if (pScb->SCB_Status != SCB_BUSY) + { /* 03/24/95 */ + + return tul_msgout_abort_tag(pHcs); + } + pHcs->HCS_ActScb = pScb; + if ((phase = tul_msgin_accept(pHcs)) == -1) + return (-1); + } + else /* No tag */ + { +/*printf("tarlun= %x\n", tarlun);*/ + pScb = pTcb->TCS_NonTagScb; + if ((pScb->SCB_Status != SCB_BUSY)|| (pScb->SCB_Lun != lun)) + { +/*printf("SCB wrong lun\n");*/ +no_tag: + return tul_msgout_abort_targ(pHcs); + } + pHcs->HCS_ActScb = pScb; + if ((phase = tul_msgin_accept(pHcs)) == -1) + return (-1); + } + return(tul_next_state(pHcs)); +} + + + +/***************************************************************************/ +static long tul_msgout_abort_targ(I91U_HCS *pHcs) +{ + int phase; + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, ((TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN)); + phase = tul_msgin_accept(pHcs); + if (phase == -1) + return(-1); + if (phase != MSG_OUT) + return(tul_bad_seq(pHcs)); + + TUL_WR(pHcs->HCS_SFifo, MSG_ABORT); + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + pHcs->HCS_Flags |= HCF_EXPECT_DISC; + if (wait_tulip(pHcs) != -1) { + return (tul_bad_seq(pHcs)); + } + return -1; +} + +/***************************************************************************/ + +static long tul_msgout_abort_tag(I91U_HCS *pHcs) + +{ + int phase; + + + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, ((TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN)); + + phase = tul_msgin_accept(pHcs); + + if (phase == -1) + + return(-1); + + if (phase != MSG_OUT) + + return(tul_bad_seq(pHcs)); + + + + TUL_WR(pHcs->HCS_SFifo, MSG_ABORT_TAG); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + + + pHcs->HCS_Flags |= HCF_EXPECT_DISC; + + if (wait_tulip(pHcs) != -1) + + { + + return (tul_bad_seq(pHcs)); + + } + + + + return (-1); + +} + + + +/***************************************************************************/ + +static long tul_msgin(I91U_HCS *pHcs) + +{ + + TCS *pTcb = pHcs->HCS_ActTcs; + long cnt; + int phase; + BYTE imsg; + + for (;;) + + { + + if ((cnt = TUL_RD(pHcs->HCS_Base + TUL_SFifoCnt) & 0x1F) != 0) + + { /* Flush SCSI FIFO */ + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + + } + + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 1); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_IN); + + if ((phase = wait_tulip(pHcs)) == -1) + + return (-1); + + imsg = TUL_RD(pHcs->HCS_SFifo); + + switch (imsg) { + + case MSG_DISC: /* Disconnect msg */ + + phase = tul_msgin_discon(pHcs); + + break; + + case MSG_SDP: + + case MSG_RESTORE: + + case MSG_NOP: + + phase = tul_msgin_accept(pHcs); + + break; + + case MSG_REJ: /* Clear ATN first */ + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, (TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7))); + + if ((pTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) + { /* do sync nego */ + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, ((TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN)); + + } + + phase = tul_msgin_accept(pHcs); + + break; + + case MSG_EXTEND: /* extended msg */ + + phase = tul_msgin_extend(pHcs); + + break; + + case MSG_IGNOREWIDE: + + phase = tul_msgin_ignore_wid_resid(pHcs); + + break; + + case MSG_COMP: + + pHcs->HCS_Flags |= HCF_EXPECT_DONE_DISC; + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + + if ((phase = tul_msgin_accept(pHcs)) != -1) { + + return (tul_bad_seq(pHcs)); + + } + + break; + + default: + + phase = tul_msgout_reject(pHcs); + + break; + + } + + if (phase != MSG_IN) + + return (phase); + + } + + /* statement won't reach here */ + +} + + + + + +/***************************************************************************/ + +static long tul_msgin_discon(I91U_HCS *pHcs) +{ + pHcs->HCS_Flags |= HCF_EXPECT_DISC; + if (tul_msgin_accept(pHcs) == -1) + return (-1); + return (tul_bad_seq(pHcs)); +} + + +/***************************************************************************/ + +static long tul_msgout_reject(I91U_HCS *pHcs) + +{ + + int phase; + + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, ((TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN)); + + + + if ((phase = tul_msgin_accept(pHcs)) == -1) + + return(-1); + + + + if (phase == MSG_OUT) + + { + + TUL_WR(pHcs->HCS_SFifo, MSG_REJ); /* Msg reject */ + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + return (wait_tulip(pHcs)); + + } + + return (phase); + +} + + + +/************** tul_msgout_sync rtn **************************/ + +static long tul_msgout_sync(I91U_HCS *pHcs) + +{ + +char phase; + + + + TCS *pTcb = pHcs->HCS_ActTcs; + + + + pTcb->TCS_Flags |= TCF_SYNC_DONE; + + + + TUL_WR(pHcs->HCS_SFifo, MSG_EXTEND); + + TUL_WR(pHcs->HCS_SFifo, 3); /* extended msg length */ + + TUL_WR(pHcs->HCS_SFifo, 1); /* sync request */ + + TUL_WR(pHcs->HCS_SFifo, tul_rate_tbl[pTcb->TCS_Flags & TCF_SCSI_RATE]); + + TUL_WR(pHcs->HCS_SFifo, MAX_OFFSET); /* REQ/ACK offset */ + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + phase = wait_tulip(pHcs); + + TUL_WR(pHcs->HCS_Base+TUL_SCtrl0, TSC_FLUSH_FIFO); + + TUL_WR(pHcs->HCS_Base+TUL_SSignal, TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7)); + + + + return (phase); + +} + + + +/***************************************************************************/ + +static long tul_msgout_nop(I91U_HCS *pHcs) + +{ + + TUL_WR(pHcs->HCS_SFifo, MSG_NOP); /* msg nop */ + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + return (wait_tulip(pHcs)); + +} + + + +/***************************************************************************/ + +static long tul_msgout_ide(I91U_HCS *pHcs) + +{ + + TUL_WR(pHcs->HCS_SFifo, MSG_IDE); /* Initiator Detected Error */ + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + return (wait_tulip(pHcs)); + +} + + + +/***************************************************************************/ + +static long tul_msgin_ignore_wid_resid(I91U_HCS *pHcs) + +{ + + int phase; + + + + if ((phase = tul_msgin_accept(pHcs)) != MSG_IN) + + return (phase); + + + + /* get */ + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_IN); + + if (wait_tulip(pHcs) == -1) + + return -1; + + + + TUL_WR(pHcs->HCS_SFifo, 0); /* put pad */ + +/* TTT TUL_RD(pHcs->HCS_SFifo); */ /* get IGNORE field */ + +/* TTT TUL_RD(pHcs->HCS_SFifo); */ /* get pad */ + + + + return (tul_msgin_accept(pHcs)); + + + +} + + + +/***************************************************************************/ + +static long tul_msgin_extend(I91U_HCS *pHcs) + +{ + + int phase; + + BYTE len, idx; + +/* BYTE msg[10];*/ + + + + if ((phase = tul_msgin_accept(pHcs)) != MSG_IN) + + return (phase); + + + + /* Get extended msg length */ + + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 1); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_IN); + + if (wait_tulip(pHcs) == -1) + + return (-1); + + len = TUL_RD(pHcs->HCS_SFifo); + + pHcs->HCS_Msg[0] = len; + + for (idx = 1 ; len != 0; len--) + + { + + if ((phase = tul_msgin_accept(pHcs)) != MSG_IN) + + return (phase); + + TUL_WRLONG(pHcs->HCS_Base + TUL_SCnt0, 1); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_IN); + + if (wait_tulip(pHcs) == -1) + + return (-1); + + pHcs->HCS_Msg[idx++] = TUL_RD(pHcs->HCS_SFifo); + + } + + if (pHcs->HCS_Msg[1] == 1) + + { /* if it's synchronous data transfer request */ + + if (pHcs->HCS_Msg[0] != 3) /* if length is not right */ + + return (tul_msgout_reject(pHcs)); + + if (pHcs->HCS_ActTcs->TCS_Flags & TCF_NO_SYNC_NEGO) + + { /* Set OFFSET=0 to do async, nego back */ + + pHcs->HCS_Msg[3] = 0; + + } + + else + + { + + if ((tul_msgin_sync(pHcs) == 0) && + + (pHcs->HCS_ActTcs->TCS_Flags & TCF_SYNC_DONE)) + + { + + tul_sync_done(pHcs); + + return (tul_msgin_accept(pHcs)); + + } + + } + + + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, ((TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN)); + + if ((phase = tul_msgin_accept(pHcs)) != MSG_OUT) + + return (phase); + + /* sync msg out */ + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); + +/* TUL_WR(pHcs->HCS_SFifo, TSC_FLUSH_FIFO); */ + + + + tul_sync_done(pHcs); + + + + TUL_WR(pHcs->HCS_SFifo, MSG_EXTEND); + + TUL_WR(pHcs->HCS_SFifo, 3); + + TUL_WR(pHcs->HCS_SFifo, 1); + + TUL_WR(pHcs->HCS_SFifo, pHcs->HCS_Msg[2]); + + TUL_WR(pHcs->HCS_SFifo, pHcs->HCS_Msg[3]); + + + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + return (wait_tulip(pHcs)); + + } + + + + if ((pHcs->HCS_Msg[0] != 2) || (pHcs->HCS_Msg[1] != 3)) + + return (tul_msgout_reject(pHcs)); + + /* if it's WIDE DATA XFER REQ */ + + if (pHcs->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) + + { + + pHcs->HCS_Msg[2] = 0; + + } + + else + + { + + if (pHcs->HCS_Msg[2] > 2) /* > 32 bits */ + + return (tul_msgout_reject(pHcs)); + + if (pHcs->HCS_Msg[2] == 2) /* == 32 */ + + { + + pHcs->HCS_Msg[2] = 1; + + } + + else + + { + + if ((pHcs->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) == 0) + + { + + tul_wdtr_done(pHcs); + + if ((pHcs->HCS_ActTcs->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, ((TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN)); + + return (tul_msgin_accept(pHcs)); + + } + + } + + } + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, ((TUL_RD(pHcs->HCS_Base + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN)); + + + + if ((phase = tul_msgin_accept(pHcs)) != MSG_OUT) + + return (phase); + + /* WDTR msg out */ + + TUL_WR(pHcs->HCS_SFifo, MSG_EXTEND); + + TUL_WR(pHcs->HCS_SFifo, 2); + + TUL_WR(pHcs->HCS_SFifo, 3); + + TUL_WR(pHcs->HCS_SFifo, pHcs->HCS_Msg[2]); + + TUL_WR(pHcs->HCS_SCmd, TSC_XF_FIFO_OUT); + + return (wait_tulip(pHcs)); + +} + + + +/***************************************************************************/ + +static long tul_msgin_sync(I91U_HCS *pHcs) + +{ + + char default_period; + + + + default_period = tul_rate_tbl[pHcs->HCS_ActTcs->TCS_Flags & TCF_SCSI_RATE]; + + if (pHcs->HCS_Msg[3] > MAX_OFFSET) + + { + + pHcs->HCS_Msg[3] = MAX_OFFSET; + + if (pHcs->HCS_Msg[2] < default_period) + + { + + pHcs->HCS_Msg[2] = default_period; + + return 1; + + } + + if (pHcs->HCS_Msg[2] >= 59) + + { /* Change to async */ + + pHcs->HCS_Msg[3] = 0; + + } + + return 1; + + } + + + + /* offset requests asynchronous transfers ? */ + + if (pHcs->HCS_Msg[3] == 0) + + { + + return 0; + + } + + if (pHcs->HCS_Msg[2] < default_period) + + { + + pHcs->HCS_Msg[2] = default_period; + + return 1; + + } + + + + if (pHcs->HCS_Msg[2] >= 59) + + { + + pHcs->HCS_Msg[3] = 0; + + return 1; + + } + + return 0; + +} + + + + + +/***************************************************************************/ + +static void tul_wdtr_done(I91U_HCS *pHcs) + +{ + + pHcs->HCS_ActTcs->TCS_Flags &= ~TCF_SYNC_DONE; + + pHcs->HCS_ActTcs->TCS_Flags |= TCF_WDTR_DONE; + + + + pHcs->HCS_ActTcs->TCS_JS_Period = 0; + + if (pHcs->HCS_Msg[2]) + + { /* if 16 bit */ + + pHcs->HCS_ActTcs->TCS_JS_Period |= TSC_WIDE_SCSI; + + } + + pHcs->HCS_ActTcs->TCS_SConfig0 &= ~TSC_ALT_PERIOD; + + TUL_WR(pHcs->HCS_Base+TUL_SConfig, pHcs->HCS_ActTcs->TCS_SConfig0); + + TUL_WR(pHcs->HCS_Base+TUL_SPeriod, pHcs->HCS_ActTcs->TCS_JS_Period); + + + +} + + + +/***************************************************************************/ + +void tul_sync_done(I91U_HCS *pHcs) + +{ + + int i; + + + + pHcs->HCS_ActTcs->TCS_Flags |= TCF_SYNC_DONE; + + + + if (pHcs->HCS_Msg[3]) + + { + + pHcs->HCS_ActTcs->TCS_JS_Period |= pHcs->HCS_Msg[3]; + + for (i = 0; i < 8; i++) + + { + + if (tul_rate_tbl[i] >= pHcs->HCS_Msg[2]) /* pick the big one */ + + break; + + } + + pHcs->HCS_ActTcs->TCS_JS_Period |= (i << 4); + + pHcs->HCS_ActTcs->TCS_SConfig0 |= TSC_ALT_PERIOD; + + } + + TUL_WR(pHcs->HCS_Base+TUL_SConfig, pHcs->HCS_ActTcs->TCS_SConfig0); + + TUL_WR(pHcs->HCS_Base+TUL_SPeriod, pHcs->HCS_ActTcs->TCS_JS_Period); + + +} + + +/***************************************************************************/ + +static long tul_reset_scsi(I91U_HCS *pHcs) + +{ + ULONG i; + + TUL_WR( pHcs->HCS_Base + TUL_SCtrl0, TSC_RST_BUS); + + + while(!((pHcs->HCS_JSInt = TUL_RD(pHcs->HCS_Base + TUL_SInt)) & TSS_SCSIRST_INT)); + + /* reset tulip chip */ + + + TUL_WR(pHcs->HCS_Base + TUL_SSignal, 0); + + + /* Stall for a while, wait for target's firmware ready,make it 2 sec ! */ + /* SONY 5200 tape drive won't work if only stall for 1 sec */ + + for (i = 0; i < 1000; i++) /* wait 1 sec */ + + DELAY (1000); /* delay 1 msec */ + +/* TTT TUL_RD(pHcs->HCS_Base + TUL_SInt); */ + + + for (i = 0; i < 16000; i++) + DELAY (1000); /* delay 1 msec */ + + return (1); +} + +static long tul_post_scsi_rst(I91U_HCS *pHcs) +{ + I91U_SCB *pScb; + TCS *pTcb; + int i; + + pHcs->HCS_ActScb = 0; + + pScb = pHcs->HCS_Scb ; + for (i = 0; i < pHcs->HCS_NumScbs; i++, pScb++) + { + if (pScb->SCB_Status & SCB_BUSY) + { + tul_unlink_busy_scb(pHcs, pScb); + + pScb->SCB_HaStat = HOST_SCSI_RST; + tul_append_done_scb(pHcs, pScb); + } + } + + /* clear sync done flag */ + + pTcb = &pHcs->HCS_Tcs[0]; + for (i = 0; i < pHcs->HCS_MaxTar; pTcb++, i++) + + { + pTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE); + + /* Initialize the sync. xfer register values to an asyn xfer */ + pTcb->TCS_JS_Period = 0; + pTcb->TCS_SConfig0 = pHcs->HCS_SConf1; + pTcb->TCS_TagCnt = 0; + pTcb->TCS_NonTagScb = NULL; + } /* for */ + return (-1); +} + +/***************************************************************************/ + +static void tul_select_atn_stop(I91U_HCS *pHcs, I91U_SCB *pScb) + +{ + + TUL_WR(pHcs->HCS_SCmd, TSC_SELATNSTOP); + pScb->SCB_Status |= SCB_SELECT; + pScb->SCB_NxtStat = 1; + pHcs->HCS_ActScb = pScb; +} + + +/***************************************************************************/ + +static void tul_select_atn(I91U_HCS *pHcs, I91U_SCB *pScb) +{ +#if 0 + int i; + + + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_Ident); + + for (i = 0; i < (int)pScb->SCB_CDBLen; i++) + + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_CDB[i]); + +#else + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_Ident); + + outsb(pHcs->HCS_SFifo, pScb->SCB_CDB, pScb->SCB_CDBLen); +#endif + TUL_WR(pHcs->HCS_SCmd, TSC_SEL_ATN); + + + pScb->SCB_Status |= SCB_SELECT; + pScb->SCB_NxtStat = 2; + pHcs->HCS_ActScb = pScb; + +} + +/***************************************************************************/ + +static void tul_select_atn3(I91U_HCS *pHcs, I91U_SCB *pScb) + +{ +#if 0 + int i; + + + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_Ident); + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_TagMsg); + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_TagId); + for (i = 0; i < (int) pScb->SCB_CDBLen; i++) + TUL_WR(pHcs->HCS_SFifo, pScb->SCB_CDB[i]); +#else + outsb(pHcs->HCS_SFifo, &(pScb->SCB_Ident), pScb->SCB_CDBLen+3); +#endif + TUL_WR(pHcs->HCS_SCmd, TSC_SEL_ATN3); + + pScb->SCB_Status |= SCB_SELECT; + pScb->SCB_NxtStat = 2; + pHcs->HCS_ActScb = pScb; + + +} + + +/***************************************************************************/ +static long tul_msgin_accept(I91U_HCS *pHcs) +{ + TUL_WR(pHcs->HCS_SCmd, TSC_MSG_ACCEPT); + + return (wait_tulip(pHcs)); +} + +/***************************************************************************/ +static long wait_tulip(I91U_HCS *pHcs) +{ + I91U_SCB *pScb = pHcs->HCS_ActScb; +/* register BYTE s; + int phase;*/ + + while (!((pHcs->HCS_JSStatus0 = TUL_RD(pHcs->HCS_Base + TUL_SStatus0)) + & TSS_INT_PENDING)); + + pHcs->HCS_Phase = pHcs->HCS_JSStatus0 & TSS_PH_MASK; + pHcs->HCS_JSInt = TUL_RD(pHcs->HCS_Base + TUL_SInt); + pHcs->HCS_JSStatus1 = TUL_RD(pHcs->HCS_Base + TUL_SStatus1); + +/* printf("int=%x ps=%x ", pHcs->HCS_JSInt, pHcs->HCS_Phase); */ + + if (pHcs->HCS_JSInt & TSS_SCSIRST_INT) + { /* if SCSI bus reset detected */ + return (int_tul_scsi_rst(pHcs)); + } + + if (pHcs->HCS_JSInt & TSS_RESEL_INT) + { /* if SCSI bus reset detected */ + return (int_tul_resel(pHcs)); + } + + if (pHcs->HCS_JSInt & TSS_SEL_TIMEOUT) + { /* if selected/reselected timeout interrupt */ + return (int_tul_busfree(pHcs)); + } + + if (pHcs->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */ + if (pHcs->HCS_Flags & HCF_EXPECT_DONE_DISC) { + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */ + + TUL_WR(pHcs->HCS_Base + TUL_SConfig, TSC_INITDEFAULT); + TUL_WR(pHcs->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);/* Enable HW reselect */ + + tul_unlink_busy_scb(pHcs, pScb); + tul_append_done_scb(pHcs, pScb); + pHcs->HCS_ActScb = NULL; + pHcs->HCS_Flags &= ~HCF_EXPECT_DONE_DISC; + + return (-1); + } + + if (pHcs->HCS_Flags & HCF_EXPECT_DISC) { + TUL_WR(pHcs->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */ + TUL_WR(pHcs->HCS_Base + TUL_SConfig, TSC_INITDEFAULT); + + TUL_WR(pHcs->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);/* Enable HW reselect */ + + pHcs->HCS_ActScb = NULL; + pHcs->HCS_Flags &= ~HCF_EXPECT_DISC; + + return (-1); + + } + + return (int_tul_busfree(pHcs)); + + } + + return (pHcs->HCS_Phase); + +} + +/**************************** EOF *********************************/ +