OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [scsi/] [i60uscsi.c] - Blame information for rev 199

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/**************************************************************************
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 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
 **************************************************************************/
68
 
69
#ifndef CVT_LINUX_VERSION
70
#define CVT_LINUX_VERSION(V,P,S)        (V * 65536 + P * 256 + S)
71
#endif
72
 
73
#include <linux/sched.h>
74
#include <asm/io.h>
75
#include "i60uscsi.h"
76
 
77
 
78
/* ---- INTERNAL FUNCTIONS ---- */
79
static UCHAR waitChipReady(ORC_HCS * hcsp);
80
static UCHAR waitFWReady(ORC_HCS * hcsp);
81
static UCHAR waitFWReady(ORC_HCS * hcsp);
82
static UCHAR waitSCSIRSTdone(ORC_HCS * hcsp);
83
static UCHAR waitHDOoff(ORC_HCS * hcsp);
84
static UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData);
85
static unsigned short get_FW_version(ORC_HCS * hcsp);
86
static UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value);
87
static UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn);
88
static int se2_rd_all(ORC_HCS * hcsp);
89
static void se2_update_all(ORC_HCS * hcsp);     /* setup default pattern        */
90
static void read_eeprom(ORC_HCS * hcsp);
91
static UCHAR load_FW(ORC_HCS * hcsp);
92
static void setup_SCBs(ORC_HCS * hcsp);
93
static void initAFlag(ORC_HCS * hcsp);
94
ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
95
 
96
/* ---- EXTERNAL FUNCTIONS ---- */
97
extern void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
98
 
99
/* ---- INTERNAL VARIABLES ---- */
100
ORC_HCS orc_hcs[MAX_SUPPORTED_ADAPTERS];
101
static INIA100_ADPT_STRUCT inia100_adpt[MAX_SUPPORTED_ADAPTERS];
102
/* set by inia100_setup according to the command line */
103
int orc_num_scb;
104
 
105
NVRAM nvram, *nvramp = &nvram;
106
static UCHAR dftNvRam[64] =
107
{
108
/*----------header -------------*/
109
        0x01,                   /* 0x00: Sub System Vendor ID 0 */
110
        0x11,                   /* 0x01: Sub System Vendor ID 1 */
111
        0x60,                   /* 0x02: Sub System ID 0        */
112
        0x10,                   /* 0x03: Sub System ID 1        */
113
        0x00,                   /* 0x04: SubClass               */
114
        0x01,                   /* 0x05: Vendor ID 0            */
115
        0x11,                   /* 0x06: Vendor ID 1            */
116
        0x60,                   /* 0x07: Device ID 0            */
117
        0x10,                   /* 0x08: Device ID 1            */
118
        0x00,                   /* 0x09: Reserved               */
119
        0x00,                   /* 0x0A: Reserved               */
120
        0x01,                   /* 0x0B: Revision of Data Structure     */
121
                                /* -- Host Adapter Structure --- */
122
        0x01,                   /* 0x0C: Number Of SCSI Channel */
123
        0x01,                   /* 0x0D: BIOS Configuration 1   */
124
        0x00,                   /* 0x0E: BIOS Configuration 2   */
125
        0x00,                   /* 0x0F: BIOS Configuration 3   */
126
                                /* --- SCSI Channel 0 Configuration --- */
127
        0x07,                   /* 0x10: H/A ID                 */
128
        0x83,                   /* 0x11: Channel Configuration  */
129
        0x20,                   /* 0x12: MAX TAG per target     */
130
        0x0A,                   /* 0x13: SCSI Reset Recovering time     */
131
        0x00,                   /* 0x14: Channel Configuration4 */
132
        0x00,                   /* 0x15: Channel Configuration5 */
133
                                /* SCSI Channel 0 Target Configuration  */
134
                                /* 0x16-0x25                    */
135
        0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
136
        0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
137
                                /* --- SCSI Channel 1 Configuration --- */
138
        0x07,                   /* 0x26: H/A ID                 */
139
        0x83,                   /* 0x27: Channel Configuration  */
140
        0x20,                   /* 0x28: MAX TAG per target     */
141
        0x0A,                   /* 0x29: SCSI Reset Recovering time     */
142
        0x00,                   /* 0x2A: Channel Configuration4 */
143
        0x00,                   /* 0x2B: Channel Configuration5 */
144
                                /* SCSI Channel 1 Target Configuration  */
145
                                /* 0x2C-0x3B                    */
146
        0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
147
        0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
148
        0x00,                   /* 0x3C: Reserved               */
149
        0x00,                   /* 0x3D: Reserved               */
150
        0x00,                   /* 0x3E: Reserved               */
151
        0x00                    /* 0x3F: Checksum               */
152
};
153
 
