1 /*+M*************************************************************************
 
   2  * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
 
   4  * Copyright (c) 1997 Perceptive Solutions, Inc.
 
   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)
 
  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.
 
  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.
 
  21  *      File Name:              psi240i.c
 
  23  *      Description:    SCSI driver for the PSI240I EIDE interface card.
 
  25  *-M*************************************************************************/
 
  27 #include <linux/module.h>
 
  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>
 
  41 #include <asm/system.h>
 
  44 #include <scsi/scsi_host.h>
 
  57 #define MAXBOARDS 6     /* Increase this and the sizes of the arrays below, if you need more. */
 
  61 #define PORT_SECTOR_COUNT               2
 
  66 #define PORT_STAT_CMD                   7
 
  67 #define PORT_SEL_FAIL                   8
 
  68 #define PORT_IRQ_STATUS                 9
 
  69 #define PORT_ADDRESS                    10
 
  71 #define PORT_ALT_STAT                   12
 
  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;
 
  97         }       ADAPTER240I, *PADAPTER240I;
 
  99 #define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)
 
 101 static struct   Scsi_Host *PsiHost[6] = {NULL,};  /* One for each IRQ level (10-15) */
 
 102 static                  IDENTIFY_DATA   identifyData;
 
 103 static                  SETUP                   ChipSetup;
 
 105 static  USHORT  portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};
 
 107 /****************************************************************
 
 108  *      Name:   WriteData       :LOCAL
 
 110  *      Description:    Write data to device.
 
 112  *      Parameters:             padapter - Pointer adapter data structure.
 
 114  *      Returns:                TRUE if drive does not assert DRQ in time.
 
 116  ****************************************************************/
 
 117 static int WriteData (PADAPTER240I padapter)
 
 120         USHORT *pports = padapter->ports;
 
 122         timer = jiffies + TIMEOUT_DRQ;                                                          // calculate the timeout value
 
 124                 if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
 
 126                         outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);
 
 129                 }       while ( time_after(timer, jiffies) );                                                                   // test for timeout
 
 131         padapter->ide.ide.ides.cmd = 0;                                                                 // null out the command byte
 
 134 /****************************************************************
 
 135  *      Name:   IdeCmd  :LOCAL
 
 137  *      Description:    Process a queued command from the SCSI manager.
 
 139  *      Parameters:             padapter - Pointer adapter data structure.
 
 141  *      Returns:                Zero if no error or status register contents on error.
 
 143  ****************************************************************/
 
 144 static UCHAR IdeCmd (PADAPTER240I padapter)
 
 147         USHORT *pports = padapter->ports;
 
 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
 
 154                 status = inb_p (padapter->ports[PORT_STAT_CMD]);
 
 155                 if ( status & IDE_STATUS_DRDY )
 
 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]);
 
 164                         if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
 
 165                                 return (WriteData (padapter));
 
 169                 }       while ( time_after(timer, jiffies) );                                                                   // test for timeout
 
 171         padapter->ide.ide.ides.cmd = 0;                                                                 // null out the command byte
 
 174 /****************************************************************
 
 175  *      Name:   SetupTransfer   :LOCAL
 
 177  *      Description:    Setup a data transfer command.
 
 179  *      Parameters:             padapter - Pointer adapter data structure.
 
 180  *                                      drive    - Drive/head register upper nibble only.
 
 182  *      Returns:                TRUE if no data to transfer.
 
 184  ****************************************************************/
 
 185 static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)
 
 187         if ( padapter->sectorCount )
 
 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;
 
 198                 padapter->ide.ide.ides.cmd = 0;                                                         // null out the command byte
 
 199                 padapter->SCpnt = NULL;
 
 203 /****************************************************************
 
 204  *      Name:   DecodeError     :LOCAL
 
 206  *      Description:    Decode and process device errors.
 
 208  *      Parameters:             pshost - Pointer to host data block.
 
 209  *                                      status - Status register code.
 
 211  *      Returns:                The driver status code.
 
 213  ****************************************************************/
 
 214 static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
 
 216         PADAPTER240I    padapter = HOSTDATA(pshost);
 
 219         padapter->expectingIRQ = 0;
 
 220         padapter->SCpnt = NULL;
 
 221         if ( status & IDE_STATUS_WRITE_FAULT )
 
 223                 return DID_PARITY << 16;
 
 225         if ( status & IDE_STATUS_BUSY )
 
 226                 return DID_BUS_BUSY << 16;
 
 228         error = inb_p (padapter->ports[PORT_ERROR]);
 
 229         DEB(printk ("\npsi240i error register: %x", error));
 
 233                 case IDE_ERROR_TKONF:
 
 239                         return DID_ERROR << 16;
 
 241         return DID_ERROR << 16;
 
 243 /****************************************************************
 
 244  *      Name:   Irq_Handler     :LOCAL
 
 246  *      Description:    Interrupt handler.
 
 248  *      Parameters:             irq             - Hardware IRQ number.
 
 252  *      Returns:                TRUE if drive is not ready in time.
 
 254  ****************************************************************/
 
 255 static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
 
 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
 
 264         DEB(printk ("\npsi240i received interrupt\n"));
 
 266         shost = PsiHost[irq - 10];
 
 270         padapter = HOSTDATA(shost);
 
 271         pports = padapter->ports;
 
 272         SCpnt = padapter->SCpnt;
 
 274         if ( !padapter->expectingIRQ )
 
 276                 DEB(printk ("\npsi240i Unsolicited interrupt\n"));
 
 279         padapter->expectingIRQ = 0;
 
 281         status = inb_p (padapter->ports[PORT_STAT_CMD]);                        // read the device status
 
 282         if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
 
 285         DEB(printk ("\npsi240i processing interrupt"));
 
 286         switch ( padapter->ide.ide.ides.cmd )                                                   // decide how to handle the interrupt
 
 288                 case IDE_CMD_READ_MULTIPLE:
 
 289                         if ( status & IDE_STATUS_DRQ )
 
 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) )
 
 295                                         SCpnt->result = DID_OK << 16;
 
 296                                         padapter->SCpnt = NULL;
 
 297                                         SCpnt->scsi_done (SCpnt);
 
 300                                 if ( !(status = IdeCmd (padapter)) )
 
 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) )
 
 309                                 SCpnt->result = DID_OK << 16;
 
 310                                 padapter->SCpnt = NULL;
 
 311                                 SCpnt->scsi_done (SCpnt);
 
 314                         if ( !(status = IdeCmd (padapter)) )
 
 318                 case IDE_COMMAND_IDENTIFY:
 
 320                         PINQUIRYDATA    pinquiryData  = SCpnt->request_buffer;
 
 322                         if ( status & IDE_STATUS_DRQ )
 
 324                                 insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
 
 326                                 memset (pinquiryData, 0, SCpnt->request_bufflen);               // Zero INQUIRY data structure.
 
 327                                 pinquiryData->DeviceType = 0;
 
 328                                 pinquiryData->Versions = 2;
 
 329                                 pinquiryData->AdditionalLength = 35 - 4;
 
 331                                 // Fill in vendor identification fields.
 
 332                                 for ( z = 0;  z < 20;  z += 2 )
 
 334                                         pinquiryData->VendorId[z]         = ((UCHAR *)identifyData.ModelNumber)[z + 1];
 
 335                                         pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
 
 338                                 // Initialize unused portion of product id.
 
 339                                 for ( z = 0;  z < 4;  z++ )
 
 340                                         pinquiryData->ProductId[12 + z] = ' ';
 
 342                                 // Move firmware revision from IDENTIFY data to
 
 343                                 // product revision in INQUIRY data.
 
 344                                 for ( z = 0;  z < 4;  z += 2 )
 
 346                                         pinquiryData->ProductRevisionLevel[z]    = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
 
 347                                         pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
 
 350                                 SCpnt->result = DID_OK << 16;
 
 351                                 padapter->SCpnt = NULL;
 
 352                                 SCpnt->scsi_done (SCpnt);
 
 359                         SCpnt->result = DID_OK << 16;
 
 360                         padapter->SCpnt = NULL;
 
 361                         SCpnt->scsi_done (SCpnt);
 
 366         DEB(printk ("\npsi240i error  Device Status: %X\n", status));
 
 367         SCpnt->result = DecodeError (shost, status);
 
 368         SCpnt->scsi_done (SCpnt);
 
 371 static irqreturn_t do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
 
 374         struct Scsi_Host *dev = dev_id;
 
 376         spin_lock_irqsave(dev->host_lock, flags);
 
 377         Irq_Handler(irq, dev_id, regs);
 
 378         spin_unlock_irqrestore(dev->host_lock, flags);
 
 382 /****************************************************************
 
 383  *      Name:   Psi240i_QueueCommand
 
 385  *      Description:    Process a queued command from the SCSI manager.
 
 387  *      Parameters:             SCpnt - Pointer to SCSI command structure.
 
 388  *                                      done  - Pointer to done function to call.
 
 390  *      Returns:                Status code.
 
 392  ****************************************************************/
 
 393 static int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 
 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
 
 400         SCpnt->scsi_done = done;
 
 401         padapter->ide.ide.ides.spigot = pdev->spigot;
 
 402         padapter->buffer = SCpnt->request_buffer;
 
 407                         SCpnt->result = DID_BAD_TARGET << 16;
 
 414                 printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
 
 420                 case SCSIOP_INQUIRY:                                    // inquiry CDB
 
 422                         padapter->ide.ide.ide[6] = pdev->byte6;
 
 423                         padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
 
 427                 case SCSIOP_TEST_UNIT_READY:                    // test unit ready CDB
 
 428                         SCpnt->result = DID_OK << 16;
 
 432                 case SCSIOP_READ_CAPACITY:                              // read capctiy CDB
 
 434                         PREAD_CAPACITY_DATA     pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
 
 436                         pdata->blksiz = 0x20000;
 
 437                         XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
 
 438                         SCpnt->result = DID_OK << 16;
 
 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;
 
 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;
 
 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;
 
 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;
 
 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;
 
 478                         DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
 
 479                         SCpnt->result = DID_ERROR << 16;
 
 484         padapter->SCpnt = SCpnt;                                                                        // Save this command data
 
 486         rc = IdeCmd (padapter);
 
 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;
 
 495         DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
 
 499 /***************************************************************************
 
 500  *      Name:                   ReadChipMemory
 
 502  *      Description:    Read information from controller memory.
 
 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.
 
 511  **************************************************************************/
 
 512 static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
 
 515         UCHAR   *pd = (UCHAR *)pdata;
 
 516         outb_p (SEL_NONE, port + REG_SEL_FAIL);                         // setup data port
 
 518         while ( zz < length )
 
 520                 outw_p (base, port + REG_ADDRESS);                              // setup address
 
 522                 for ( z = 0;  z < 8;  z++ )
 
 524                         if ( (zz + z) < length )
 
 525                         *pd++ = inb_p (port + z);       // read data byte
 
 531 /****************************************************************
 
 532  *      Name:   Psi240i_Detect
 
 534  *      Description:    Detect and initialize our boards.
 
 536  *      Parameters:             tpnt - Pointer to SCSI host template structure.
 
 538  *      Returns:                Number of adapters found.
 
 540  ****************************************************************/
 
 541 static int Psi240i_Detect (Scsi_Host_Template *tpnt)
 
 547         USHORT                          port, port_range = 16;
 
 548         CHIP_CONFIG_N           chipConfig;
 
 549         CHIP_DEVICE_N           chipDevice[8];
 
 550         struct Scsi_Host   *pshost;
 
 552         for ( board = 0;  board < MAXBOARDS;  board++ )                                 // scan for I/O ports
 
 555                 port = portAddr[board];                                                         // get base address to test
 
 556                 if ( !request_region (port, port_range, "psi240i") )
 
 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
 
 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.
 
 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);
 
 575                 if ( !chipConfig.numDrives )                                            // if no devices on this board
 
 576                         goto host_init_failure;
 
 578                 pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
 
 580                         goto host_init_failure; 
 
 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;
 
 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]););
 
 595                 for ( z = 0;  z < chipConfig.numDrives;  ++z )
 
 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));
 
 614                 if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) 
 
 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");
 
 622                 printk ("Unable to allocate IRQ for PSI-240I controller.\n");
 
 626                 release_region (port, port_range);
 
 628                         scsi_unregister (pshost);
 
 634 static int Psi240i_Release(struct Scsi_Host *shost)
 
 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);
 
 644 /****************************************************************
 
 645  *      Name:   Psi240i_BiosParam
 
 647  *      Description:    Process the biosparam request from the SCSI manager to
 
 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.
 
 656  ****************************************************************/
 
 657 static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
 
 658                 sector_t capacity, int geom[])
 
 662         pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]);
 
 664         geom[0] = pdev->heads;
 
 665         geom[1] = pdev->sectors;
 
 666         geom[2] = pdev->cylinders;
 
 670 MODULE_LICENSE("GPL");
 
 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,
 
 681         .sg_tablesize           = SG_NONE,
 
 683         .use_clustering         = DISABLE_CLUSTERING,
 
 685 #include "scsi_module.c"