Merge branch 'master'
[pandora-kernel.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/blkdev.h>
30 #include <linux/kernel.h>
31 #include <linux/types.h>
32 #include <linux/string.h>
33 #include <linux/ioport.h>
34 #include <linux/delay.h>
35 #include <linux/interrupt.h>
36 #include <linux/proc_fs.h>
37 #include <linux/spinlock.h>
38 #include <linux/stat.h>
39
40 #include <asm/dma.h>
41 #include <asm/system.h>
42 #include <asm/io.h>
43 #include "scsi.h"
44 #include <scsi/scsi_host.h>
45
46 #include "psi240i.h"
47 #include "psi_chip.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 6     /* 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
371 static irqreturn_t do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
372 {
373         unsigned long flags;
374         struct Scsi_Host *dev = dev_id;
375         
376         spin_lock_irqsave(dev->host_lock, flags);
377         Irq_Handler(irq, dev_id, regs);
378         spin_unlock_irqrestore(dev->host_lock, flags);
379         return IRQ_HANDLED;
380 }
381
382 /****************************************************************
383  *      Name:   Psi240i_QueueCommand
384  *
385  *      Description:    Process a queued command from the SCSI manager.
386  *
387  *      Parameters:             SCpnt - Pointer to SCSI command structure.
388  *                                      done  - Pointer to done function to call.
389  *
390  *      Returns:                Status code.
391  *
392  ****************************************************************/
393 static int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
394         {
395         UCHAR              *cdb = (UCHAR *)SCpnt->cmnd;                                 // Pointer to SCSI CDB
396         PADAPTER240I    padapter = HOSTDATA (SCpnt->device->host);                      // Pointer to adapter control structure
397         POUR_DEVICE             pdev     = &padapter->device [SCpnt->device->id];// Pointer to device information
398         UCHAR                   rc;                                                                                     // command return code
399
400         SCpnt->scsi_done = done;
401         padapter->ide.ide.ides.spigot = pdev->spigot;
402         padapter->buffer = SCpnt->request_buffer;
403         if (done)
404                 {
405                 if ( !pdev->device )
406                         {
407                         SCpnt->result = DID_BAD_TARGET << 16;
408                         done (SCpnt);
409                         return 0;
410                         }
411                 }
412         else
413                 {
414                 printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
415                 return 0;
416                 }
417
418         switch ( *cdb )
419                 {
420                 case SCSIOP_INQUIRY:                                    // inquiry CDB
421                         {
422                         padapter->ide.ide.ide[6] = pdev->byte6;
423                         padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
424                         break;
425                         }
426
427                 case SCSIOP_TEST_UNIT_READY:                    // test unit ready CDB
428                         SCpnt->result = DID_OK << 16;
429                         done (SCpnt);
430                         return 0;
431
432                 case SCSIOP_READ_CAPACITY:                              // read capctiy CDB
433                         {
434                         PREAD_CAPACITY_DATA     pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
435
436                         pdata->blksiz = 0x20000;
437                         XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
438                         SCpnt->result = DID_OK << 16;
439                         done (SCpnt);
440                         return 0;
441                         }
442
443                 case SCSIOP_VERIFY:                                             // verify CDB
444                         *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
445                         padapter->ide.ide.ide[6] |= pdev->byte6;
446                         padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
447                         padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
448                         break;
449
450                 case SCSIOP_READ:                                               // read10 CDB
451                         padapter->startSector = XSCSI2LONG (&cdb[2]);
452                         padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
453                         SetupTransfer (padapter, pdev->byte6);
454                         padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
455                         break;
456
457                 case SCSIOP_READ6:                                              // read6  CDB
458                         padapter->startSector = SCSI2LONG (&cdb[1]);
459                         padapter->sectorCount = cdb[4];
460                         SetupTransfer (padapter, pdev->byte6);
461                         padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
462                         break;
463
464                 case SCSIOP_WRITE:                                              // write10 CDB
465                         padapter->startSector = XSCSI2LONG (&cdb[2]);
466                         padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
467                         SetupTransfer (padapter, pdev->byte6);
468                         padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
469                         break;
470                 case SCSIOP_WRITE6:                                             // write6  CDB
471                         padapter->startSector = SCSI2LONG (&cdb[1]);
472                         padapter->sectorCount = cdb[4];
473                         SetupTransfer (padapter, pdev->byte6);
474                         padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
475                         break;
476
477                 default:
478                         DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
479                         SCpnt->result = DID_ERROR << 16;
480                         done (SCpnt);
481                         return 0;
482                 }
483
484         padapter->SCpnt = SCpnt;                                                                        // Save this command data
485
486         rc = IdeCmd (padapter);
487         if ( rc )
488                 {
489                 padapter->expectingIRQ = 0;
490                 DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
491                 SCpnt->result = DID_ERROR << 16;
492                 done (SCpnt);
493                 return 0;
494                 }
495         DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
496         return 0;
497         }
498
499 /***************************************************************************
500  *      Name:                   ReadChipMemory
501  *
502  *      Description:    Read information from controller memory.
503  *
504  *      Parameters:             psetup  - Pointer to memory image of setup information.
505  *                                      base    - base address of memory.
506  *                                      length  - lenght of data space in bytes.
507  *                                      port    - I/O address of data port.
508  *
509  *      Returns:                Nothing.
510  *
511  **************************************************************************/
512 static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
513         {
514         USHORT  z, zz;
515         UCHAR   *pd = (UCHAR *)pdata;
516         outb_p (SEL_NONE, port + REG_SEL_FAIL);                         // setup data port
517         zz = 0;
518         while ( zz < length )
519                 {
520                 outw_p (base, port + REG_ADDRESS);                              // setup address
521
522                 for ( z = 0;  z < 8;  z++ )
523                         {
524                         if ( (zz + z) < length )
525                         *pd++ = inb_p (port + z);       // read data byte
526                         }
527                 zz += 8;
528                 base += 8;
529                 }
530         }
531 /****************************************************************
532  *      Name:   Psi240i_Detect
533  *
534  *      Description:    Detect and initialize our boards.
535  *
536  *      Parameters:             tpnt - Pointer to SCSI host template structure.
537  *
538  *      Returns:                Number of adapters found.
539  *
540  ****************************************************************/
541 static int Psi240i_Detect (Scsi_Host_Template *tpnt)
542         {
543         int                                     board;
544         int                                     count = 0;
545         int                                     unit;
546         int                                     z;
547         USHORT                          port, port_range = 16;
548         CHIP_CONFIG_N           chipConfig;
549         CHIP_DEVICE_N           chipDevice[8];
550         struct Scsi_Host   *pshost;
551
552         for ( board = 0;  board < MAXBOARDS;  board++ )                                 // scan for I/O ports
553                 {
554                 pshost = NULL;
555                 port = portAddr[board];                                                         // get base address to test
556                 if ( !request_region (port, port_range, "psi240i") )
557                         continue;
558                 if ( inb_p (port + REG_FAIL) != CHIP_ID )                       // do the first test for likley hood that it is us
559                         goto host_init_failure;
560                 outb_p (SEL_NONE, port + REG_SEL_FAIL);                         // setup EEPROM/RAM access
561                 outw (0, port + REG_ADDRESS);                                           // setup EEPROM address zero
562                 if ( inb_p (port) != 0x55 )                                                     // test 1st byte
563                         goto host_init_failure;                                                                 //   nope
564                 if ( inb_p (port + 1) != 0xAA )                                         // test 2nd byte
565                         goto host_init_failure;                                                         //   nope
566
567                 // at this point our board is found and can be accessed.  Now we need to initialize
568                 // our informatation and register with the kernel.
569
570
571                 ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
572                 ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
573                 ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
574
575                 if ( !chipConfig.numDrives )                                            // if no devices on this board
576                         goto host_init_failure;
577
578                 pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
579                 if(pshost == NULL)
580                         goto host_init_failure; 
581
582                 PsiHost[chipConfig.irq - 10] = pshost;
583                 pshost->unique_id = port;
584                 pshost->io_port = port;
585                 pshost->n_io_port = 16;  /* Number of bytes of I/O space used */
586                 pshost->irq = chipConfig.irq;
587
588                 for ( z = 0;  z < 11;  z++ )                                            // build regester address array
589                         HOSTDATA(pshost)->ports[z] = port + z;
590                 HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
591                 HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
592                 DEB (printk ("\nPorts ="));
593                 DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
594
595                 for ( z = 0;  z < chipConfig.numDrives;  ++z )
596                         {
597                         unit = chipDevice[z].channel & 0x0F;
598                         HOSTDATA(pshost)->device[unit].device    = ChipSetup.setupDevice[unit].device;
599                         HOSTDATA(pshost)->device[unit].byte6     = (UCHAR)(((unit & 1) << 4) | 0xE0);
600                         HOSTDATA(pshost)->device[unit].spigot    = (UCHAR)(1 << (unit >> 1));
601                         HOSTDATA(pshost)->device[unit].sectors   = ChipSetup.setupDevice[unit].sectors;
602                         HOSTDATA(pshost)->device[unit].heads     = ChipSetup.setupDevice[unit].heads;
603                         HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
604                         HOSTDATA(pshost)->device[unit].blocks    = ChipSetup.setupDevice[unit].blocks;
605                         DEB (printk ("\nHOSTDATA->device    = %X", HOSTDATA(pshost)->device[unit].device));
606                         DEB (printk ("\n          byte6     = %X", HOSTDATA(pshost)->device[unit].byte6));
607                         DEB (printk ("\n          spigot    = %X", HOSTDATA(pshost)->device[unit].spigot));
608                         DEB (printk ("\n          sectors   = %X", HOSTDATA(pshost)->device[unit].sectors));
609                         DEB (printk ("\n          heads     = %X", HOSTDATA(pshost)->device[unit].heads));
610                         DEB (printk ("\n          cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
611                         DEB (printk ("\n          blocks    = %lX", HOSTDATA(pshost)->device[unit].blocks));
612                         }
613
614                 if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) 
615                         {
616                         printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x  IRQ = %d\n", port, chipConfig.irq);
617                         printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
618                         count++;
619                         continue;
620                         }
621
622                 printk ("Unable to allocate IRQ for PSI-240I controller.\n");
623            
624 host_init_failure:
625                 
626                 release_region (port, port_range);
627                 if (pshost)
628                         scsi_unregister (pshost);
629
630                 }
631         return count;
632         }
633
634 static int Psi240i_Release(struct Scsi_Host *shost)
635 {
636         if (shost->irq)
637                 free_irq(shost->irq, NULL);
638         if (shost->io_port && shost->n_io_port)
639                 release_region(shost->io_port, shost->n_io_port);
640         scsi_unregister(shost);
641         return 0;
642 }
643
644 /****************************************************************
645  *      Name:   Psi240i_BiosParam
646  *
647  *      Description:    Process the biosparam request from the SCSI manager to
648  *                                      return C/H/S data.
649  *
650  *      Parameters:             disk - Pointer to SCSI disk structure.
651  *                                      dev      - Major/minor number from kernel.
652  *                                      geom - Pointer to integer array to place geometry data.
653  *
654  *      Returns:                zero.
655  *
656  ****************************************************************/
657 static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
658                 sector_t capacity, int geom[])
659         {
660         POUR_DEVICE     pdev;
661
662         pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]);
663
664         geom[0] = pdev->heads;
665         geom[1] = pdev->sectors;
666         geom[2] = pdev->cylinders;
667         return 0;
668         }
669
670 MODULE_LICENSE("GPL");
671
672 static Scsi_Host_Template driver_template = {
673         .proc_name              = "psi240i", 
674         .name                   = "PSI-240I EIDE Disk Controller",
675         .detect                 = Psi240i_Detect,
676         .release                = Psi240i_Release,
677         .queuecommand           = Psi240i_QueueCommand,
678         .bios_param             = Psi240i_BiosParam,
679         .can_queue              = 1,
680         .this_id                = -1,
681         .sg_tablesize           = SG_NONE,
682         .cmd_per_lun            = 1, 
683         .use_clustering         = DISABLE_CLUSTERING,
684 };
685 #include "scsi_module.c"