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