linux-old/drivers/scsi/i60uscsi.c
<<
>>
Prefs
   1/**************************************************************************
   2 * Initio A100 device driver for Linux.
   3 *
   4 * Copyright (c) 1994-1998 Initio Corporation
   5 * All rights reserved.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2, or (at your option)
  10 * any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; see the file COPYING.  If not, write to
  19 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  20 *
  21 * --------------------------------------------------------------------------
  22 *
  23 * Redistribution and use in source and binary forms, with or without
  24 * modification, are permitted provided that the following conditions
  25 * are met:
  26 * 1. Redistributions of source code must retain the above copyright
  27 *    notice, this list of conditions, and the following disclaimer,
  28 *    without modification, immediately at the beginning of the file.
  29 * 2. Redistributions in binary form must reproduce the above copyright
  30 *    notice, this list of conditions and the following disclaimer in the
  31 *    documentation and/or other materials provided with the distribution.
  32 * 3. The name of the author may not be used to endorse or promote products
  33 *    derived from this software without specific prior written permission.
  34 *
  35 * Where this Software is combined with software released under the terms of 
  36 * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  37 * combined work to also be released under the terms of the GPL, the terms
  38 * and conditions of this License will apply in addition to those of the
  39 * GPL with the exception of any terms or conditions of this License that
  40 * conflict with, or are expressly prohibited by, the GPL.
  41 *
  42 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  45 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  46 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  52 * SUCH DAMAGE.
  53 *
  54 *************************************************************************
  55 *
  56 * module: i60uscsi.c 
  57 * DESCRIPTION:
  58 *      This is the Linux low-level SCSI driver for Initio INIA100 SCSI host
  59 * adapters
  60 *
  61 * 07/02/98 hl  - v.91n Initial drivers.
  62 * 09/14/98 hl - v1.01 Support new Kernel.
  63 * 09/22/98 hl - v1.01a Support reset.
  64 * 09/24/98 hl - v1.01b Fixed reset.
  65 * 10/05/98 hl - v1.02 split the source code and release.
  66 * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up
  67 * 01/31/99 bv - v1.02b Use mdelay instead of waitForPause
  68 * 08/08/99 bv - v1.02c Use waitForPause again.
  69 **************************************************************************/
  70
  71#include <linux/version.h>
  72#include <linux/sched.h>
  73#include <asm/io.h>
  74#include "i60uscsi.h"
  75
  76#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
  77#define MS_TO_JIFFIES(j) ((j * HZ) / 1000)
  78
  79/* ---- INTERNAL FUNCTIONS ---- */
  80static UCHAR waitChipReady(ORC_HCS * hcsp);
  81static UCHAR waitFWReady(ORC_HCS * hcsp);
  82static UCHAR waitFWReady(ORC_HCS * hcsp);
  83static UCHAR waitSCSIRSTdone(ORC_HCS * hcsp);
  84static UCHAR waitHDOoff(ORC_HCS * hcsp);
  85static UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData);
  86static unsigned short get_FW_version(ORC_HCS * hcsp);
  87static UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value);
  88static UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn);
  89static int se2_rd_all(ORC_HCS * hcsp);
  90static void se2_update_all(ORC_HCS * hcsp);     /* setup default pattern        */
  91static void read_eeprom(ORC_HCS * hcsp);
  92static UCHAR load_FW(ORC_HCS * hcsp);
  93static void setup_SCBs(ORC_HCS * hcsp);
  94static void initAFlag(ORC_HCS * hcsp);
  95ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
  96
  97/* ---- EXTERNAL FUNCTIONS ---- */
  98extern void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
  99
 100/* ---- INTERNAL VARIABLES ---- */
 101ORC_HCS orc_hcs[MAX_SUPPORTED_ADAPTERS];
 102static INIA100_ADPT_STRUCT inia100_adpt[MAX_SUPPORTED_ADAPTERS];
 103/* set by inia100_setup according to the command line */
 104int orc_num_scb;
 105
 106NVRAM nvram, *nvramp = &nvram;
 107static UCHAR dftNvRam[64] =
 108{
 109/*----------header -------------*/
 110        0x01,                   /* 0x00: Sub System Vendor ID 0 */
 111        0x11,                   /* 0x01: Sub System Vendor ID 1 */
 112        0x60,                   /* 0x02: Sub System ID 0        */
 113        0x10,                   /* 0x03: Sub System ID 1        */
 114        0x00,                   /* 0x04: SubClass               */
 115        0x01,                   /* 0x05: Vendor ID 0            */
 116        0x11,                   /* 0x06: Vendor ID 1            */
 117        0x60,                   /* 0x07: Device ID 0            */
 118        0x10,                   /* 0x08: Device ID 1            */
 119        0x00,                   /* 0x09: Reserved               */
 120        0x00,                   /* 0x0A: Reserved               */
 121        0x01,                   /* 0x0B: Revision of Data Structure     */
 122                                /* -- Host Adapter Structure --- */
 123        0x01,                   /* 0x0C: Number Of SCSI Channel */
 124        0x01,                   /* 0x0D: BIOS Configuration 1   */
 125        0x00,                   /* 0x0E: BIOS Configuration 2   */
 126        0x00,                   /* 0x0F: BIOS Configuration 3   */
 127                                /* --- SCSI Channel 0 Configuration --- */
 128        0x07,                   /* 0x10: H/A ID                 */
 129        0x83,                   /* 0x11: Channel Configuration  */
 130        0x20,                   /* 0x12: MAX TAG per target     */
 131        0x0A,                   /* 0x13: SCSI Reset Recovering time     */
 132        0x00,                   /* 0x14: Channel Configuration4 */
 133        0x00,                   /* 0x15: Channel Configuration5 */
 134                                /* SCSI Channel 0 Target Configuration  */
 135                                /* 0x16-0x25                    */
 136        0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
 137        0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
 138                                /* --- SCSI Channel 1 Configuration --- */
 139        0x07,                   /* 0x26: H/A ID                 */
 140        0x83,                   /* 0x27: Channel Configuration  */
 141        0x20,                   /* 0x28: MAX TAG per target     */
 142        0x0A,                   /* 0x29: SCSI Reset Recovering time     */
 143        0x00,                   /* 0x2A: Channel Configuration4 */
 144        0x00,                   /* 0x2B: Channel Configuration5 */
 145                                /* SCSI Channel 1 Target Configuration  */
 146                                /* 0x2C-0x3B                    */
 147        0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
 148        0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
 149        0x00,                   /* 0x3C: Reserved               */
 150        0x00,                   /* 0x3D: Reserved               */
 151        0x00,                   /* 0x3E: Reserved               */
 152        0x00                    /* 0x3F: Checksum               */
 153};
 154
 155
 156/***************************************************************************/
 157static void waitForPause(unsigned amount)
 158{
 159        ULONG the_time = jiffies + MS_TO_JIFFIES(amount);
 160        while (time_before_eq(jiffies, the_time))
 161                cpu_relax();
 162}
 163
 164/***************************************************************************/
 165UCHAR waitChipReady(ORC_HCS * hcsp)
 166{
 167        int i;
 168
 169        for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
 170                if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP)       /* Wait HOSTSTOP set */
 171                        return (TRUE);
 172                waitForPause(100);      /* wait 100ms before try again  */
 173        }
 174        return (FALSE);
 175}
 176
 177/***************************************************************************/
 178UCHAR waitFWReady(ORC_HCS * hcsp)
 179{
 180        int i;
 181
 182        for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
 183                if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY)         /* Wait READY set */
 184                        return (TRUE);
 185                waitForPause(100);      /* wait 100ms before try again  */
 186        }
 187        return (FALSE);
 188}
 189
 190/***************************************************************************/
 191UCHAR waitSCSIRSTdone(ORC_HCS * hcsp)
 192{
 193        int i;
 194
 195        for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
 196                if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST))     /* Wait SCSIRST done */
 197                        return (TRUE);
 198                waitForPause(100);      /* wait 100ms before try again  */
 199        }
 200        return (FALSE);
 201}
 202
 203/***************************************************************************/
 204UCHAR waitHDOoff(ORC_HCS * hcsp)
 205{
 206        int i;
 207
 208        for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
 209                if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO))         /* Wait HDO off */
 210                        return (TRUE);
 211                waitForPause(100);      /* wait 100ms before try again  */
 212        }
 213        return (FALSE);
 214}
 215
 216/***************************************************************************/
 217UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData)
 218{
 219        int i;
 220
 221        for (i = 0; i < 10; i++) {      /* Wait 1 second for report timeout     */
 222                if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI)
 223                        return (TRUE);  /* Wait HDI set */
 224                waitForPause(100);      /* wait 100ms before try again  */
 225        }
 226        return (FALSE);
 227}
 228
 229/***************************************************************************/
 230unsigned short get_FW_version(ORC_HCS * hcsp)
 231{
 232        UCHAR bData;
 233        union {
 234                unsigned short sVersion;
 235                unsigned char cVersion[2];
 236        } Version;
 237
 238        ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_VERSION);
 239        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
 240        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
 241                return (FALSE);
 242
 243        if (waitHDIset(hcsp, &bData) == FALSE)  /* Wait HDI set   */
 244                return (FALSE);
 245        Version.cVersion[0] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
 246        ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI            */
 247
 248        if (waitHDIset(hcsp, &bData) == FALSE)  /* Wait HDI set   */
 249                return (FALSE);
 250        Version.cVersion[1] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
 251        ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI            */
 252
 253        return (Version.sVersion);
 254}
 255
 256/***************************************************************************/
 257UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value)
 258{
 259        ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_SET_NVM);    /* Write command */
 260        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
 261        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
 262                return (FALSE);
 263
 264        ORC_WR(hcsp->HCS_Base + ORC_HDATA, address);    /* Write address */
 265        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
 266        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
 267                return (FALSE);
 268
 269        ORC_WR(hcsp->HCS_Base + ORC_HDATA, value);      /* Write value  */
 270        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
 271        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
 272                return (FALSE);
 273
 274        return (TRUE);
 275}
 276
 277/***************************************************************************/
 278UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn)
 279{
 280        unsigned char bData;
 281
 282        ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_GET_NVM);    /* Write command */
 283        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
 284        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
 285                return (FALSE);
 286
 287        ORC_WR(hcsp->HCS_Base + ORC_HDATA, address);    /* Write address */
 288        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
 289        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
 290                return (FALSE);
 291
 292        if (waitHDIset(hcsp, &bData) == FALSE)  /* Wait HDI set   */
 293                return (FALSE);
 294        *pDataIn = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
 295        ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI    */
 296
 297        return (TRUE);
 298}
 299
 300/***************************************************************************/
 301void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
 302{
 303        scbp->SCB_Status = SCB_POST;
 304        ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx);
 305        return;
 306}
 307
 308
 309/***********************************************************************
 310 Read SCSI H/A configuration parameters from serial EEPROM
 311************************************************************************/
 312int se2_rd_all(ORC_HCS * hcsp)
 313{
 314        int i;
 315        UCHAR *np, chksum = 0;
 316
 317        np = (UCHAR *) nvramp;
 318        for (i = 0; i < 64; i++, np++) {        /* <01> */
 319                if (get_NVRAM(hcsp, (unsigned char) i, np) == FALSE)
 320                        return -1;
 321//      *np++ = get_NVRAM(hcsp, (unsigned char ) i);
 322        }
 323
 324/*------ Is ckecksum ok ? ------*/
 325        np = (UCHAR *) nvramp;
 326        for (i = 0; i < 63; i++)
 327                chksum += *np++;
 328
 329        if (nvramp->CheckSum != (UCHAR) chksum)
 330                return -1;
 331        return 1;
 332}
 333
 334/************************************************************************
 335 Update SCSI H/A configuration parameters from serial EEPROM
 336*************************************************************************/
 337void se2_update_all(ORC_HCS * hcsp)
 338{                               /* setup default pattern  */
 339        int i;
 340        UCHAR *np, *np1, chksum = 0;
 341
 342        /* Calculate checksum first   */
 343        np = (UCHAR *) dftNvRam;
 344        for (i = 0; i < 63; i++)
 345                chksum += *np++;
 346        *np = chksum;
 347
 348        np = (UCHAR *) dftNvRam;
 349        np1 = (UCHAR *) nvramp;
 350        for (i = 0; i < 64; i++, np++, np1++) {
 351                if (*np != *np1) {
 352                        set_NVRAM(hcsp, (unsigned char) i, *np);
 353                }
 354        }
 355        return;
 356}
 357
 358/*************************************************************************
 359 Function name  : read_eeprom
 360**************************************************************************/
 361void read_eeprom(ORC_HCS * hcsp)
 362{
 363        if (se2_rd_all(hcsp) != 1) {
 364                se2_update_all(hcsp);   /* setup default pattern        */
 365                se2_rd_all(hcsp);       /* load again                   */
 366        }
 367}
 368
 369
 370/***************************************************************************/
 371UCHAR load_FW(ORC_HCS * hcsp)
 372{
 373        U32 dData;
 374        USHORT wBIOSAddress;
 375        USHORT i;
 376        UCHAR *pData, bData;
 377
 378
 379        bData = ORC_RD(hcsp->HCS_Base, ORC_GCFG);
 380        ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData | EEPRG);       /* Enable EEPROM programming */
 381        ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, 0x00);
 382        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x00);
 383        if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0x55) {
 384                ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /* Disable EEPROM programming */
 385                return (FALSE);
 386        }
 387        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x01);
 388        if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0xAA) {
 389                ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /* Disable EEPROM programming */
 390                return (FALSE);
 391        }
 392        ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD);       /* Enable SRAM programming */
 393        pData = (UCHAR *) & dData;
 394        dData = 0;              /* Initial FW address to 0 */
 395        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x10);
 396        *pData = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);         /* Read from BIOS */
 397        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x11);
 398        *(pData + 1) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);   /* Read from BIOS */
 399        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x12);
 400        *(pData + 2) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);   /* Read from BIOS */
 401        ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, *(pData + 2));
 402        ORC_WRLONG(hcsp->HCS_Base + ORC_FWBASEADR, dData);      /* Write FW address */
 403
 404        wBIOSAddress = (USHORT) dData;  /* FW code locate at BIOS address + ? */
 405        for (i = 0, pData = (UCHAR *) & dData;  /* Download the code    */
 406             i < 0x1000;        /* Firmware code size = 4K      */
 407             i++, wBIOSAddress++) {
 408                ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
 409                *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);       /* Read from BIOS */
 410                if ((i % 4) == 3) {
 411                        ORC_WRLONG(hcsp->HCS_Base + ORC_RISCRAM, dData);        /* Write every 4 bytes */
 412                        pData = (UCHAR *) & dData;
 413                }
 414        }
 415
 416        ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD);       /* Reset program count 0 */
 417        wBIOSAddress -= 0x1000; /* Reset the BIOS adddress      */
 418        for (i = 0, pData = (UCHAR *) & dData;  /* Check the code       */
 419             i < 0x1000;        /* Firmware code size = 4K      */
 420             i++, wBIOSAddress++) {
 421                ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
 422                *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);       /* Read from BIOS */
 423                if ((i % 4) == 3) {
 424                        if (ORC_RDLONG(hcsp->HCS_Base, ORC_RISCRAM) != dData) {
 425                                ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST);  /* Reset program to 0 */
 426                                ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /*Disable EEPROM programming */
 427                                return (FALSE);
 428                        }
 429                        pData = (UCHAR *) & dData;
 430                }
 431        }
 432        ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST);  /* Reset program to 0   */
 433        ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /* Disable EEPROM programming */
 434        return (TRUE);
 435}
 436
 437/***************************************************************************/
 438void setup_SCBs(ORC_HCS * hcsp)
 439{
 440        ORC_SCB *pVirScb;
 441        int i;
 442        UCHAR j;
 443        ESCB *pVirEscb;
 444        PVOID pPhysEscb;
 445        PVOID tPhysEscb;
 446
 447        j = 0;
 448        pVirScb = NULL;
 449        tPhysEscb = (PVOID) NULL;
 450        pPhysEscb = (PVOID) NULL;
 451        /* Setup SCB HCS_Base and SCB Size registers */
 452        ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, orc_num_scb);      /* Total number of SCBs */
 453        /* SCB HCS_Base address 0      */
 454        ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray);
 455        /* SCB HCS_Base address 1      */
 456        ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray);
 457
 458        /* setup scatter list address with one buffer */
 459        pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray;
 460        pVirEscb = (ESCB *) hcsp->HCS_virEscbArray;
 461
 462        for (i = 0; i < orc_num_scb; i++) {
 463                pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
 464                pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
 465                pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
 466                pVirScb->SCB_EScb = pVirEscb;
 467                pVirScb->SCB_ScbIdx = i;
 468                pVirScb++;
 469                pVirEscb++;
 470        }
 471
 472        return;
 473}
 474
 475/***************************************************************************/
 476static void initAFlag(ORC_HCS * hcsp)
 477{
 478        UCHAR i, j;
 479
 480        for (i = 0; i < MAX_CHANNELS; i++) {
 481                for (j = 0; j < 8; j++) {
 482                        hcsp->BitAllocFlag[i][j] = 0xffffffff;
 483                }
 484        }
 485}
 486
 487/***************************************************************************/
 488int init_orchid(ORC_HCS * hcsp)
 489{
 490        UBYTE *readBytep;
 491        USHORT revision;
 492        UCHAR i;
 493
 494        initAFlag(hcsp);
 495        ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF);       /* Disable all interrupt        */
 496        if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) {       /* Orchid is ready              */
 497                revision = get_FW_version(hcsp);
 498                if (revision == 0xFFFF) {
 499                        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST);     /* Reset Host Adapter   */
 500                        if (waitChipReady(hcsp) == FALSE)
 501                                return (-1);
 502                        load_FW(hcsp);  /* Download FW                  */
 503                        setup_SCBs(hcsp);       /* Setup SCB HCS_Base and SCB Size registers */
 504                        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0);  /* clear HOSTSTOP       */
 505                        if (waitFWReady(hcsp) == FALSE)
 506                                return (-1);
 507                        /* Wait for firmware ready     */
 508                } else {
 509                        setup_SCBs(hcsp);       /* Setup SCB HCS_Base and SCB Size registers */
 510                }
 511        } else {                /* Orchid is not Ready          */
 512                ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST);     /* Reset Host Adapter   */
 513                if (waitChipReady(hcsp) == FALSE)
 514                        return (-1);
 515                load_FW(hcsp);  /* Download FW                  */
 516                setup_SCBs(hcsp);       /* Setup SCB HCS_Base and SCB Size registers */
 517                ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);        /* Do Hardware Reset &  */
 518
 519                /*     clear HOSTSTOP  */
 520                if (waitFWReady(hcsp) == FALSE)         /* Wait for firmware ready      */
 521                        return (-1);
 522        }
 523
 524/*------------- get serial EEProm settting -------*/
 525
 526        read_eeprom(hcsp);
 527
 528        if (nvramp->Revision != 1)
 529                return (-1);
 530
 531        hcsp->HCS_SCSI_ID = nvramp->SCSI0Id;
 532        hcsp->HCS_BIOS = nvramp->BIOSConfig1;
 533        hcsp->HCS_MaxTar = MAX_TARGETS;
 534        readBytep = (UCHAR *) & (nvramp->Target00Config);
 535        for (i = 0; i < 16; readBytep++, i++) {
 536                hcsp->TargetFlag[i] = *readBytep;
 537                hcsp->MaximumTags[i] = orc_num_scb;
 538        }                       /* for                          */
 539
 540        if (nvramp->SCSI0Config & NCC_BUSRESET) {       /* Reset SCSI bus               */
 541                hcsp->HCS_Flags |= HCF_SCSI_RESET;
 542        }
 543        ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB);       /* enable RP FIFO interrupt     */
 544        return (0);
 545}
 546
 547/*****************************************************************************
 548 Function name  : orc_reset_scsi_bus
 549 Description    : Reset registers, reset a hanging bus and
 550                  kill active and disconnected commands for target w/o soft reset
 551 Input          : pHCB  -       Pointer to host adapter structure
 552 Output         : None.
 553 Return         : pSRB  -       Pointer to SCSI request block.
 554*****************************************************************************/
 555int orc_reset_scsi_bus(ORC_HCS * pHCB)
 556{                               /* I need Host Control Block Information */
 557        ULONG flags;
 558
 559        spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
 560
 561        initAFlag(pHCB);
 562        /* reset scsi bus */
 563        ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST);
 564        if (waitSCSIRSTdone(pHCB) == FALSE) {
 565                spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
 566                return (SCSI_RESET_ERROR);
 567        } else {
 568                spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
 569                return (SCSI_RESET_SUCCESS);
 570        }
 571}
 572
 573/*****************************************************************************
 574 Function name  : orc_device_reset
 575 Description    : Reset registers, reset a hanging bus and
 576                  kill active and disconnected commands for target w/o soft reset
 577 Input          : pHCB  -       Pointer to host adapter structure
 578 Output         : None.
 579 Return         : pSRB  -       Pointer to SCSI request block.
 580*****************************************************************************/
 581int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags)
 582{                               /* I need Host Control Block Information */
 583        ORC_SCB *pScb;
 584        ESCB *pVirEscb;
 585        ORC_SCB *pVirScb;
 586        UCHAR i;
 587        ULONG flags;
 588
 589        spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
 590        pScb = (ORC_SCB *) NULL;
 591        pVirEscb = (ESCB *) NULL;
 592
 593        /* setup scatter list address with one buffer */
 594        pVirScb = (ORC_SCB *) pHCB->HCS_virScbArray;
 595
 596        initAFlag(pHCB);
 597        /* device reset */
 598        for (i = 0; i < orc_num_scb; i++) {
 599                pVirEscb = pVirScb->SCB_EScb;
 600                if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt))
 601                        break;
 602                pVirScb++;
 603        }
 604
 605        if (i == orc_num_scb) {
 606                printk("Unable to Reset - No SCB Found\n");
 607                spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
 608                return (SCSI_RESET_NOT_RUNNING);
 609        }
 610        if ((pScb = orc_alloc_scb(pHCB)) == NULL) {
 611                spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
 612                return (SCSI_RESET_NOT_RUNNING);
 613        }
 614        pScb->SCB_Opcode = ORC_BUSDEVRST;
 615        pScb->SCB_Target = target;
 616        pScb->SCB_HaStat = 0;
 617        pScb->SCB_TaStat = 0;
 618        pScb->SCB_Status = 0x0;
 619        pScb->SCB_Link = 0xFF;
 620        pScb->SCB_Reserved0 = 0;
 621        pScb->SCB_Reserved1 = 0;
 622        pScb->SCB_XferLen = 0;
 623        pScb->SCB_SGLen = 0;
 624
 625        pVirEscb->SCB_Srb = 0;
 626        if (ResetFlags & SCSI_RESET_SYNCHRONOUS) {
 627                pVirEscb->SCB_Srb = (unsigned char *) SCpnt;
 628        }
 629        orc_exec_scb(pHCB, pScb);       /* Start execute SCB            */
 630        spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
 631        return SCSI_RESET_PENDING;
 632}
 633
 634
 635/***************************************************************************/
 636ORC_SCB *__orc_alloc_scb(ORC_HCS * hcsp)
 637{
 638        ORC_SCB *pTmpScb;
 639        UCHAR Ch;
 640        ULONG idx;
 641        UCHAR index;
 642        UCHAR i;
 643
 644        Ch = hcsp->HCS_Index;
 645        for (i = 0; i < 8; i++) {
 646                for (index = 0; index < 32; index++) {
 647                        if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) {
 648                                hcsp->BitAllocFlag[Ch][i] &= ~(1 << index);
 649                                break;
 650                        }
 651                }
 652                idx = index + 32 * i;
 653                pTmpScb = (PVOID) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB)));
 654                return (pTmpScb);
 655        }
 656        return (NULL);
 657}
 658
 659ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp)
 660{
 661        ORC_SCB *pTmpScb;
 662        ULONG flags;
 663
 664        spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
 665        pTmpScb = __orc_alloc_scb(hcsp);
 666        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
 667        return (pTmpScb);
 668}
 669
 670
 671/***************************************************************************/
 672void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
 673{
 674        ULONG flags;
 675        UCHAR Index;
 676        UCHAR i;
 677        UCHAR Ch;
 678
 679        spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
 680        Ch = hcsp->HCS_Index;
 681        Index = scbp->SCB_ScbIdx;
 682        i = Index / 32;
 683        Index %= 32;
 684        hcsp->BitAllocFlag[Ch][i] |= (1 << Index);
 685        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
 686}
 687
 688
 689/*****************************************************************************
 690 Function name  : Addinia100_into_Adapter_table
 691 Description    : This function will scan PCI bus to get all Orchid card
 692 Input          : None.
 693 Output         : None.
 694 Return         : SUCCESSFUL    - Successful scan
 695 ohterwise      - No drives founded
 696*****************************************************************************/
 697int Addinia100_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
 698                                  BYTE bBus, BYTE bDevice)
 699{
 700        unsigned int i, j;
 701
 702        for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {
 703                if (inia100_adpt[i].ADPT_BIOS < wBIOS)
 704                        continue;
 705                if (inia100_adpt[i].ADPT_BIOS == wBIOS) {
 706                        if (inia100_adpt[i].ADPT_BASE == wBASE) {
 707                                if (inia100_adpt[i].ADPT_Bus != 0xFF)
 708                                        return (FAILURE);
 709                        } else if (inia100_adpt[i].ADPT_BASE < wBASE)
 710                                continue;
 711                }
 712                for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
 713                        inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE;
 714                        inia100_adpt[j].ADPT_INTR = inia100_adpt[j - 1].ADPT_INTR;
 715                        inia100_adpt[j].ADPT_BIOS = inia100_adpt[j - 1].ADPT_BIOS;
 716                        inia100_adpt[j].ADPT_Bus = inia100_adpt[j - 1].ADPT_Bus;
 717                        inia100_adpt[j].ADPT_Device = inia100_adpt[j - 1].ADPT_Device;
 718                }
 719                inia100_adpt[i].ADPT_BASE = wBASE;
 720                inia100_adpt[i].ADPT_INTR = bInterrupt;
 721                inia100_adpt[i].ADPT_BIOS = wBIOS;
 722                inia100_adpt[i].ADPT_Bus = bBus;
 723                inia100_adpt[i].ADPT_Device = bDevice;
 724                return (SUCCESSFUL);
 725        }
 726        return (FAILURE);
 727}
 728
 729
 730/*****************************************************************************
 731 Function name  : init_inia100Adapter_table
 732 Description    : This function will scan PCI bus to get all Orchid card
 733 Input          : None.
 734 Output         : None.
 735 Return         : SUCCESSFUL    - Successful scan
 736 ohterwise      - No drives founded
 737*****************************************************************************/
 738void init_inia100Adapter_table(void)
 739{
 740        int i;
 741
 742        for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {  /* Initialize adapter structure */
 743                inia100_adpt[i].ADPT_BIOS = 0xffff;
 744                inia100_adpt[i].ADPT_BASE = 0xffff;
 745                inia100_adpt[i].ADPT_INTR = 0xff;
 746                inia100_adpt[i].ADPT_Bus = 0xff;
 747                inia100_adpt[i].ADPT_Device = 0xff;
 748        }
 749}
 750
 751/*****************************************************************************
 752 Function name  : get_orcPCIConfig
 753 Description    : 
 754 Input          : pHCB  -       Pointer to host adapter structure
 755 Output         : None.
 756 Return         : pSRB  -       Pointer to SCSI request block.
 757*****************************************************************************/
 758void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx)
 759{
 760        pCurHcb->HCS_Base = inia100_adpt[ch_idx].ADPT_BASE;     /* Supply base address  */
 761        pCurHcb->HCS_BIOS = inia100_adpt[ch_idx].ADPT_BIOS;     /* Supply BIOS address  */
 762        pCurHcb->HCS_Intr = inia100_adpt[ch_idx].ADPT_INTR;     /* Supply interrupt line */
 763        return;
 764}
 765
 766
 767/*****************************************************************************
 768 Function name  : abort_SCB
 769 Description    : Abort a queued command.
 770                         (commands that are on the bus can't be aborted easily)
 771 Input          : pHCB  -       Pointer to host adapter structure
 772 Output         : None.
 773 Return         : pSRB  -       Pointer to SCSI request block.
 774*****************************************************************************/
 775int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb)
 776{
 777        unsigned char bData, bStatus;
 778
 779        ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB);  /* Write command */
 780        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
 781        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
 782                return (FALSE);
 783
 784        ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx);   /* Write address */
 785        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
 786        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
 787                return (FALSE);
 788
 789        if (waitHDIset(hcsp, &bData) == FALSE)  /* Wait HDI set   */
 790                return (FALSE);
 791        bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
 792        ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI    */
 793
 794        if (bStatus == 1)       /* 0 - Successfully               */
 795                return (FALSE); /* 1 - Fail                     */
 796        return (TRUE);
 797}
 798
 799/*****************************************************************************
 800 Function name  : inia100_abort
 801 Description    : Abort a queued command.
 802                         (commands that are on the bus can't be aborted easily)
 803 Input          : pHCB  -       Pointer to host adapter structure
 804 Output         : None.
 805 Return         : pSRB  -       Pointer to SCSI request block.
 806*****************************************************************************/
 807int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt)
 808{
 809        ESCB *pVirEscb;
 810        ORC_SCB *pVirScb;
 811        UCHAR i;
 812        ULONG flags;
 813
 814        spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
 815
 816        pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray;
 817
 818        for (i = 0; i < orc_num_scb; i++, pVirScb++) {
 819                pVirEscb = pVirScb->SCB_EScb;
 820                if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) {
 821                        if (pVirScb->SCB_TagMsg == 0) {
 822                                spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
 823                                return (SCSI_ABORT_BUSY);
 824                        } else {
 825                                if (abort_SCB(hcsp, pVirScb)) {
 826                                        pVirEscb->SCB_Srb = NULL;
 827                                        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
 828                                        return (SCSI_ABORT_SUCCESS);
 829                                } else {
 830                                        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
 831                                        return (SCSI_ABORT_NOT_RUNNING);
 832                                }
 833                        }
 834                }
 835        }
 836        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
 837        return (SCSI_ABORT_NOT_RUNNING);
 838}
 839
 840/***********************************************************************
 841 Routine Description:
 842          This is the interrupt service routine for the Orchid SCSI adapter.
 843          It reads the interrupt register to determine if the adapter is indeed
 844          the source of the interrupt and clears the interrupt at the device.
 845 Arguments:
 846          HwDeviceExtension - HBA miniport driver's adapter data storage
 847 Return Value:
 848***********************************************************************/
 849void orc_interrupt(
 850                          ORC_HCS * hcsp
 851)
 852{
 853        BYTE bScbIdx;
 854        ORC_SCB *pScb;
 855
 856        if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) {
 857                return;         // (FALSE);
 858
 859        }
 860        do {
 861                bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE);
 862
 863                pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx));
 864                pScb->SCB_Status = 0x0;
 865
 866                inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb);
 867        } while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT));
 868        return;                 //(TRUE);
 869
 870}                               /* End of I1060Interrupt() */
 871
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.