Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/cooloney...
[linux-2.6] / 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         struct scsi_cmnd *pSCmnd;
91         IDE_STRUCT       ide;
92         ULONG            startSector;
93         USHORT           sectorCount;
94         struct 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  *
251  *      Returns:                TRUE if drive is not ready in time.
252  *
253  ****************************************************************/
254 static void Irq_Handler (int irq, void *dev_id)
255         {
256         struct Scsi_Host *shost;        // Pointer to host data block
257         PADAPTER240I padapter;          // Pointer to adapter control structure
258         USHORT *pports;                 // I/O port array
259         struct scsi_cmnd *SCpnt;
260         UCHAR status;
261         int z;
262
263         DEB(printk ("\npsi240i received interrupt\n"));
264
265         shost = PsiHost[irq - 10];
266         if ( !shost )
267                 panic ("Splunge!");
268
269         padapter = HOSTDATA(shost);
270         pports = padapter->ports;
271         SCpnt = padapter->SCpnt;
272
273         if ( !padapter->expectingIRQ )
274                 {
275                 DEB(printk ("\npsi240i Unsolicited interrupt\n"));
276                 return;
277                 }
278         padapter->expectingIRQ = 0;
279
280         status = inb_p (padapter->ports[PORT_STAT_CMD]);                        // read the device status
281         if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
282                 goto irqerror;
283
284         DEB(printk ("\npsi240i processing interrupt"));
285         switch ( padapter->ide.ide.ides.cmd )                                                   // decide how to handle the interrupt
286                 {
287                 case IDE_CMD_READ_MULTIPLE:
288                         if ( status & IDE_STATUS_DRQ )
289                                 {
290                                 insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);
291                                 padapter->buffer += padapter->ide.ide.ides.sectors * 512;
292                                 if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
293                                         {
294                                         SCpnt->result = DID_OK << 16;
295                                         padapter->SCpnt = NULL;
296                                         SCpnt->scsi_done (SCpnt);
297                                         return;
298                                         }
299                                 if ( !(status = IdeCmd (padapter)) )
300                                         return;
301                                 }
302                         break;
303
304                 case IDE_CMD_WRITE_MULTIPLE:
305                         padapter->buffer += padapter->ide.ide.ides.sectors * 512;
306                         if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
307                                 {
308                                 SCpnt->result = DID_OK << 16;
309                                 padapter->SCpnt = NULL;
310                                 SCpnt->scsi_done (SCpnt);
311                                 return;
312                                 }
313                         if ( !(status = IdeCmd (padapter)) )
314                                 return;
315                         break;
316
317                 case IDE_COMMAND_IDENTIFY:
318                         {
319                         PINQUIRYDATA    pinquiryData  = SCpnt->request_buffer;
320
321                         if ( status & IDE_STATUS_DRQ )
322                                 {
323                                 insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
324
325                                 memset (pinquiryData, 0, SCpnt->request_bufflen);               // Zero INQUIRY data structure.
326                                 pinquiryData->DeviceType = 0;
327                                 pinquiryData->Versions = 2;
328                                 pinquiryData->AdditionalLength = 35 - 4;
329
330                                 // Fill in vendor identification fields.
331                                 for ( z = 0;  z < 8;  z += 2 )
332                                         {
333                                         pinquiryData->VendorId[z]         = ((UCHAR *)identifyData.ModelNumber)[z + 1];
334                                         pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
335                                         }
336
337                                 // Initialize unused portion of product id.
338                                 for ( z = 0;  z < 4;  z++ )
339                                         pinquiryData->ProductId[12 + z] = ' ';
340
341                                 // Move firmware revision from IDENTIFY data to
342                                 // product revision in INQUIRY data.
343                                 for ( z = 0;  z < 4;  z += 2 )
344                                         {
345                                         pinquiryData->ProductRevisionLevel[z]    = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
346                                         pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
347                                         }
348
349                                 SCpnt->result = DID_OK << 16;
350                                 padapter->SCpnt = NULL;
351                                 SCpnt->scsi_done (SCpnt);
352                                 return;
353                                 }
354                         break;
355                         }
356
357                 default:
358                         SCpnt->result = DID_OK << 16;
359                         padapter->SCpnt = NULL;
360                         SCpnt->scsi_done (SCpnt);
361                         return;
362                 }
363
364 irqerror:;
365         DEB(printk ("\npsi240i error  Device Status: %X\n", status));
366         SCpnt->result = DecodeError (shost, status);
367         SCpnt->scsi_done (SCpnt);
368         }
369
370 static irqreturn_t do_Irq_Handler (int irq, void *dev_id)
371 {
372         unsigned long flags;
373         struct Scsi_Host *dev = dev_id;
374         
375         spin_lock_irqsave(dev->host_lock, flags);
376         Irq_Handler(irq, dev_id);
377         spin_unlock_irqrestore(dev->host_lock, flags);
378         return IRQ_HANDLED;
379 }
380
381 /****************************************************************
382  *      Name:   Psi240i_QueueCommand
383  *
384  *      Description:    Process a queued command from the SCSI manager.
385  *
386  *      Parameters:             SCpnt - Pointer to SCSI command structure.
387  *                                      done  - Pointer to done function to call.
388  *
389  *      Returns:                Status code.
390  *
391  ****************************************************************/
392 static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt,
393                                 void (*done)(struct scsi_cmnd *))
394         {
395         UCHAR *cdb = (UCHAR *)SCpnt->cmnd;
396         // Pointer to SCSI CDB
397         PADAPTER240I padapter = HOSTDATA (SCpnt->device->host);
398         // Pointer to adapter control structure
399         POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];
400         // Pointer to device information
401         UCHAR rc;
402         // command return code
403
404         SCpnt->scsi_done = done;
405         padapter->ide.ide.ides.spigot = pdev->spigot;
406         padapter->buffer = SCpnt->request_buffer;
407         if (done)
408                 {
409                 if ( !pdev->device )
410                         {
411                         SCpnt->result = DID_BAD_TARGET << 16;
412                         done (SCpnt);
413                         return 0;
414                         }
415                 }
416         else
417                 {
418                 printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
419                 return 0;
420                 }
421
422         switch ( *cdb )
423                 {
424                 case SCSIOP_INQUIRY:                                    // inquiry CDB
425                         {
426                         padapter->ide.ide.ide[6] = pdev->byte6;
427                         padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
428                         break;
429                         }
430
431                 case SCSIOP_TEST_UNIT_READY:                    // test unit ready CDB
432                         SCpnt->result = DID_OK << 16;
433                         done (SCpnt);
434                         return 0;
435
436                 case SCSIOP_READ_CAPACITY:                              // read capctiy CDB
437                         {
438                         PREAD_CAPACITY_DATA     pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
439
440                         pdata->blksiz = 0x20000;
441                         XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
442                         SCpnt->result = DID_OK << 16;
443                         done (SCpnt);
444                         return 0;
445                         }
446
447                 case SCSIOP_VERIFY:                                             // verify CDB
448                         *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
449                         padapter->ide.ide.ide[6] |= pdev->byte6;
450                         padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
451                         padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
452                         break;
453
454                 case SCSIOP_READ:                                               // read10 CDB
455                         padapter->startSector = XSCSI2LONG (&cdb[2]);
456                         padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
457                         SetupTransfer (padapter, pdev->byte6);
458                         padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
459                         break;
460
461                 case SCSIOP_READ6:                                              // read6  CDB
462                         padapter->startSector = SCSI2LONG (&cdb[1]);
463                         padapter->sectorCount = cdb[4];
464                         SetupTransfer (padapter, pdev->byte6);
465                         padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
466                         break;
467
468                 case SCSIOP_WRITE:                                              // write10 CDB
469                         padapter->startSector = XSCSI2LONG (&cdb[2]);
470                         padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
471                         SetupTransfer (padapter, pdev->byte6);
472                         padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
473                         break;
474                 case SCSIOP_WRITE6:                                             // write6  CDB
475                         padapter->startSector = SCSI2LONG (&cdb[1]);
476                         padapter->sectorCount = cdb[4];
477                         SetupTransfer (padapter, pdev->byte6);
478                         padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
479                         break;
480
481                 default:
482                         DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
483                         SCpnt->result = DID_ERROR << 16;
484                         done (SCpnt);
485                         return 0;
486                 }
487
488         padapter->SCpnt = SCpnt;                                                                        // Save this command data
489
490         rc = IdeCmd (padapter);
491         if ( rc )
492                 {
493                 padapter->expectingIRQ = 0;
494                 DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
495                 SCpnt->result = DID_ERROR << 16;
496                 done (SCpnt);
497                 return 0;
498                 }
499         DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
500         return 0;
501         }
502
503 /***************************************************************************
504  *      Name:                   ReadChipMemory
505  *
506  *      Description:    Read information from controller memory.
507  *
508  *      Parameters:             psetup  - Pointer to memory image of setup information.
509  *                                      base    - base address of memory.
510  *                                      length  - lenght of data space in bytes.
511  *                                      port    - I/O address of data port.
512  *
513  *      Returns:                Nothing.
514  *
515  **************************************************************************/
516 static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
517         {
518         USHORT  z, zz;
519         UCHAR   *pd = (UCHAR *)pdata;
520         outb_p (SEL_NONE, port + REG_SEL_FAIL);                         // setup data port
521         zz = 0;
522         while ( zz < length )
523                 {
524                 outw_p (base, port + REG_ADDRESS);                              // setup address
525
526                 for ( z = 0;  z < 8;  z++ )
527                         {
528                         if ( (zz + z) < length )
529                         *pd++ = inb_p (port + z);       // read data byte
530                         }
531                 zz += 8;
532                 base += 8;
533                 }
534         }
535 /****************************************************************
536  *      Name:   Psi240i_Detect
537  *
538  *      Description:    Detect and initialize our boards.
539  *
540  *      Parameters:             tpnt - Pointer to SCSI host template structure.
541  *
542  *      Returns:                Number of adapters found.
543  *
544  ****************************************************************/
545 static int Psi240i_Detect (struct scsi_host_template *tpnt)
546         {
547         int                                     board;
548         int                                     count = 0;
549         int                                     unit;
550         int                                     z;
551         USHORT                          port, port_range = 16;
552         CHIP_CONFIG_N           chipConfig;
553         CHIP_DEVICE_N           chipDevice[8];
554         struct Scsi_Host   *pshost;
555
556         for ( board = 0;  board < MAXBOARDS;  board++ )                                 // scan for I/O ports
557                 {
558                 pshost = NULL;
559                 port = portAddr[board];                                                         // get base address to test
560                 if ( !request_region (port, port_range, "psi240i") )
561                         continue;
562                 if ( inb_p (port + REG_FAIL) != CHIP_ID )                       // do the first test for likley hood that it is us
563                         goto host_init_failure;
564                 outb_p (SEL_NONE, port + REG_SEL_FAIL);                         // setup EEPROM/RAM access
565                 outw (0, port + REG_ADDRESS);                                           // setup EEPROM address zero
566                 if ( inb_p (port) != 0x55 )                                                     // test 1st byte
567                         goto host_init_failure;                                                                 //   nope
568                 if ( inb_p (port + 1) != 0xAA )                                         // test 2nd byte
569                         goto host_init_failure;                                                         //   nope
570
571                 // at this point our board is found and can be accessed.  Now we need to initialize
572                 // our informatation and register with the kernel.
573
574
575                 ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
576                 ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
577                 ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
578
579                 if ( !chipConfig.numDrives )                                            // if no devices on this board
580                         goto host_init_failure;
581
582                 pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
583                 if(pshost == NULL)
584                         goto host_init_failure; 
585
586                 PsiHost[chipConfig.irq - 10] = pshost;
587                 pshost->unique_id = port;
588                 pshost->io_port = port;
589                 pshost->n_io_port = 16;  /* Number of bytes of I/O space used */
590                 pshost->irq = chipConfig.irq;
591
592                 for ( z = 0;  z < 11;  z++ )                                            // build regester address array
593                         HOSTDATA(pshost)->ports[z] = port + z;
594                 HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
595                 HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
596                 DEB (printk ("\nPorts ="));
597                 DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
598
599                 for ( z = 0;  z < chipConfig.numDrives;  ++z )
600                         {
601                         unit = chipDevice[z].channel & 0x0F;
602                         HOSTDATA(pshost)->device[unit].device    = ChipSetup.setupDevice[unit].device;
603                         HOSTDATA(pshost)->device[unit].byte6     = (UCHAR)(((unit & 1) << 4) | 0xE0);
604                         HOSTDATA(pshost)->device[unit].spigot    = (UCHAR)(1 << (unit >> 1));
605                         HOSTDATA(pshost)->device[unit].sectors   = ChipSetup.setupDevice[unit].sectors;
606                         HOSTDATA(pshost)->device[unit].heads     = ChipSetup.setupDevice[unit].heads;
607                         HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
608                         HOSTDATA(pshost)->device[unit].blocks    = ChipSetup.setupDevice[unit].blocks;
609                         DEB (printk ("\nHOSTDATA->device    = %X", HOSTDATA(pshost)->device[unit].device));
610                         DEB (printk ("\n          byte6     = %X", HOSTDATA(pshost)->device[unit].byte6));
611                         DEB (printk ("\n          spigot    = %X", HOSTDATA(pshost)->device[unit].spigot));
612                         DEB (printk ("\n          sectors   = %X", HOSTDATA(pshost)->device[unit].sectors));
613                         DEB (printk ("\n          heads     = %X", HOSTDATA(pshost)->device[unit].heads));
614                         DEB (printk ("\n          cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
615                         DEB (printk ("\n          blocks    = %lX", HOSTDATA(pshost)->device[unit].blocks));
616                         }
617
618                 if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) 
619                         {
620                         printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x  IRQ = %d\n", port, chipConfig.irq);
621                         printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
622                         count++;
623                         continue;
624                         }
625
626                 printk ("Unable to allocate IRQ for PSI-240I controller.\n");
627            
628 host_init_failure:
629                 
630                 release_region (port, port_range);
631                 if (pshost)
632                         scsi_unregister (pshost);
633
634                 }
635         return count;
636         }
637
638 static int Psi240i_Release(struct Scsi_Host *shost)
639 {
640         if (shost->irq)
641                 free_irq(shost->irq, NULL);
642         if (shost->io_port && shost->n_io_port)
643                 release_region(shost->io_port, shost->n_io_port);
644         scsi_unregister(shost);
645         return 0;
646 }
647
648 /****************************************************************
649  *      Name:   Psi240i_BiosParam
650  *
651  *      Description:    Process the biosparam request from the SCSI manager to
652  *                                      return C/H/S data.
653  *
654  *      Parameters:             disk - Pointer to SCSI disk structure.
655  *                                      dev      - Major/minor number from kernel.
656  *                                      geom - Pointer to integer array to place geometry data.
657  *
658  *      Returns:                zero.
659  *
660  ****************************************************************/
661 static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
662                 sector_t capacity, int geom[])
663         {
664         POUR_DEVICE     pdev;
665
666         pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]);
667
668         geom[0] = pdev->heads;
669         geom[1] = pdev->sectors;
670         geom[2] = pdev->cylinders;
671         return 0;
672         }
673
674 MODULE_LICENSE("GPL");
675
676 static struct scsi_host_template driver_template = {
677         .proc_name              = "psi240i", 
678         .name                   = "PSI-240I EIDE Disk Controller",
679         .detect                 = Psi240i_Detect,
680         .release                = Psi240i_Release,
681         .queuecommand           = Psi240i_QueueCommand,
682         .bios_param             = Psi240i_BiosParam,
683         .can_queue              = 1,
684         .this_id                = -1,
685         .sg_tablesize           = SG_NONE,
686         .cmd_per_lun            = 1, 
687         .use_clustering         = DISABLE_CLUSTERING,
688 };
689 #include "scsi_module.c"