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