154
 
155
/***************************************************************************/
156
static void waitForPause(unsigned amount)
157
{
158
        ULONG the_time = jiffies + amount;      /* 0.01 seconds per jiffy */
159
 
160
#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
161
        while (time_before_eq(jiffies, the_time));
162
#else
163
        while (jiffies < the_time);
164
#endif
165
}
166
 
167
/***************************************************************************/
168
UCHAR waitChipReady(ORC_HCS * hcsp)
169
{
170
        int i;
171
 
172
        for (i = 0; i < 2000; i++) {     /* Wait 1 second for report timeout     */
173
                if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP)       /* Wait HOSTSTOP set */
174
                        return (TRUE);
175
                waitForPause(5);        /* wait 500ms before try again  */
176
        }
177
        return (FALSE);
178
}
179
 
180
/***************************************************************************/
181
UCHAR waitFWReady(ORC_HCS * hcsp)
182
{
183
        int i;
184
 
185
        for (i = 0; i < 2000; i++) {     /* Wait 1 second for report timeout     */
186
                if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY)         /* Wait READY set */
187
                        return (TRUE);
188
                waitForPause(5);        /* wait 500ms before try again  */
189
        }
190
        return (FALSE);
191
}
192
 
193
/***************************************************************************/
194
UCHAR waitSCSIRSTdone(ORC_HCS * hcsp)
195
{
196
        int i;
197
 
198
        for (i = 0; i < 2000; i++) {     /* Wait 1 second for report timeout     */
199
                if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST))     /* Wait SCSIRST done */
200
                        return (TRUE);
201
                waitForPause(5);        /* wait 500ms before try again  */
202
        }
203
        return (FALSE);
204
}
205
 
206
/***************************************************************************/
207
UCHAR waitHDOoff(ORC_HCS * hcsp)
208
{
209
        int i;
210
 
211
        for (i = 0; i < 2000; i++) {     /* Wait 1 second for report timeout     */
212
                if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO))         /* Wait HDO off */
213
                        return (TRUE);
214
                waitForPause(5);        /* wait 500ms before try again  */
215
        }
216
        return (FALSE);
217
}
218
 
219
/***************************************************************************/
220
UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData)
221
{
222
        int i;
223
 
224
        for (i = 0; i < 2000; i++) {     /* Wait 1 second for report timeout     */
225
                if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI)
226
                        return (TRUE);  /* Wait HDI set */
227
                waitForPause(5);        /* wait 500ms before try again  */
228
        }
229
        return (FALSE);
230
}
231
 
232
/***************************************************************************/
233
unsigned short get_FW_version(ORC_HCS * hcsp)
234
{
235
        UCHAR bData;
236
        union {
237
                unsigned short sVersion;
238
                unsigned char cVersion[2];
239
        } Version;
240
 
241
        ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_VERSION);
242
        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
243
        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
244
                return (FALSE);
245
 
246
        if (waitHDIset(hcsp, &bData) == FALSE)  /* Wait HDI set   */
247
                return (FALSE);
248
        Version.cVersion[0] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
249
        ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI            */
250
 
251
        if (waitHDIset(hcsp, &bData) == FALSE)  /* Wait HDI set   */
252
                return (FALSE);
253
        Version.cVersion[1] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
254
        ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI            */
255
 
256
        return (Version.sVersion);
257
}
258
 
259
/***************************************************************************/
260
UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value)
261
{
262
        ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_SET_NVM);    /* Write command */
