Import 2.3.18pre1
[davej-history.git] / drivers / scsi / inia100.c
blobeab18bad12d763e538a3357d79c50360c31a9216
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: inia100.c
57 * DESCRIPTION:
58 * This is the Linux low-level SCSI driver for Initio INIA100 SCSI host
59 * adapters
60 * 09/24/98 hl - v1.02 initial production release.
61 * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up.
62 **************************************************************************/
64 #define CVT_LINUX_VERSION(V,P,S) (V * 65536 + P * 256 + S)
66 #ifndef LINUX_VERSION_CODE
67 #include <linux/version.h>
68 #endif
70 #ifdef MODULE
71 #include <linux/module.h>
72 #endif
74 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
75 #include <stdarg.h>
76 #include <asm/io.h>
77 #include <asm/irq.h>
78 #include <linux/string.h>
79 #include <linux/errno.h>
80 #include <linux/kernel.h>
81 #include <linux/ioport.h>
82 #include <linux/delay.h>
83 #include <linux/sched.h>
84 #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
85 #include <linux/bios32.h>
86 #endif
87 #include <linux/pci.h>
88 #include <linux/proc_fs.h>
89 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
90 #include <linux/init.h>
91 #endif
92 #include <linux/blk.h>
93 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
94 #include <linux/spinlock.h>
95 #endif
96 #include "sd.h"
97 #include "scsi.h"
98 #include "hosts.h"
99 #include "inia100.h"
100 #include <linux/stat.h>
101 #include <linux/malloc.h>
102 #include <linux/config.h>
105 #else
107 #include <linux/kernel.h>
108 #include <linux/head.h>
109 #include <linux/types.h>
110 #include <linux/string.h>
111 #include <linux/ioport.h>
113 #include <linux/sched.h>
114 #include <linux/proc_fs.h>
115 #include <asm/system.h>
116 #include <asm/io.h>
117 #include "../block/blk.h"
118 #include "scsi.h"
119 #include "sd.h"
120 #include "hosts.h"
121 #include <linux/malloc.h>
122 #include "inia100.h"
123 #endif
125 #ifdef MODULE
126 Scsi_Host_Template driver_template = INIA100;
127 #include "scsi_module.c"
128 #endif
130 #define ORC_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
132 char *inia100_Copyright = "Copyright (C) 1998-99";
133 char *inia100_InitioName = "by Initio Corporation";
134 char *inia100_ProductName = "INI-A100U2W";
135 char *inia100_Version = "v1.02c";
137 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
138 struct proc_dir_entry proc_scsi_inia100 =
140 PROC_SCSI_INIA100, 7, "INIA100",
141 S_IFDIR | S_IRUGO | S_IXUGO, 2,
142 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
144 #endif
146 /* set by inia100_setup according to the command line */
147 static int setup_called = 0;
148 static int orc_num_ch = MAX_SUPPORTED_ADAPTERS; /* Maximum 4 adapters */
150 /* ---- INTERNAL VARIABLES ---- */
151 #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
152 static char *setup_str = (char *) NULL;
154 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
155 static void inia100_intr0(int irq, void *dev_id, struct pt_regs *);
156 static void inia100_intr1(int irq, void *dev_id, struct pt_regs *);
157 static void inia100_intr2(int irq, void *dev_id, struct pt_regs *);
158 static void inia100_intr3(int irq, void *dev_id, struct pt_regs *);
159 static void inia100_intr4(int irq, void *dev_id, struct pt_regs *);
160 static void inia100_intr5(int irq, void *dev_id, struct pt_regs *);
161 static void inia100_intr6(int irq, void *dev_id, struct pt_regs *);
162 static void inia100_intr7(int irq, void *dev_id, struct pt_regs *);
163 #else
164 static void inia100_intr0(int irq, struct pt_regs *);
165 static void inia100_intr1(int irq, struct pt_regs *);
166 static void inia100_intr2(int irq, struct pt_regs *);
167 static void inia100_intr3(int irq, struct pt_regs *);
168 static void inia100_intr4(int irq, struct pt_regs *);
169 static void inia100_intr5(int irq, struct pt_regs *);
170 static void inia100_intr6(int irq, struct pt_regs *);
171 static void inia100_intr7(int irq, struct pt_regs *);
172 #endif
174 static void inia100_panic(char *msg);
175 void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
177 /* ---- EXTERNAL VARIABLES ---- */
178 extern int Addinia100_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE);
179 extern void init_inia100Adapter_table(void);
180 extern ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
181 extern void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp);
182 extern void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp);
183 extern void orc_interrupt(ORC_HCS * hcsp);
184 extern int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags);
185 extern int orc_reset_scsi_bus(ORC_HCS * pHCB);
186 extern int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb);
187 extern int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt);
188 extern void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx);
189 extern int init_orchid(ORC_HCS * hcsp);
191 extern int orc_num_scb;
192 extern ORC_HCS orc_hcs[];
194 /*****************************************************************************
195 Function name : inia100AppendSRBToQueue
196 Description : This function will push current request into save list
197 Input : pSRB - Pointer to SCSI request block.
198 pHCB - Pointer to host adapter structure
199 Output : None.
200 Return : None.
201 *****************************************************************************/
202 static void inia100AppendSRBToQueue(ORC_HCS * pHCB, Scsi_Cmnd * pSRB)
204 ULONG flags;
206 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
207 spin_lock_irqsave(&(pHCB->pSRB_lock), flags);
208 #else
209 save_flags(flags);
210 cli();
211 #endif
213 pSRB->next = NULL; /* Pointer to next */
214 if (pHCB->pSRB_head == NULL)
215 pHCB->pSRB_head = pSRB;
216 else
217 pHCB->pSRB_tail->next = pSRB; /* Pointer to next */
218 pHCB->pSRB_tail = pSRB;
219 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
220 spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);
221 #else
222 restore_flags(flags);
223 #endif
224 return;
227 /*****************************************************************************
228 Function name : inia100PopSRBFromQueue
229 Description : This function will pop current request from save list
230 Input : pHCB - Pointer to host adapter structure
231 Output : None.
232 Return : pSRB - Pointer to SCSI request block.
233 *****************************************************************************/
234 static Scsi_Cmnd *inia100PopSRBFromQueue(ORC_HCS * pHCB)
236 Scsi_Cmnd *pSRB;
237 ULONG flags;
238 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
239 spin_lock_irqsave(&(pHCB->pSRB_lock), flags);
240 #else
241 save_flags(flags);
242 cli();
243 #endif
245 if ((pSRB = (Scsi_Cmnd *) pHCB->pSRB_head) != NULL) {
246 pHCB->pSRB_head = pHCB->pSRB_head->next;
247 pSRB->next = NULL;
249 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
250 spin_unlock_irqrestore(&(pHCB->pSRB_lock), flags);
251 #else
252 restore_flags(flags);
253 #endif
254 return (pSRB);
257 /*****************************************************************************
258 Function name : inia100_setup
259 Description :
260 Input : pHCB - Pointer to host adapter structure
261 Output : None.
262 Return : pSRB - Pointer to SCSI request block.
263 *****************************************************************************/
264 void inia100_setup(char *str, int *ints)
266 if (setup_called)
267 inia100_panic("inia100: inia100_setup called twice.\n");
269 setup_called = ints[0];
270 setup_str = str;
273 /*****************************************************************************
274 Function name : orc_ReturnNumberOfAdapters
275 Description : This function will scan PCI bus to get all Orchid card
276 Input : None.
277 Output : None.
278 Return : SUCCESSFUL - Successful scan
279 ohterwise - No drives founded
280 *****************************************************************************/
281 int orc_ReturnNumberOfAdapters(void)
283 unsigned int i, iAdapters;
285 iAdapters = 0;
287 * PCI-bus probe.
289 if (pcibios_present()) {
290 struct {
291 unsigned short vendor_id;
292 unsigned short device_id;
293 } const inia100_pci_devices[] =
295 {ORC_VENDOR_ID, I920_DEVICE_ID},
296 {ORC_VENDOR_ID, ORC_DEVICE_ID}
299 unsigned int dRegValue;
300 unsigned short command;
301 WORD wBIOS, wBASE;
302 BYTE bPCIBusNum, bInterrupt, bPCIDeviceNum;
304 #ifdef MMAPIO
305 unsigned long page_offset, base;
306 #endif
308 #if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
309 struct pci_dev *pdev = NULL;
310 #else
311 int index;
312 unsigned char pci_bus, pci_devfn;
313 #endif
315 bPCIBusNum = 0;
316 bPCIDeviceNum = 0;
317 init_inia100Adapter_table();
318 for (i = 0; i < NUMBER(inia100_pci_devices); i++) {
319 #if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
320 pdev = NULL;
321 while ((pdev = pci_find_device(inia100_pci_devices[i].vendor_id,
322 inia100_pci_devices[i].device_id,
323 pdev)))
324 #else
325 index = 0;
326 while (!(pcibios_find_device(inia100_pci_devices[i].vendor_id,
327 inia100_pci_devices[i].device_id,
328 index++, &pci_bus, &pci_devfn)))
329 #endif
331 if (iAdapters >= MAX_SUPPORTED_ADAPTERS)
332 break; /* Never greater than maximum */
334 if (i == 0) {
336 printk("inia100: The RAID controller is not supported by\n");
337 printk("inia100: this driver, we are ignoring it.\n");
339 } else {
341 * Read sundry information from PCI BIOS.
343 #if LINUX_VERSION_CODE > CVT_LINUX_VERSION(2,1,92)
344 bPCIBusNum = pdev->bus->number;
345 bPCIDeviceNum = pdev->devfn;
346 dRegValue = pdev->resource[0].start;
347 if (dRegValue == -1) { /* Check return code */
348 printk("\n\rinia100: orchid read configuration error.\n");
349 return (0); /* Read configuration space error */
351 /* <02> read from base address + 0x50 offset to get the wBIOS balue. */
352 wBASE = (WORD) dRegValue;
354 /* Now read the interrupt line */
355 dRegValue = pdev->irq;
356 bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */
357 pci_read_config_word(pdev, PCI_COMMAND, &command);
358 pci_write_config_word(pdev, PCI_COMMAND,
359 command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
361 #else
362 bPCIBusNum = pci_bus;
363 bPCIDeviceNum = pci_devfn;
364 pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_0,
365 &dRegValue);
366 if (dRegValue == -1) { /* Check return code */
367 printk("\n\rinia100: Orchid read configuration error.\n");
368 return (0); /* Read configuration space error */
370 /* <02> read from base address + 0x50 offset to get the wBIOS balue. */
371 wBASE = (WORD) dRegValue;
373 /* Now read the interrupt line */
374 pcibios_read_config_dword(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
375 &dRegValue);
376 bInterrupt = dRegValue & 0xFF; /* Assign interrupt line */
377 pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
378 pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND,
379 command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
380 #endif
381 wBASE &= PCI_BASE_ADDRESS_IO_MASK;
382 wBIOS = ORC_RDWORD(wBASE, 0x50);
384 #ifdef MMAPIO
385 base = wBASE & PAGE_MASK;
386 page_offset = wBASE - base;
389 * replace the next line with this one if you are using 2.1.x:
390 * temp_p->maddr = ioremap(base, page_offset + 256);
392 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,0)
393 wBASE = ioremap(base, page_offset + 256);
394 #else
395 wBASE = (WORD) vremap(base, page_offset + 256);
396 #endif
397 if (wBASE) {
398 wBASE += page_offset;
400 #endif
402 if (Addinia100_into_Adapter_table(wBIOS, wBASE, bInterrupt, bPCIBusNum,
403 bPCIDeviceNum) == SUCCESSFUL)
404 iAdapters++;
406 } /* while(pdev=....) */
407 } /* for PCI_DEVICES */
408 } /* PCI BIOS present */
409 return (iAdapters);
412 /*****************************************************************************
413 Function name : inia100_detect
414 Description :
415 Input : pHCB - Pointer to host adapter structure
416 Output : None.
417 Return : pSRB - Pointer to SCSI request block.
418 *****************************************************************************/
419 int inia100_detect(Scsi_Host_Template * tpnt)
421 ORC_HCS *pHCB;
422 struct Scsi_Host *hreg;
423 U32 sz;
424 U32 i; /* 01/14/98 */
425 int ok = 0, iAdapters;
426 ULONG dBiosAdr;
427 BYTE *pbBiosAdr;
429 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
430 tpnt->proc_dir = &proc_scsi_inia100;
431 #endif
432 if (setup_called) {
433 /* Setup by inia100_setup */
434 printk("inia100: processing commandline: ");
436 /* Get total number of adapters in the motherboard */
437 iAdapters = orc_ReturnNumberOfAdapters();
439 /* printk("inia100: Total Initio Adapters = %d\n", iAdapters); */
440 if (iAdapters == 0) /* If no orc founded, return */
441 return (0);
443 orc_num_ch = (iAdapters > orc_num_ch) ? orc_num_ch : iAdapters;
444 orc_num_scb = ORC_MAXQUEUE;
446 /* clear the memory needed for HCS */
447 i = orc_num_ch * sizeof(ORC_HCS);
448 memset((unsigned char *) &orc_hcs[0], 0, i); /* Initialize orc_hcs 0 */
450 #if 0
451 printk("orc_num_scb= %x orc_num_ch= %x hcsize= %x scbsize= %x escbsize= %x\n",
452 orc_num_scb, orc_num_ch, sizeof(ORC_HCS), sizeof(ORC_SCB), sizeof(ESCB));
453 #endif
455 for (i = 0, pHCB = &orc_hcs[0]; /* Get pointer for control block */
456 i < orc_num_ch;
457 i++, pHCB++) {
459 pHCB->pSRB_head = NULL; /* Initial SRB save queue */
460 pHCB->pSRB_tail = NULL; /* Initial SRB save queue */
461 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
462 pHCB->pSRB_lock = SPIN_LOCK_UNLOCKED; /* SRB save queue lock */
463 #endif
464 /* Get total memory needed for SCB */
465 sz = orc_num_scb * sizeof(ORC_SCB);
466 if ((pHCB->HCS_virScbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) {
467 printk("inia100: SCB memory allocation error\n");
468 return (0);
470 memset((unsigned char *) pHCB->HCS_virScbArray, 0, sz);
471 pHCB->HCS_physScbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virScbArray);
473 /* Get total memory needed for ESCB */
474 sz = orc_num_scb * sizeof(ESCB);
475 if ((pHCB->HCS_virEscbArray = (PVOID) kmalloc(sz, GFP_ATOMIC | GFP_DMA)) == NULL) {
476 printk("inia100: ESCB memory allocation error\n");
477 return (0);
479 memset((unsigned char *) pHCB->HCS_virEscbArray, 0, sz);
480 pHCB->HCS_physEscbArray = (U32) VIRT_TO_BUS(pHCB->HCS_virEscbArray);
482 request_region(pHCB->HCS_Base, 0x100, "inia100"); /* Register */
483 get_orcPCIConfig(pHCB, i);
485 dBiosAdr = pHCB->HCS_BIOS;
486 dBiosAdr = (dBiosAdr << 4);
488 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
489 pbBiosAdr = phys_to_virt(dBiosAdr);
490 #endif
492 if (init_orchid(pHCB)) { /* Initial orchid chip */
493 printk("inia100: initial orchid fail!!\n");
494 return (0);
496 hreg = scsi_register(tpnt, sizeof(ORC_HCS));
497 if (hreg == NULL) {
498 printk("Invalid scsi_register pointer.\n");
500 hreg->io_port = pHCB->HCS_Base;
501 hreg->n_io_port = 0xff;
502 hreg->can_queue = orc_num_scb; /* 03/05/98 */
504 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
505 hreg->unique_id = pHCB->HCS_Base;
506 hreg->max_id = pHCB->HCS_MaxTar;
507 #endif
509 hreg->max_lun = 32; /* 10/21/97 */
511 hreg->max_lun = 8;
512 hreg->max_channel = 1;
514 hreg->irq = pHCB->HCS_Intr;
515 hreg->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */
516 hreg->base = (UCHAR *) pHCB;
518 #if 1
519 hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */
520 #else
521 hreg->sg_tablesize = SG_NONE; /* No SG */
522 #endif
524 /* Initial orc chip */
525 switch (i) {
526 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
527 case 0:
528 ok = request_irq(pHCB->HCS_Intr, inia100_intr0, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);
529 break;
530 case 1:
531 ok = request_irq(pHCB->HCS_Intr, inia100_intr1, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);
532 break;
533 case 2:
534 ok = request_irq(pHCB->HCS_Intr, inia100_intr2, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);
535 break;
536 case 3:
537 ok = request_irq(pHCB->HCS_Intr, inia100_intr3, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);
538 break;
539 case 4:
540 ok = request_irq(pHCB->HCS_Intr, inia100_intr4, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);
541 break;
542 case 5:
543 ok = request_irq(pHCB->HCS_Intr, inia100_intr5, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);
544 break;
545 case 6:
546 ok = request_irq(pHCB->HCS_Intr, inia100_intr6, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);
547 break;
548 case 7:
549 ok = request_irq(pHCB->HCS_Intr, inia100_intr7, SA_INTERRUPT | SA_SHIRQ, "inia100", NULL);
550 break;
551 default:
552 inia100_panic("inia100: Too many host adapters\n");
553 break;
556 if (ok < 0) {
557 if (ok == -EINVAL) {
558 printk("inia100: bad IRQ %d.\n", pHCB->HCS_Intr);
559 printk(" Contact author.\n");
560 } else {
561 if (ok == -EBUSY)
562 printk("inia100: IRQ %d already in use. Configure another.\n", pHCB->HCS_Intr);
563 else {
564 printk("\ninia100: Unexpected error code on requesting IRQ %d.\n",
565 pHCB->HCS_Intr);
566 printk(" Contact author.\n");
569 inia100_panic("inia100: driver needs an IRQ.\n");
571 #endif
574 tpnt->this_id = -1;
575 tpnt->can_queue = 1;
576 return 1;
579 /*****************************************************************************
580 Function name : inia100BuildSCB
581 Description :
582 Input : pHCB - Pointer to host adapter structure
583 Output : None.
584 Return : pSRB - Pointer to SCSI request block.
585 *****************************************************************************/
586 static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, Scsi_Cmnd * SCpnt)
587 { /* Create corresponding SCB */
588 struct scatterlist *pSrbSG;
589 ORC_SG *pSG; /* Pointer to SG list */
590 int i;
591 U32 TotalLen;
592 ESCB *pEScb;
594 pEScb = pSCB->SCB_EScb;
595 pEScb->SCB_Srb = SCpnt;
596 pSG = NULL;
598 pSCB->SCB_Opcode = ORC_EXECSCSI;
599 pSCB->SCB_Flags = SCF_NO_DCHK; /* Clear done bit */
600 pSCB->SCB_Target = SCpnt->target;
601 pSCB->SCB_Lun = SCpnt->lun;
602 pSCB->SCB_Reserved0 = 0;
603 pSCB->SCB_Reserved1 = 0;
604 pSCB->SCB_SGLen = 0;
606 if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) {
607 pSG = (ORC_SG *) & pEScb->ESCB_SGList[0];
608 if (SCpnt->use_sg) {
609 TotalLen = 0;
610 pSCB->SCB_SGLen = (U32) (SCpnt->use_sg * 8);
611 pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
612 for (i = 0; i < SCpnt->use_sg; i++, pSG++, pSrbSG++) {
613 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
614 pSG->SG_Ptr = (U32) (VIRT_TO_BUS(pSrbSG->address));
615 #else
616 pSG->SG_Ptr = (U32) pSrbSG->address;
617 #endif
618 pSG->SG_Len = (U32) pSrbSG->length;
619 TotalLen += (U32) pSrbSG->length;
621 } else { /* Non SG */
622 pSCB->SCB_SGLen = 0x8;
623 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
624 pSG->SG_Ptr = (U32) (VIRT_TO_BUS(SCpnt->request_buffer));
625 #else
626 pSG->SG_PTR = (U32) SCpnt->request_buffer;
627 #endif
628 pSG->SG_Len = (U32) SCpnt->request_bufflen;
631 pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr;
632 pSCB->SCB_HaStat = 0;
633 pSCB->SCB_TaStat = 0;
634 pSCB->SCB_Link = 0xFF;
635 pSCB->SCB_SenseLen = SENSE_SIZE;
636 pSCB->SCB_CDBLen = SCpnt->cmd_len;
637 if (pSCB->SCB_CDBLen >= IMAX_CDB) {
638 printk("max cdb length= %x\b", SCpnt->cmd_len);
639 pSCB->SCB_CDBLen = IMAX_CDB;
641 pSCB->SCB_Ident = SCpnt->lun | DISC_ALLOW;
642 if (SCpnt->device->tagged_supported) { /* Tag Support */
643 pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
644 } else {
645 pSCB->SCB_TagMsg = 0; /* No tag support */
647 memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen);
648 return;
651 /*****************************************************************************
652 Function name : inia100_queue
653 Description : Queue a command and setup interrupts for a free bus.
654 Input : pHCB - Pointer to host adapter structure
655 Output : None.
656 Return : pSRB - Pointer to SCSI request block.
657 *****************************************************************************/
658 int inia100_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
660 register ORC_SCB *pSCB;
661 ORC_HCS *pHCB; /* Point to Host adapter control block */
663 if (SCpnt->lun > 16) {
664 SCpnt->result = (DID_TIME_OUT << 16);
665 done(SCpnt); /* Notify system DONE */
666 return (0);
668 pHCB = (ORC_HCS *) SCpnt->host->base;
669 SCpnt->scsi_done = done;
670 /* Get free SCSI control block */
671 if ((pSCB = orc_alloc_scb(pHCB)) == NULL) {
672 inia100AppendSRBToQueue(pHCB, SCpnt); /* Buffer this request */
673 /* printk("inia100_entry: can't allocate SCB\n"); */
674 return (0);
676 inia100BuildSCB(pHCB, pSCB, SCpnt);
677 orc_exec_scb(pHCB, pSCB); /* Start execute SCB */
679 return (0);
682 /*****************************************************************************
683 Function name : inia100_command
684 Description : We only support command in interrupt-driven fashion
685 Input : pHCB - Pointer to host adapter structure
686 Output : None.
687 Return : pSRB - Pointer to SCSI request block.
688 *****************************************************************************/
689 int inia100_command(Scsi_Cmnd * SCpnt)
691 printk("inia100: interrupt driven driver; use inia100_queue()\n");
692 return -1;
695 /*****************************************************************************
696 Function name : inia100_abort
697 Description : Abort a queued command.
698 (commands that are on the bus can't be aborted easily)
699 Input : pHCB - Pointer to host adapter structure
700 Output : None.
701 Return : pSRB - Pointer to SCSI request block.
702 *****************************************************************************/
703 int inia100_abort(Scsi_Cmnd * SCpnt)
705 ORC_HCS *hcsp;
707 hcsp = (ORC_HCS *) SCpnt->host->base;
708 return orc_abort_srb(hcsp, (ULONG) SCpnt);
711 /*****************************************************************************
712 Function name : inia100_reset
713 Description : Reset registers, reset a hanging bus and
714 kill active and disconnected commands for target w/o soft reset
715 Input : pHCB - Pointer to host adapter structure
716 Output : None.
717 Return : pSRB - Pointer to SCSI request block.
718 *****************************************************************************/
719 int inia100_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
720 { /* I need Host Control Block Information */
721 ORC_HCS *pHCB;
722 pHCB = (ORC_HCS *) SCpnt->host->base;
724 if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
725 return orc_reset_scsi_bus(pHCB);
726 else
727 return orc_device_reset(pHCB, (ULONG) SCpnt, SCpnt->target, reset_flags);
731 /*****************************************************************************
732 Function name : inia100SCBPost
733 Description : This is callback routine be called when orc finish one
734 SCSI command.
735 Input : pHCB - Pointer to host adapter control block.
736 pSCB - Pointer to SCSI control block.
737 Output : None.
738 Return : None.
739 *****************************************************************************/
740 void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
742 Scsi_Cmnd *pSRB; /* Pointer to SCSI request block */
743 ORC_HCS *pHCB;
744 ORC_SCB *pSCB;
745 ESCB *pEScb;
747 pHCB = (ORC_HCS *) pHcb;
748 pSCB = (ORC_SCB *) pScb;
749 pEScb = pSCB->SCB_EScb;
750 if ((pSRB = (Scsi_Cmnd *) pEScb->SCB_Srb) == 0) {
751 printk("inia100SCBPost: SRB pointer is empty\n");
752 orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */
753 return;
755 pEScb->SCB_Srb = NULL;
757 switch (pSCB->SCB_HaStat) {
758 case 0x0:
759 case 0xa: /* Linked command complete without error and linked normally */
760 case 0xb: /* Linked command complete without error interrupt generated */
761 pSCB->SCB_HaStat = 0;
762 break;
764 case 0x11: /* Selection time out-The initiator selection or target
765 reselection was not complete within the SCSI Time out period */
766 pSCB->SCB_HaStat = DID_TIME_OUT;
767 break;
769 case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
770 phase sequence was requested by the target. The host adapter
771 will generate a SCSI Reset Condition, notifying the host with
772 a SCRD interrupt */
773 pSCB->SCB_HaStat = DID_RESET;
774 break;
776 case 0x1a: /* SCB Aborted. 07/21/98 */
777 pSCB->SCB_HaStat = DID_ABORT;
778 break;
780 case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
781 than was allocated by the Data Length field or the sum of the
782 Scatter / Gather Data Length fields. */
783 case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
784 case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. */
786 default:
787 printk("inia100: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
788 pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */
789 break;
792 if (pSCB->SCB_TaStat == 2) { /* Check condition */
793 memcpy((unsigned char *) &pSRB->sense_buffer[0],
794 (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE);
796 pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
797 pSRB->scsi_done(pSRB); /* Notify system DONE */
799 /* Find the next pending SRB */
800 if ((pSRB = inia100PopSRBFromQueue(pHCB)) != NULL) { /* Assume resend will success */
801 /* Reuse old SCB */
802 inia100BuildSCB(pHCB, pSCB, pSRB); /* Create corresponding SCB */
803 orc_exec_scb(pHCB, pSCB); /* Start execute SCB */
804 } else { /* No Pending SRB */
805 orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */
807 return;
810 /*****************************************************************************
811 Function name : inia100_biosparam
812 Description : Return the "logical geometry"
813 Input : pHCB - Pointer to host adapter structure
814 Output : None.
815 Return : pSRB - Pointer to SCSI request block.
816 *****************************************************************************/
817 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
818 int inia100_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
819 #else
820 int inia100_biosparam(Scsi_Disk * disk, int dev, int *info_array)
821 #endif
823 ORC_HCS *pHcb; /* Point to Host adapter control block */
824 ORC_TCS *pTcb;
826 pHcb = (ORC_HCS *) disk->device->host->base;
827 pTcb = &pHcb->HCS_Tcs[disk->device->id];
829 if (pTcb->TCS_DrvHead) {
830 info_array[0] = pTcb->TCS_DrvHead;
831 info_array[1] = pTcb->TCS_DrvSector;
832 info_array[2] = disk->capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
833 } else {
834 if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
835 info_array[0] = 255;
836 info_array[1] = 63;
837 info_array[2] = disk->capacity / 255 / 63;
838 } else {
839 info_array[0] = 64;
840 info_array[1] = 32;
841 info_array[2] = disk->capacity >> 11;
844 return 0;
848 static void subIntr(ORC_HCS * pHCB, int irqno)
850 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
851 unsigned long flags;
853 spin_lock_irqsave(&io_request_lock, flags);
854 #endif
856 if (pHCB->HCS_Intr != irqno) {
857 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
858 spin_unlock_irqrestore(&io_request_lock, flags);
859 #endif
860 return;
862 orc_interrupt(pHCB);
864 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
865 spin_unlock_irqrestore(&io_request_lock, flags);
866 #endif
870 * Interrupts handler (main routine of the driver)
872 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
873 static void inia100_intr0(int irqno, void *dev_id, struct pt_regs *regs)
874 #else
875 static void inia100_intr0(int irqno, struct pt_regs *regs)
876 #endif
878 subIntr(&orc_hcs[0], irqno);
881 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
882 static void inia100_intr1(int irqno, void *dev_id, struct pt_regs *regs)
883 #else
884 static void inia100_intr1(int irqno, struct pt_regs *regs)
885 #endif
887 subIntr(&orc_hcs[1], irqno);
890 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
891 static void inia100_intr2(int irqno, void *dev_id, struct pt_regs *regs)
892 #else
893 static void inia100_intr2(int irqno, struct pt_regs *regs)
894 #endif
896 subIntr(&orc_hcs[2], irqno);
899 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
900 static void inia100_intr3(int irqno, void *dev_id, struct pt_regs *regs)
901 #else
902 static void inia100_intr3(int irqno, struct pt_regs *regs)
903 #endif
905 subIntr(&orc_hcs[3], irqno);
908 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
909 static void inia100_intr4(int irqno, void *dev_id, struct pt_regs *regs)
910 #else
911 static void inia100_intr4(int irqno, struct pt_regs *regs)
912 #endif
914 subIntr(&orc_hcs[4], irqno);
917 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
918 static void inia100_intr5(int irqno, void *dev_id, struct pt_regs *regs)
919 #else
920 static void inia100_intr5(int irqno, struct pt_regs *regs)
921 #endif
923 subIntr(&orc_hcs[5], irqno);
926 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
927 static void inia100_intr6(int irqno, void *dev_id, struct pt_regs *regs)
928 #else
929 static void inia100_intr6(int irqno, struct pt_regs *regs)
930 #endif
932 subIntr(&orc_hcs[6], irqno);
935 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
936 static void inia100_intr7(int irqno, void *dev_id, struct pt_regs *regs)
937 #else
938 static void inia100_intr7(int irqno, struct pt_regs *regs)
939 #endif
941 subIntr(&orc_hcs[7], irqno);
945 * Dump the current driver status and panic...
947 static void inia100_panic(char *msg)
949 printk("\ninia100_panic: %s\n", msg);
950 panic("inia100 panic");
953 /*#include "inia100scsi.c" */