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 73typedef 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 86typedef 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 101static struct Scsi_Host *PsiHost[6] = {NULL,}; /* One for each IRQ level (10-15) */ 102static IDENTIFY_DATA identifyData; 103static SETUP ChipSetup; 104 105static 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 ****************************************************************/ 117static 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 ****************************************************************/ 144static 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 ****************************************************************/ 185static 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 ****************************************************************/ 214static 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 ****************************************************************/ 254static 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 364irqerror:; 365 DEB(printk ("\npsi240i error Device Status: %X\n", status)); 366 SCpnt->result = DecodeError (shost, status); 367 SCpnt->scsi_done (SCpnt); 368 } 369 370static 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 ****************************************************************/ 392static 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 **************************************************************************/ 516static 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 ****************************************************************/ 545static 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 628host_init_failure: 629 630 release_region (port, port_range); 631 if (pshost) 632 scsi_unregister (pshost); 633 634 } 635 return count; 636 } 637 638static 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 ****************************************************************/ 661static 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 674MODULE_LICENSE("GPL"); 675 676static 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" 690