263
        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
264
        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
265
                return (FALSE);
266
 
267
        ORC_WR(hcsp->HCS_Base + ORC_HDATA, address);    /* Write address */
268
        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
269
        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
270
                return (FALSE);
271
 
272
        ORC_WR(hcsp->HCS_Base + ORC_HDATA, value);      /* Write value  */
273
        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
274
        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
275
                return (FALSE);
276
 
277
        return (TRUE);
278
}
279
 
280
/***************************************************************************/
281
UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn)
282
{
283
        unsigned char bData;
284
 
285
        ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_GET_NVM);    /* Write command */
286
        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
287
        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
288
                return (FALSE);
289
 
290
        ORC_WR(hcsp->HCS_Base + ORC_HDATA, address);    /* Write address */
291
        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
292
        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
293
                return (FALSE);
294
 
295
        if (waitHDIset(hcsp, &bData) == FALSE)  /* Wait HDI set   */
296
                return (FALSE);
297
        *pDataIn = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
298
        ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI    */
299
 
300
        return (TRUE);
301
}
302
 
303
/***************************************************************************/
304
void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
305
{
306
        scbp->SCB_Status = SCB_POST;
307
        ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx);
308
        return;
309
}
310
 
311
 
312
/***********************************************************************
313
 Read SCSI H/A configuration parameters from serial EEPROM
314
************************************************************************/
315
int se2_rd_all(ORC_HCS * hcsp)
316
{
317
        int i;
318
        UCHAR *np, chksum = 0;
319
 
320
        np = (UCHAR *) nvramp;
321
        for (i = 0; i < 64; i++, np++) { /* <01> */
322
                if (get_NVRAM(hcsp, (unsigned char) i, np) == FALSE)
323
                        return -1;
324
//      *np++ = get_NVRAM(hcsp, (unsigned char ) i);
325
        }
326
 
327
/*------ Is ckecksum ok ? ------*/
328
        np = (UCHAR *) nvramp;
329
        for (i = 0; i < 63; i++)
330
                chksum += *np++;
331
 
332
        if (nvramp->CheckSum != (UCHAR) chksum)
333
                return -1;
334
        return 1;
335
}
336
 
337
/************************************************************************
338
 Update SCSI H/A configuration parameters from serial EEPROM
339
*************************************************************************/
340
void se2_update_all(ORC_HCS * hcsp)
341
{                               /* setup default pattern  */
342
        int i;
343
        UCHAR *np, *np1, chksum = 0;
344
 
345
        /* Calculate checksum first   */
346
        np = (UCHAR *) dftNvRam;
347
        for (i = 0; i < 63; i++)
348
                chksum += *np++;
349
        *np = chksum;
350
 
351
        np = (UCHAR *) dftNvRam;
352
        np1 = (UCHAR *) nvramp;
353
        for (i = 0; i < 64; i++, np++, np1++) {
354
                if (*np != *np1) {
355
                        set_NVRAM(hcsp, (unsigned char) i, *np);
356
                }
357
        }
358
        return;
359
}
360
 
361
/*************************************************************************
362
 Function name  : read_eeprom
363
**************************************************************************/
364
void read_eeprom(ORC_HCS * hcsp)
365
{
366
        if (se2_rd_all(hcsp) != 1) {
367
                se2_update_all(hcsp);   /* setup default pattern        */
368
                se2_rd_all(hcsp);       /* load again                   */
369
        }
370
}
371
 
372
 
373
/***************************************************************************/
374
UCHAR load_FW(ORC_HCS * hcsp)
375
{
376
        U32 dData;
377
        USHORT wBIOSAddress;
378
        USHORT i;
379
        UCHAR *pData, bData;
380
 
381
 
382
        bData = ORC_RD(hcsp->HCS_Base, ORC_GCFG);
383
        ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData | EEPRG);       /* Enable EEPROM programming */
384
        ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, 0x00);
385
        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x00);
386
        if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0x55) {
387
                ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /* Disable EEPROM programming */
388
                return (FALSE);
389
        }
390
        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x01);
