import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / drivers / scsi / psi240i.c
1 /*+M*************************************************************************
2  * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
3  *
4  * Copyright (c) 1997 Perceptive Solutions, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; see the file COPYING.  If not, write to
18  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  *
21  *      File Name:              psi240i.c
22  *
23  *      Description:    SCSI driver for the PSI240I EIDE interface card.
24  *
25  *-M*************************************************************************/
26
27 #include <linux/module.h>
28
29 #include <linux/kernel.h>
30 #include <linux/types.h>
31 #include <linux/string.h>
32 #include <linux/ioport.h>
33 #include <linux/delay.h>
34 #include <linux/sched.h>
35 #include <linux/proc_fs.h>
36 #include <linux/spinlock.h>
37 #include <asm/dma.h>
38 #include <asm/system.h>
39 #include <asm/io.h>
40 #include <linux/blk.h>
41 #include "scsi.h"
42 #include "hosts.h"
43
44 #include "psi240i.h"
45 #include "psi_chip.h"
46
47 #include<linux/stat.h>
48
49 //#define DEBUG 1
50
51 #ifdef DEBUG
52 #define DEB(x) x
53 #else
54 #define DEB(x)
55 #endif
56
57 #define MAXBOARDS 2     /* Increase this and the sizes of the arrays below, if you need more. */
58
59 #define PORT_DATA                               0
60 #define PORT_ERROR                              1
61 #define PORT_SECTOR_COUNT               2
62 #define PORT_LBA_0                              3
63 #define PORT_LBA_8                              4
64 #define PORT_LBA_16                             5
65 #define PORT_LBA_24                             6
66 #define PORT_STAT_CMD                   7
67 #define PORT_SEL_FAIL                   8
68 #define PORT_IRQ_STATUS                 9
69 #define PORT_ADDRESS                    10
70 #define PORT_FAIL                               11
71 #define PORT_ALT_STAT                   12
72
73 typedef struct
74         {
75         UCHAR                   device;                         // device code
76         UCHAR                   byte6;                          // device select register image
77         UCHAR                   spigot;                         // spigot number
78         UCHAR                   expectingIRQ;           // flag for expecting and interrupt
79         USHORT                  sectors;                        // number of sectors per track
80         USHORT                  heads;                          // number of heads
81         USHORT                  cylinders;                      // number of cylinders for this device
82         USHORT                  spareword;                      // placeholder
83         ULONG                   blocks;                         // number of blocks on device
84         }       OUR_DEVICE, *POUR_DEVICE;
85
86 typedef struct
87         {
88         USHORT           ports[13];
89         OUR_DEVICE       device[8];
90         Scsi_Cmnd       *pSCmnd;
91         IDE_STRUCT       ide;
92         ULONG            startSector;
93         USHORT           sectorCount;
94         Scsi_Cmnd       *SCpnt;
95         VOID            *buffer;
96         USHORT           expectingIRQ;
97         }       ADAPTER240I, *PADAPTER240I;
98
99 #define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)
100
101 static struct   Scsi_Host *PsiHost[6] = {NULL,};  /* One for each IRQ level (10-15) */
102 static                  IDENTIFY_DATA   identifyData;
103 static                  SETUP                   ChipSetup;
104
105 static  USHORT  portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};
106
107 /****************************************************************
108  *      Name:   WriteData       :LOCAL
109  *
110  *      Description:    Write data to device.
111  *
112  *      Parameters:             padapter - Pointer adapter data structure.
113  *
114  *      Returns:                TRUE if drive does not assert DRQ in time.
115  *
116  ****************************************************************/
117 static int WriteData (PADAPTER240I padapter)
118         {
119         ULONG   timer;
120         USHORT *pports = padapter->ports;
121
122         timer = jiffies + TIMEOUT_DRQ;                                                          // calculate the timeout value
123         do  {
124                 if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
125                         {
126                         outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);
127                         return 0;
128                         }
129                 }       while ( time_after(timer, jiffies) );                                                                   // test for timeout
130
131         padapter->ide.ide.ides.cmd = 0;                                                                 // null out the command byte
132         return 1;
133         }
134 /****************************************************************
135  *      Name:   IdeCmd  :LOCAL
136  *
137  *      Description:    Process a queued command from the SCSI manager.
138  *
139  *      Parameters:             padapter - Pointer adapter data structure.
140  *
141  *      Returns:                Zero if no error or status register contents on error.
142  *
143  ****************************************************************/
144 static UCHAR IdeCmd (PADAPTER240I padapter)
145         {
146         ULONG   timer;
147         USHORT *pports = padapter->ports;
148         UCHAR   status;
149
150         outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]);  // select the spigot
151         outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]);                 // select the drive
152         timer = jiffies + TIMEOUT_READY;                                                        // calculate the timeout value
153         do  {
154                 status = inb_p (padapter->ports[PORT_STAT_CMD]);
155                 if ( status & IDE_STATUS_DRDY )
156                         {
157                         outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
158                         outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
159                         outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
160                         outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
161                         padapter->expectingIRQ = 1;
162                         outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
163
164                         if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
165                                 return (WriteData (padapter));
166
167                         return 0;
168                         }
169                 }       while ( time_after(timer, jiffies) );                                                                   // test for timeout
170
171         padapter->ide.ide.ides.cmd = 0;                                                                 // null out the command byte
172         return status;
173         }
174 /****************************************************************
175  *      Name:   SetupTransfer   :LOCAL
176  *
177  *      Description:    Setup a data transfer command.
178  *
179  *      Parameters:             padapter - Pointer adapter data structure.
180  *                                      drive    - Drive/head register upper nibble only.
181  *
182  *      Returns:                TRUE if no data to transfer.
183  *
184  ****************************************************************/
185 static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)
186         {
187         if ( padapter->sectorCount )
188                 {
189                 *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
190                 padapter->ide.ide.ide[6] |= drive;
191                 padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
192                 padapter->sectorCount -= padapter->ide.ide.ides.sectors;        // bump the start and count for next xfer
193                 padapter->startSector += padapter->ide.ide.ides.sectors;
194                 return 0;
195                 }
196         else
197                 {
198                 padapter->ide.ide.ides.cmd = 0;                                                         // null out the command byte
199                 padapter->SCpnt = NULL;
200                 return 1;
201                 }
202         }
203 /****************************************************************
204  *      Name:   DecodeError     :LOCAL
205  *
206  *      Description:    Decode and process device errors.
207  *
208  *      Parameters:             pshost - Pointer to host data block.
209  *                                      status - Status register code.
210  *
211  *      Returns:                The driver status code.
212  *
213  ****************************************************************/
214 static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
215         {
216         PADAPTER240I    padapter = HOSTDATA(pshost);
217         UCHAR                   error;
218
219         padapter->expectingIRQ = 0;
220         padapter->SCpnt = NULL;
221         if ( status & IDE_STATUS_WRITE_FAULT )
222                 {
223                 return DID_PARITY << 16;
224                 }
225         if ( status & IDE_STATUS_BUSY )
226                 return DID_BUS_BUSY << 16;
227
228         error = inb_p (padapter->ports[PORT_ERROR]);
229         DEB(printk ("\npsi240i error register: %x", error));
230         switch ( error )
231                 {
232                 case IDE_ERROR_AMNF:
233                 case IDE_ERROR_TKONF:
234                 case IDE_ERROR_ABRT:
235                 case IDE_ERROR_IDFN:
236                 case IDE_ERROR_UNC:
237                 case IDE_ERROR_BBK:
238                 default:
239                         return DID_ERROR << 16;
240                 }
241         return DID_ERROR << 16;
242         }
243 /****************************************************************
244  *      Name:   Irq_Handler     :LOCAL
245  *
246  *      Description:    Interrupt handler.
247  *
248  *      Parameters:             irq             - Hardware IRQ number.
249  *                                      dev_id  -
250  *                                      regs    -
251  *
252  *      Returns:                TRUE if drive is not ready in time.
253  *
254  ****************************************************************/
255 static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
256         {
257         struct Scsi_Host   *shost;                      // Pointer to host data block
258         PADAPTER240I            padapter;               // Pointer to adapter control structure
259         USHORT                     *pports;                     // I/O port array
260         Scsi_Cmnd                  *SCpnt;
261         UCHAR                           status;
262         int                                     z;
263
264         DEB(printk ("\npsi240i received interrupt\n"));
265
266         shost = PsiHost[irq - 10];
267         if ( !shost )
268                 panic ("Splunge!");
269
270         padapter = HOSTDATA(shost);
271         pports = padapter->ports;
272         SCpnt = padapter->SCpnt;
273
274         if ( !padapter->expectingIRQ )
275                 {
276                 DEB(printk ("\npsi240i Unsolicited interrupt\n"));
277                 return;
278                 }
279         padapter->expectingIRQ = 0;
280
281         status = inb_p (padapter->ports[PORT_STAT_CMD]);                        // read the device status
282         if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
283                 goto irqerror;
284
285         DEB(printk ("\npsi240i processing interrupt"));
286         switch ( padapter->ide.ide.ides.cmd )                                                   // decide how to handle the interrupt
287                 {
288                 case IDE_CMD_READ_MULTIPLE:
289                         if ( status & IDE_STATUS_DRQ )
290                                 {
291                                 insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);
292                                 padapter->buffer += padapter->ide.ide.ides.sectors * 512;
293                                 if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
294                                         {
295                                         SCpnt->result = DID_OK << 16;
296                                         padapter->SCpnt = NULL;
297                                         SCpnt->scsi_done (SCpnt);
298                                         return;
299                                         }
300                                 if ( !(status = IdeCmd (padapter)) )
301                                         return;
302                                 }
303                         break;
304
305                 case IDE_CMD_WRITE_MULTIPLE:
306                         padapter->buffer += padapter->ide.ide.ides.sectors * 512;
307                         if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
308                                 {
309                                 SCpnt->result = DID_OK << 16;
310                                 padapter->SCpnt = NULL;
311                                 SCpnt->scsi_done (SCpnt);
312                                 return;
313                                 }
314                         if ( !(status = IdeCmd (padapter)) )
315                                 return;
316                         break;
317
318                 case IDE_COMMAND_IDENTIFY:
319                         {
320                         PINQUIRYDATA    pinquiryData  = SCpnt->request_buffer;
321
322                         if ( status & IDE_STATUS_DRQ )
323                                 {
324                                 insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
325
326                                 memset (pinquiryData, 0, SCpnt->request_bufflen);               // Zero INQUIRY data structure.
327                                 pinquiryData->DeviceType = 0;
328                                 pinquiryData->Versions = 2;
329                                 pinquiryData->AdditionalLength = 35 - 4;
330
331                                 // Fill in vendor identification fields.
332                                 for ( z = 0;  z < 20;  z += 2 )
333                                         {
334                                         pinquiryData->VendorId[z]         = ((UCHAR *)identifyData.ModelNumber)[z + 1];
335                                         pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
336                                         }
337
338                                 // Initialize unused portion of product id.
339                                 for ( z = 0;  z < 4;  z++ )
340                                         pinquiryData->ProductId[12 + z] = ' ';
341
342                                 // Move firmware revision from IDENTIFY data to
343                                 // product revision in INQUIRY data.
344                                 for ( z = 0;  z < 4;  z += 2 )
345                                         {
346                                         pinquiryData->ProductRevisionLevel[z]    = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
347                                         pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
348                                         }
349
350                                 SCpnt->result = DID_OK << 16;
351                                 padapter->SCpnt = NULL;
352                                 SCpnt->scsi_done (SCpnt);
353                                 return;
354                                 }
355                         break;
356                         }
357
358                 default:
359                         SCpnt->result = DID_OK << 16;
360                         padapter->SCpnt = NULL;
361                         SCpnt->scsi_done (SCpnt);
362                         return;
363                 }
364
365 irqerror:;
366         DEB(printk ("\npsi240i error  Device Status: %X\n", status));
367         SCpnt->result = DecodeError (shost, status);
368         SCpnt->scsi_done (SCpnt);
369         }
370 static void do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
371         {
372         unsigned long flags;
373
374         spin_lock_irqsave(&io_request_lock, flags);
375         Irq_Handler(irq, dev_id, regs);
376         spin_unlock_irqrestore(&io_request_lock, flags);
377         }
378 /****************************************************************
379  *      Name:   Psi240i_QueueCommand
380  *
381  *      Description:    Process a queued command from the SCSI manager.
382  *
383  *      Parameters:             SCpnt - Pointer to SCSI command structure.
384  *                                      done  - Pointer to done function to call.
385  *
386  *      Returns:                Status code.
387  *
388  ****************************************************************/
389 int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
390         {
391         UCHAR              *cdb = (UCHAR *)SCpnt->cmnd;                                 // Pointer to SCSI CDB
392         PADAPTER240I    padapter = HOSTDATA(SCpnt->host);                       // Pointer to adapter control structure
393         POUR_DEVICE             pdev     = &padapter->device[SCpnt->target];// Pointer to device information
394         UCHAR                   rc;                                                                                     // command return code
395
396         SCpnt->scsi_done = done;
397         padapter->ide.ide.ides.spigot = pdev->spigot;
398         padapter->buffer = SCpnt->request_buffer;
399         if (done)
400                 {
401                 if ( !pdev->device )
402                         {
403                         SCpnt->result = DID_BAD_TARGET << 16;
404                         done (SCpnt);
405                         return 0;
406                         }
407                 }
408         else
409                 {
410                 printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
411                 return 0;
412                 }
413
414         switch ( *cdb )
415                 {
416                 case SCSIOP_INQUIRY:                                    // inquiry CDB
417                         {
418                         padapter->ide.ide.ide[6] = pdev->byte6;
419                         padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
420                         break;
421                         }
422
423                 case SCSIOP_TEST_UNIT_READY:                    // test unit ready CDB
424                         SCpnt->result = DID_OK << 16;
425                         done (SCpnt);
426                         return 0;
427
428                 case SCSIOP_READ_CAPACITY:                              // read capctiy CDB
429                         {
430                         PREAD_CAPACITY_DATA     pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
431
432                         pdata->blksiz = 0x20000;
433                         XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
434                         SCpnt->result = DID_OK << 16;
435                         done (SCpnt);
436                         return 0;
437                         }
438
439                 case SCSIOP_VERIFY:                                             // verify CDB
440                         *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
441                         padapter->ide.ide.ide[6] |= pdev->byte6;
442                         padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
443                         padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
444                         break;
445
446                 case SCSIOP_READ:                                               // read10 CDB
447                         padapter->startSector = XSCSI2LONG (&cdb[2]);
448                         padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
449                         SetupTransfer (padapter, pdev->byte6);
450                         padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
451                         break;
452
453                 case SCSIOP_READ6:                                              // read6  CDB
454                         padapter->startSector = SCSI2LONG (&cdb[1]);
455                         padapter->sectorCount = cdb[4];
456                         SetupTransfer (padapter, pdev->byte6);
457                         padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
458                         break;
459
460                 case SCSIOP_WRITE:                                              // write10 CDB
461                         padapter->startSector = XSCSI2LONG (&cdb[2]);
462                         padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
463                         SetupTransfer (padapter, pdev->byte6);
464                         padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
465                         break;
466                 case SCSIOP_WRITE6:                                             // write6  CDB
467                         padapter->startSector = SCSI2LONG (&cdb[1]);
468                         padapter->sectorCount = cdb[4];
469                         SetupTransfer (padapter, pdev->byte6);
470                         padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
471                         break;
472
473                 default:
474                         DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
475                         SCpnt->result = DID_ERROR << 16;
476                         done (SCpnt);
477                         return 0;
478                 }
479
480         padapter->SCpnt = SCpnt;                                                                        // Save this command data
481
482         rc = IdeCmd (padapter);
483         if ( rc )
484                 {
485                 padapter->expectingIRQ = 0;
486                 DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
487                 SCpnt->result = DID_ERROR << 16;
488                 done (SCpnt);
489                 return 0;
490                 }
491         DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
492         return 0;
493         }
494
495 static void internal_done(Scsi_Cmnd * SCpnt)
496         {
497         SCpnt->SCp.Status++;
498         }
499 /****************************************************************
500  *      Name:   Psi240i_Command
501  *
502  *      Description:    Process a command from the SCSI manager.
503  *
504  *      Parameters:             SCpnt - Pointer to SCSI command structure.
505  *
506  *      Returns:                Status code.
507  *
508  ****************************************************************/
509 int Psi240i_Command (Scsi_Cmnd *SCpnt)
510         {
511         DEB(printk("psi240i_command: ..calling psi240i_queuecommand\n"));
512
513         Psi240i_QueueCommand (SCpnt, internal_done);
514
515     SCpnt->SCp.Status = 0;
516         while (!SCpnt->SCp.Status)
517                 barrier ();
518         return SCpnt->result;
519         }
520 /***************************************************************************
521  *      Name:                   ReadChipMemory
522  *
523  *      Description:    Read information from controller memory.
524  *
525  *      Parameters:             psetup  - Pointer to memory image of setup information.
526  *                                      base    - base address of memory.
527  *                                      length  - lenght of data space in bytes.
528  *                                      port    - I/O address of data port.
529  *
530  *      Returns:                Nothing.
531  *
532  **************************************************************************/
533 void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
534         {
535         USHORT  z, zz;
536         UCHAR   *pd = (UCHAR *)pdata;
537         outb_p (SEL_NONE, port + REG_SEL_FAIL);                         // setup data port
538         zz = 0;
539         while ( zz < length )
540                 {
541                 outw_p (base, port + REG_ADDRESS);                              // setup address
542
543                 for ( z = 0;  z < 8;  z++ )
544                         {
545                         if ( (zz + z) < length )
546                         *pd++ = inb_p (port + z);       // read data byte
547                         }
548                 zz += 8;
549                 base += 8;
550                 }
551         }
552 /****************************************************************
553  *      Name:   Psi240i_Detect
554  *
555  *      Description:    Detect and initialize our boards.
556  *
557  *      Parameters:             tpnt - Pointer to SCSI host template structure.
558  *
559  *      Returns:                Number of adapters found.
560  *
561  ****************************************************************/
562 int Psi240i_Detect (Scsi_Host_Template *tpnt)
563         {
564         int                                     board;
565         int                                     count = 0;
566         int                                     unit;
567         int                                     z;
568         USHORT                          port;
569         CHIP_CONFIG_N           chipConfig;
570         CHIP_DEVICE_N           chipDevice[8];
571         struct Scsi_Host   *pshost;
572         ULONG                           flags;
573
574         for ( board = 0;  board < 6;  board++ )                                 // scan for I/O ports
575                 {
576                 port = portAddr[board];                                                         // get base address to test
577                 if ( check_region (port, 16) )                                          // test for I/O addresses available
578                         continue;                                                                               //   nope
579                 if ( inb_p (port + REG_FAIL) != CHIP_ID )                       // do the first test for likley hood that it is us
580                         continue;
581                 outb_p (SEL_NONE, port + REG_SEL_FAIL);                         // setup EEPROM/RAM access
582                 outw (0, port + REG_ADDRESS);                                           // setup EEPROM address zero
583                 if ( inb_p (port) != 0x55 )                                                     // test 1st byte
584                         continue;                                                                               //   nope
585                 if ( inb_p (port + 1) != 0xAA )                                         // test 2nd byte
586                         continue;                                                                               //   nope
587
588                 // at this point our board is found and can be accessed.  Now we need to initialize
589                 // our informatation and register with the kernel.
590
591
592                 ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
593                 ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
594                 ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
595
596                 if ( !chipConfig.numDrives )                                            // if no devices on this board
597                         continue;
598
599                 pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
600                 if(pshost == NULL)
601                         continue;
602
603                 save_flags (flags);
604                 cli ();
605                 if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", NULL) )
606                         {
607                         printk ("Unable to allocate IRQ for PSI-240I controller.\n");
608                         restore_flags (flags);
609                         goto unregister;
610                         }
611
612                 PsiHost[chipConfig.irq - 10] = pshost;
613                 pshost->unique_id = port;
614                 pshost->io_port = port;
615                 pshost->n_io_port = 16;  /* Number of bytes of I/O space used */
616                 pshost->irq = chipConfig.irq;
617
618                 for ( z = 0;  z < 11;  z++ )                                            // build regester address array
619                         HOSTDATA(pshost)->ports[z] = port + z;
620                 HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
621                 HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
622                 DEB (printk ("\nPorts ="));
623                 DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
624
625                 for ( z = 0;  z < chipConfig.numDrives;  ++z )
626                         {
627                         unit = chipDevice[z].channel & 0x0F;
628                         HOSTDATA(pshost)->device[unit].device    = ChipSetup.setupDevice[unit].device;
629                         HOSTDATA(pshost)->device[unit].byte6     = (UCHAR)(((unit & 1) << 4) | 0xE0);
630                         HOSTDATA(pshost)->device[unit].spigot    = (UCHAR)(1 << (unit >> 1));
631                         HOSTDATA(pshost)->device[unit].sectors   = ChipSetup.setupDevice[unit].sectors;
632                         HOSTDATA(pshost)->device[unit].heads     = ChipSetup.setupDevice[unit].heads;
633                         HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
634                         HOSTDATA(pshost)->device[unit].blocks    = ChipSetup.setupDevice[unit].blocks;
635                         DEB (printk ("\nHOSTDATA->device    = %X", HOSTDATA(pshost)->device[unit].device));
636                         DEB (printk ("\n          byte6     = %X", HOSTDATA(pshost)->device[unit].byte6));
637                         DEB (printk ("\n          spigot    = %X", HOSTDATA(pshost)->device[unit].spigot));
638                         DEB (printk ("\n          sectors   = %X", HOSTDATA(pshost)->device[unit].sectors));
639                         DEB (printk ("\n          heads     = %X", HOSTDATA(pshost)->device[unit].heads));
640                         DEB (printk ("\n          cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
641                         DEB (printk ("\n          blocks    = %lX", HOSTDATA(pshost)->device[unit].blocks));
642                         }
643
644                 restore_flags (flags);
645                 printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x  IRQ = %d\n", port, chipConfig.irq);
646                 printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
647                 count++;
648                 continue;
649
650 unregister:;
651                 scsi_unregister (pshost);
652                 }
653         return count;
654         }
655 /****************************************************************
656  *      Name:   Psi240i_Abort
657  *
658  *      Description:    Process the Abort command from the SCSI manager.
659  *
660  *      Parameters:             SCpnt - Pointer to SCSI command structure.
661  *
662  *      Returns:                Allways snooze.
663  *
664  ****************************************************************/
665 int Psi240i_Abort (Scsi_Cmnd *SCpnt)
666         {
667         DEB (printk ("psi240i_abort\n"));
668         return SCSI_ABORT_SNOOZE;
669         }
670 /****************************************************************
671  *      Name:   Psi240i_Reset
672  *
673  *      Description:    Process the Reset command from the SCSI manager.
674  *
675  *      Parameters:             SCpnt - Pointer to SCSI command structure.
676  *                                      flags - Flags about the reset command
677  *
678  *      Returns:                No active command at this time, so this means
679  *                                      that each time we got some kind of response the
680  *                                      last time through.  Tell the mid-level code to
681  *                                      request sense information in order to decide what
682  *                                      to do next.
683  *
684  ****************************************************************/
685 int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
686         {
687         return SCSI_RESET_PUNT;
688         }
689
690 #include "sd.h"
691
692 /****************************************************************
693  *      Name:   Psi240i_BiosParam
694  *
695  *      Description:    Process the biosparam request from the SCSI manager to
696  *                                      return C/H/S data.
697  *
698  *      Parameters:             disk - Pointer to SCSI disk structure.
699  *                                      dev      - Major/minor number from kernel.
700  *                                      geom - Pointer to integer array to place geometry data.
701  *
702  *      Returns:                zero.
703  *
704  ****************************************************************/
705 int Psi240i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
706         {
707         POUR_DEVICE     pdev;
708
709         pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
710
711         geom[0] = pdev->heads;
712         geom[1] = pdev->sectors;
713         geom[2] = pdev->cylinders;
714         return 0;
715         }
716
717 MODULE_LICENSE("GPL");
718
719 /* Eventually this will go into an include file, but this will be later */
720 static Scsi_Host_Template driver_template = PSI240I;
721
722 #include "scsi_module.c"
723