391
        if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0xAA) {
392
                ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /* Disable EEPROM programming */
393
                return (FALSE);
394
        }
395
        ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD);       /* Enable SRAM programming */
396
        pData = (UCHAR *) & dData;
397
        dData = 0;               /* Initial FW address to 0 */
398
        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x10);
399
        *pData = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);         /* Read from BIOS */
400
        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x11);
401
        *(pData + 1) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);   /* Read from BIOS */
402
        ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x12);
403
        *(pData + 2) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);   /* Read from BIOS */
404
        ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, *(pData + 2));
405
        ORC_WRLONG(hcsp->HCS_Base + ORC_FWBASEADR, dData);      /* Write FW address */
406
 
407
        wBIOSAddress = (USHORT) dData;  /* FW code locate at BIOS address + ? */
408
        for (i = 0, pData = (UCHAR *) & dData;   /* Download the code    */
409
             i < 0x1000;        /* Firmware code size = 4K      */
410
             i++, wBIOSAddress++) {
411
                ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
412
                *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);       /* Read from BIOS */
413
                if ((i % 4) == 3) {
414
                        ORC_WRLONG(hcsp->HCS_Base + ORC_RISCRAM, dData);        /* Write every 4 bytes */
415
                        pData = (UCHAR *) & dData;
416
                }
417
        }
418
 
419
        ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD);       /* Reset program count 0 */
420
        wBIOSAddress -= 0x1000; /* Reset the BIOS adddress      */
421
        for (i = 0, pData = (UCHAR *) & dData;   /* Check the code       */
422
             i < 0x1000;        /* Firmware code size = 4K      */
423
             i++, wBIOSAddress++) {
424
                ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
425
                *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);       /* Read from BIOS */
426
                if ((i % 4) == 3) {
427
                        if (ORC_RDLONG(hcsp->HCS_Base, ORC_RISCRAM) != dData) {
428
                                ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST);  /* Reset program to 0 */
429
                                ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /*Disable EEPROM programming */
430
                                return (FALSE);
431
                        }
432
                        pData = (UCHAR *) & dData;
433
                }
434
        }
435
        ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST);  /* Reset program to 0   */
436
        ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);       /* Disable EEPROM programming */
437
        return (TRUE);
438
}
439
 
440
/***************************************************************************/
441
void setup_SCBs(ORC_HCS * hcsp)
442
{
443
        ORC_SCB *pVirScb;
444
        int i;
445
        UCHAR j;
446
        ESCB *pVirEscb;
447
        PVOID pPhysEscb;
448
        PVOID tPhysEscb;
449
 
450
        j = 0;
451
        pVirScb = NULL;
452
        tPhysEscb = (PVOID) NULL;
453
        pPhysEscb = (PVOID) NULL;
454
        /* Setup SCB HCS_Base and SCB Size registers */
455
        ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, orc_num_scb);      /* Total number of SCBs */
456
        /* SCB HCS_Base address 0      */
457
        ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray);
458
        /* SCB HCS_Base address 1      */
459
        ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray);
460
 
461
        /* setup scatter list address with one buffer */
462
        pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray;
463
        pVirEscb = (ESCB *) hcsp->HCS_virEscbArray;
464
 
465
        for (i = 0; i < orc_num_scb; i++) {
466
#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
467
                pPhysEscb = (PVOID) ((ULONG) hcsp->HCS_virEscbArray + (sizeof(ESCB) * i));
468
                pVirScb->SCB_SGPAddr = (U32) VIRT_TO_BUS(pPhysEscb);
469
                pVirScb->SCB_SensePAddr = (U32) VIRT_TO_BUS(pPhysEscb);
470
#else
471
                pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
472
                pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
473
                pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
474
#endif
475
                pVirScb->SCB_EScb = pVirEscb;
476
                pVirScb->SCB_ScbIdx = i;
477
                pVirScb++;
478
                pVirEscb++;
479
        }
480
 
481
        return;
482
}
483
 
484
/***************************************************************************/
485
static void initAFlag(ORC_HCS * hcsp)
486
{
487
        UCHAR i, j;
488
 
489
        for (i = 0; i < MAX_CHANNELS; i++) {
490
                for (j = 0; j < 8; j++) {
491
                        hcsp->BitAllocFlag[i][j] = 0xffffffff;
492
                }
493
        }
494
}
495
 
496
/***************************************************************************/
497
int init_orchid(ORC_HCS * hcsp)
498
{
499
        UBYTE *readBytep;
500
        USHORT revision;
501
        UCHAR i;
502
 
503
        initAFlag(hcsp);
504
        ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF);       /* Disable all interrupt        */
505
        if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) {       /* Orchid is ready              */
506
                revision = get_FW_version(hcsp);
507
                if (revision == 0xFFFF) {
508
                        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST);     /* Reset Host Adapter   */
509
                        if (waitChipReady(hcsp) == FALSE)
510
                                return (-1);
511
                        load_FW(hcsp);  /* Download FW                  */
512
                        setup_SCBs(hcsp);       /* Setup SCB HCS_Base and SCB Size registers */
513
                        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0);   /* clear HOSTSTOP       */
514
                        if (waitFWReady(hcsp) == FALSE)
515
                                return (-1);
516
                        /* Wait for firmware ready     */
517
                } else {
518
                        setup_SCBs(hcsp);       /* Setup SCB HCS_Base and SCB Size registers */
519
                }
520
        } else {                /* Orchid is not Ready          */
521
                ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST);     /* Reset Host Adapter   */
522
                if (waitChipReady(hcsp) == FALSE)
523
                        return (-1);
524
                load_FW(hcsp);  /* Download FW                  */
525
                setup_SCBs(hcsp);       /* Setup SCB HCS_Base and SCB Size registers */
526
                ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);        /* Do Hardware Reset &  */
527
 
528
                /*     clear HOSTSTOP  */
529
                if (waitFWReady(hcsp) == FALSE)         /* Wait for firmware ready      */
530
                        return (-1);
531
        }
532
 
533
/*------------- get serial EEProm settting -------*/
534
 
535
        read_eeprom(hcsp);
536
 
537
        if (nvramp->Revision != 1)
538
                return (-1);
539
 
540
        hcsp->HCS_SCSI_ID = nvramp->SCSI0Id;
541
        hcsp->HCS_BIOS = nvramp->BIOSConfig1;
542
        hcsp->HCS_MaxTar = MAX_TARGETS;
543
        readBytep = (UCHAR *) & (nvramp->Target00Config);
544
        for (i = 0; i < 16; readBytep++, i++) {
545
                hcsp->TargetFlag[i] = *readBytep;
546
                hcsp->MaximumTags[i] = orc_num_scb;
547
        }                       /* for                          */
548
 
549
        if (nvramp->SCSI0Config & NCC_BUSRESET) {       /* Reset SCSI bus               */
550
                hcsp->HCS_Flags |= HCF_SCSI_RESET;
551
        }
552
        ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB);       /* enable RP FIFO interrupt     */
553
        return (0);
554
}
555
 
556
/*****************************************************************************
557
 Function name  : orc_reset_scsi_bus
558
 Description    : Reset registers, reset a hanging bus and
559
                  kill active and disconnected commands for target w/o soft reset
560
 Input          : pHCB  -       Pointer to host adapter structure
561
 Output         : None.
562
 Return         : pSRB  -       Pointer to SCSI request block.
563
*****************************************************************************/
564
int orc_reset_scsi_bus(ORC_HCS * pHCB)
565
{                               /* I need Host Control Block Information */
566
        ULONG flags;
567
 
568
#if 0
569
        printk("inia100: enter inia100_reset\n");
570
#endif
571
 
572
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
573
        save_flags(flags);
574
        cli();
575
#else
576
        spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
577
#endif
578
 
579
        initAFlag(pHCB);
580
        /* reset scsi bus */
581
        ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST);
582
        if (waitSCSIRSTdone(pHCB) == FALSE) {
583
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
584
                restore_flags(flags);
585
#else
586
                spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
587
#endif
588
                return (SCSI_RESET_ERROR);
589
        } else {
590
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
591
                restore_flags(flags);
592
#else
593
                spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
594
#endif
595
                return (SCSI_RESET_SUCCESS);
596
        }
597
}
598
 
599
/*****************************************************************************
600
 Function name  : orc_device_reset
601
 Description    : Reset registers, reset a hanging bus and
602
                  kill active and disconnected commands for target w/o soft reset
603
 Input          : pHCB  -       Pointer to host adapter structure
604
 Output         : None.
605
 Return         : pSRB  -       Pointer to SCSI request block.
606
*****************************************************************************/
607
int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags)
608
{                               /* I need Host Control Block Information */
609
        ORC_SCB *pScb;
610
        ESCB *pVirEscb;
611
        ORC_SCB *pVirScb;
612
        UCHAR i;
613
        ULONG flags;
614
 
615
#if 0
616
        printk("inia100: enter inia100_reset\n");
617
#endif
618
 
619
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
620
        save_flags(flags);
621
        cli();
622
#else
623
        spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
624
#endif
625
        pScb = (ORC_SCB *) NULL;
626
        pVirEscb = (ESCB *) NULL;
627
 
628
        /* setup scatter list address with one buffer */
629
        pVirScb = (ORC_SCB *) pHCB->HCS_virScbArray;
630
 
631
        initAFlag(pHCB);
632
        /* device reset */
633
        for (i = 0; i < orc_num_scb; i++) {
634
                pVirEscb = pVirScb->SCB_EScb;
635
                if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt))
636
                        break;
637
                pVirScb++;
638
        }
639
 
640
        if (i == orc_num_scb) {
641
                printk("Unable to Reset - No SCB Found\n");
642
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
643
                restore_flags(flags);
644
#else
645
                spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
646
#endif
647
                return (SCSI_RESET_NOT_RUNNING);
648
        }
649
        if ((pScb = orc_alloc_scb(pHCB)) == NULL) {
650
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
651
                restore_flags(flags);
652
#else
653
                spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
654
#endif
655
                return (SCSI_RESET_NOT_RUNNING);
656
        }
657
        pScb->SCB_Opcode = ORC_BUSDEVRST;
658
        pScb->SCB_Target = target;
659
        pScb->SCB_HaStat = 0;
660
        pScb->SCB_TaStat = 0;
661
        pScb->SCB_Status = 0x0;
662
        pScb->SCB_Link = 0xFF;
663
        pScb->SCB_Reserved0 = 0;
664
        pScb->SCB_Reserved1 = 0;
665
        pScb->SCB_XferLen = 0;
666
        pScb->SCB_SGLen = 0;
667
 
668
        pVirEscb->SCB_Srb = 0;
669
        if (ResetFlags & SCSI_RESET_SYNCHRONOUS) {
670
                pVirEscb->SCB_Srb = (unsigned char *) SCpnt;
671
        }
672
        orc_exec_scb(pHCB, pScb);       /* Start execute SCB            */
673
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
674
        restore_flags(flags);
675
#else
676
        spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
677
#endif
678
        return SCSI_RESET_PENDING;
679
}
680
 
681
 
682
/***************************************************************************/
683
ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp)
684
{
685
        ORC_SCB *pTmpScb;
686
        UCHAR Ch;
687
        ULONG idx;
688
        UCHAR index;
689
        UCHAR i;
690
        ULONG flags;
691
 
692
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
693
        save_flags(flags);
694
        cli();
695
#else
696
        spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
697
#endif
698
        Ch = hcsp->HCS_Index;
699
        for (i = 0; i < 8; i++) {
700
                for (index = 0; index < 32; index++) {
701
                        if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) {
702
                                hcsp->BitAllocFlag[Ch][i] &= ~(1 << index);
703
                                break;
704
                        }
705
                }
706
                idx = index + 32 * i;
707
                pTmpScb = (PVOID) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB)));
708
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
709
                restore_flags(flags);
710
#else
711
                spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
712
#endif
713
                return (pTmpScb);
714
        }
715
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
716
        restore_flags(flags);
717
#else
718
        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
719
#endif
720
        return (NULL);
721
}
722
 
723
 
724
/***************************************************************************/
725
void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
726
{
727
        ULONG flags;
728
        UCHAR Index;
729
        UCHAR i;
730
        UCHAR Ch;
731
 
732
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
733
        save_flags(flags);
734
        cli();
735
#else
736
        spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
737
#endif
738
        Ch = hcsp->HCS_Index;
739
        Index = scbp->SCB_ScbIdx;
740
        i = Index / 32;
741
        Index %= 32;
742
        hcsp->BitAllocFlag[Ch][i] |= (1 << Index);
743
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
744
        restore_flags(flags);
745
#else
746
        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
747
#endif
748
}
749
 
750
 
751
/*****************************************************************************
752
 Function name  : Addinia100_into_Adapter_table
753
 Description    : This function will scan PCI bus to get all Orchid card
754
 Input          : None.
755
 Output         : None.
756
 Return         : SUCCESSFUL    - Successful scan
757
 ohterwise      - No drives founded
758
*****************************************************************************/
759
int Addinia100_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
760
                                  BYTE bBus, BYTE bDevice)
761
{
762
        unsigned int i, j;
763
 
764
        for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {
765
                if (inia100_adpt[i].ADPT_BIOS < wBIOS)
766
                        continue;
767
                if (inia100_adpt[i].ADPT_BIOS == wBIOS) {
768
                        if (inia100_adpt[i].ADPT_BASE == wBASE)
769
                                if (inia100_adpt[i].ADPT_Bus != 0xFF)
770
                                        return (FAILURE);
771
                                else if (inia100_adpt[i].ADPT_BASE < wBASE)
772
                                        continue;
773
                }
774
                for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
775
                        inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE;
776
                        inia100_adpt[j].ADPT_INTR = inia100_adpt[j - 1].ADPT_INTR;
777
                        inia100_adpt[j].ADPT_BIOS = inia100_adpt[j - 1].ADPT_BIOS;
778
                        inia100_adpt[j].ADPT_Bus = inia100_adpt[j - 1].ADPT_Bus;
779
                        inia100_adpt[j].ADPT_Device = inia100_adpt[j - 1].ADPT_Device;
780
                }
781
                inia100_adpt[i].ADPT_BASE = wBASE;
782
                inia100_adpt[i].ADPT_INTR = bInterrupt;
783
                inia100_adpt[i].ADPT_BIOS = wBIOS;
784
                inia100_adpt[i].ADPT_Bus = bBus;
785
                inia100_adpt[i].ADPT_Device = bDevice;
786
                return (SUCCESSFUL);
787
        }
788
        return (FAILURE);
789
}
790
 
791
 
792
/*****************************************************************************
793
 Function name  : init_inia100Adapter_table
794
 Description    : This function will scan PCI bus to get all Orchid card
795
 Input          : None.
796
 Output         : None.
797
 Return         : SUCCESSFUL    - Successful scan
798
 ohterwise      - No drives founded
799
*****************************************************************************/
800
void init_inia100Adapter_table(void)
801
{
802
        int i;
803
 
804
        for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {   /* Initialize adapter structure */
805
                inia100_adpt[i].ADPT_BIOS = 0xffff;
806
                inia100_adpt[i].ADPT_BASE = 0xffff;
807
                inia100_adpt[i].ADPT_INTR = 0xff;
808
                inia100_adpt[i].ADPT_Bus = 0xff;
809
                inia100_adpt[i].ADPT_Device = 0xff;
810
        }
811
}
812
 
813
/*****************************************************************************
814
 Function name  : get_orcPCIConfig
815
 Description    :
816
 Input          : pHCB  -       Pointer to host adapter structure
817
 Output         : None.
818
 Return         : pSRB  -       Pointer to SCSI request block.
819
*****************************************************************************/
820
void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx)
821
{
822
        pCurHcb->HCS_Base = inia100_adpt[ch_idx].ADPT_BASE;     /* Supply base address  */
823
        pCurHcb->HCS_BIOS = inia100_adpt[ch_idx].ADPT_BIOS;     /* Supply BIOS address  */
824
        pCurHcb->HCS_Intr = inia100_adpt[ch_idx].ADPT_INTR;     /* Supply interrupt line */
825
        return;
826
}
827
 
828
 
829
/*****************************************************************************
830
 Function name  : abort_SCB
831
 Description    : Abort a queued command.
832
                         (commands that are on the bus can't be aborted easily)
833
 Input          : pHCB  -       Pointer to host adapter structure
834
 Output         : None.
835
 Return         : pSRB  -       Pointer to SCSI request block.
836
*****************************************************************************/
837
int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb)
838
{
839
        unsigned char bData, bStatus;
840
 
841
        ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB);  /* Write command */
842
        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
843
        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
844
                return (FALSE);
845
 
846
        ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx);   /* Write address */
847
        ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
848
        if (waitHDOoff(hcsp) == FALSE)  /* Wait HDO off   */
849
                return (FALSE);
850
 
851
        if (waitHDIset(hcsp, &bData) == FALSE)  /* Wait HDI set   */
852
                return (FALSE);
853
        bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
854
        ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);      /* Clear HDI    */
855
 
856
        if (bStatus == 1)       /* 0 - Successfully               */
857
                return (FALSE); /* 1 - Fail                     */
858
        return (TRUE);
859
}
860
 
861
/*****************************************************************************
862
 Function name  : inia100_abort
863
 Description    : Abort a queued command.
864
                         (commands that are on the bus can't be aborted easily)
865
 Input          : pHCB  -       Pointer to host adapter structure
866
 Output         : None.
867
 Return         : pSRB  -       Pointer to SCSI request block.
868
*****************************************************************************/
869
int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt)
870
{
871
        ESCB *pVirEscb;
872
        ORC_SCB *pVirScb;
873
        UCHAR i;
874
        ULONG flags;
875
 
876
#if 0
877
        printk("inia100: abort SRB \n");
878
#endif
879
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
880
        save_flags(flags);
881
        cli();
882
#else
883
        spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
884
#endif
885
 
886
        pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray;
887
 
888
        for (i = 0; i < orc_num_scb; i++, pVirScb++) {
889
                pVirEscb = pVirScb->SCB_EScb;
890
                if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) {
891
                        if (pVirScb->SCB_TagMsg == 0) {
892
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
893
                                restore_flags(flags);
894
#else
895
                                spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
896
#endif
897
                                return (SCSI_ABORT_BUSY);
898
                        } else {
899
                                if (abort_SCB(hcsp, pVirScb)) {
900
                                        pVirEscb->SCB_Srb = NULL;
901
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
902
                                        restore_flags(flags);
903
#else
904
                                        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
905
#endif
906
                                        return (SCSI_ABORT_SUCCESS);
907
                                } else {
908
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
909
                                        restore_flags(flags);
910
#else
911
                                        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
912
#endif
913
                                        return (SCSI_ABORT_NOT_RUNNING);
914
                                }
915
                        }
916
                }
917
        }
918
#if LINUX_VERSION_CODE < CVT_LINUX_VERSION(2,1,95)
919
        restore_flags(flags);
920
#else
921
        spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
922
#endif
923
        return (SCSI_ABORT_NOT_RUNNING);
924
}
925
 
926
/***********************************************************************
927
 Routine Description:
928
          This is the interrupt service routine for the Orchid SCSI adapter.
929
          It reads the interrupt register to determine if the adapter is indeed
930
          the source of the interrupt and clears the interrupt at the device.
931
 Arguments:
932
          HwDeviceExtension - HBA miniport driver's adapter data storage
933
 Return Value:
934
***********************************************************************/
935
void orc_interrupt(
936
                          ORC_HCS * hcsp
937
)
938
{
939
        BYTE bScbIdx;
940
        ORC_SCB *pScb;
941
 
942
        if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) {
943
                return;         // (FALSE);
944
 
945
        }
946
        do {
947
                bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE);
948
 
949
                pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx));
950
                pScb->SCB_Status = 0x0;
951
 
952
                inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb);
953
        } while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT));
954
        return;                 //(TRUE);
955
 
956
}                               /* End of I1060Interrupt() */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.