psi240i.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  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. #include <linux/module.h>
  27. #include <linux/blkdev.h>
  28. #include <linux/kernel.h>
  29. #include <linux/types.h>
  30. #include <linux/string.h>
  31. #include <linux/ioport.h>
  32. #include <linux/delay.h>
  33. #include <linux/interrupt.h>
  34. #include <linux/proc_fs.h>
  35. #include <linux/spinlock.h>
  36. #include <linux/stat.h>
  37. #include <asm/dma.h>
  38. #include <asm/system.h>
  39. #include <asm/io.h>
  40. #include "scsi.h"
  41. #include <scsi/scsi_host.h>
  42. #include "psi240i.h"
  43. #include "psi_chip.h"
  44. //#define DEBUG 1
  45. #ifdef DEBUG
  46. #define DEB(x) x
  47. #else
  48. #define DEB(x)
  49. #endif
  50. #define MAXBOARDS 6 /* Increase this and the sizes of the arrays below, if you need more. */
  51. #define PORT_DATA 0
  52. #define PORT_ERROR 1
  53. #define PORT_SECTOR_COUNT 2
  54. #define PORT_LBA_0 3
  55. #define PORT_LBA_8 4
  56. #define PORT_LBA_16 5
  57. #define PORT_LBA_24 6
  58. #define PORT_STAT_CMD 7
  59. #define PORT_SEL_FAIL 8
  60. #define PORT_IRQ_STATUS 9
  61. #define PORT_ADDRESS 10
  62. #define PORT_FAIL 11
  63. #define PORT_ALT_STAT 12
  64. typedef struct
  65. {
  66. UCHAR device; // device code
  67. UCHAR byte6; // device select register image
  68. UCHAR spigot; // spigot number
  69. UCHAR expectingIRQ; // flag for expecting and interrupt
  70. USHORT sectors; // number of sectors per track
  71. USHORT heads; // number of heads
  72. USHORT cylinders; // number of cylinders for this device
  73. USHORT spareword; // placeholder
  74. ULONG blocks; // number of blocks on device
  75. } OUR_DEVICE, *POUR_DEVICE;
  76. typedef struct
  77. {
  78. USHORT ports[13];
  79. OUR_DEVICE device[8];
  80. Scsi_Cmnd *pSCmnd;
  81. IDE_STRUCT ide;
  82. ULONG startSector;
  83. USHORT sectorCount;
  84. Scsi_Cmnd *SCpnt;
  85. VOID *buffer;
  86. USHORT expectingIRQ;
  87. } ADAPTER240I, *PADAPTER240I;
  88. #define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)
  89. static struct Scsi_Host *PsiHost[6] = {NULL,}; /* One for each IRQ level (10-15) */
  90. static IDENTIFY_DATA identifyData;
  91. static SETUP ChipSetup;
  92. static USHORT portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};
  93. /****************************************************************
  94. * Name: WriteData :LOCAL
  95. *
  96. * Description: Write data to device.
  97. *
  98. * Parameters: padapter - Pointer adapter data structure.
  99. *
  100. * Returns: TRUE if drive does not assert DRQ in time.
  101. *
  102. ****************************************************************/
  103. static int WriteData (PADAPTER240I padapter)
  104. {
  105. ULONG timer;
  106. USHORT *pports = padapter->ports;
  107. timer = jiffies + TIMEOUT_DRQ; // calculate the timeout value
  108. do {
  109. if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
  110. {
  111. outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);
  112. return 0;
  113. }
  114. } while ( time_after(timer, jiffies) ); // test for timeout
  115. padapter->ide.ide.ides.cmd = 0; // null out the command byte
  116. return 1;
  117. }
  118. /****************************************************************
  119. * Name: IdeCmd :LOCAL
  120. *
  121. * Description: Process a queued command from the SCSI manager.
  122. *
  123. * Parameters: padapter - Pointer adapter data structure.
  124. *
  125. * Returns: Zero if no error or status register contents on error.
  126. *
  127. ****************************************************************/
  128. static UCHAR IdeCmd (PADAPTER240I padapter)
  129. {
  130. ULONG timer;
  131. USHORT *pports = padapter->ports;
  132. UCHAR status;
  133. outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]); // select the spigot
  134. outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]); // select the drive
  135. timer = jiffies + TIMEOUT_READY; // calculate the timeout value
  136. do {
  137. status = inb_p (padapter->ports[PORT_STAT_CMD]);
  138. if ( status & IDE_STATUS_DRDY )
  139. {
  140. outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
  141. outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
  142. outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
  143. outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
  144. padapter->expectingIRQ = 1;
  145. outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
  146. if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
  147. return (WriteData (padapter));
  148. return 0;
  149. }
  150. } while ( time_after(timer, jiffies) ); // test for timeout
  151. padapter->ide.ide.ides.cmd = 0; // null out the command byte
  152. return status;
  153. }
  154. /****************************************************************
  155. * Name: SetupTransfer :LOCAL
  156. *
  157. * Description: Setup a data transfer command.
  158. *
  159. * Parameters: padapter - Pointer adapter data structure.
  160. * drive - Drive/head register upper nibble only.
  161. *
  162. * Returns: TRUE if no data to transfer.
  163. *
  164. ****************************************************************/
  165. static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)
  166. {
  167. if ( padapter->sectorCount )
  168. {
  169. *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
  170. padapter->ide.ide.ide[6] |= drive;
  171. padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
  172. padapter->sectorCount -= padapter->ide.ide.ides.sectors; // bump the start and count for next xfer
  173. padapter->startSector += padapter->ide.ide.ides.sectors;
  174. return 0;
  175. }
  176. else
  177. {
  178. padapter->ide.ide.ides.cmd = 0; // null out the command byte
  179. padapter->SCpnt = NULL;
  180. return 1;
  181. }
  182. }
  183. /****************************************************************
  184. * Name: DecodeError :LOCAL
  185. *
  186. * Description: Decode and process device errors.
  187. *
  188. * Parameters: pshost - Pointer to host data block.
  189. * status - Status register code.
  190. *
  191. * Returns: The driver status code.
  192. *
  193. ****************************************************************/
  194. static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
  195. {
  196. PADAPTER240I padapter = HOSTDATA(pshost);
  197. UCHAR error;
  198. padapter->expectingIRQ = 0;
  199. padapter->SCpnt = NULL;
  200. if ( status & IDE_STATUS_WRITE_FAULT )
  201. {
  202. return DID_PARITY << 16;
  203. }
  204. if ( status & IDE_STATUS_BUSY )
  205. return DID_BUS_BUSY << 16;
  206. error = inb_p (padapter->ports[PORT_ERROR]);
  207. DEB(printk ("\npsi240i error register: %x", error));
  208. switch ( error )
  209. {
  210. case IDE_ERROR_AMNF:
  211. case IDE_ERROR_TKONF:
  212. case IDE_ERROR_ABRT:
  213. case IDE_ERROR_IDFN:
  214. case IDE_ERROR_UNC:
  215. case IDE_ERROR_BBK:
  216. default:
  217. return DID_ERROR << 16;
  218. }
  219. return DID_ERROR << 16;
  220. }
  221. /****************************************************************
  222. * Name: Irq_Handler :LOCAL
  223. *
  224. * Description: Interrupt handler.
  225. *
  226. * Parameters: irq - Hardware IRQ number.
  227. * dev_id -
  228. * regs -
  229. *
  230. * Returns: TRUE if drive is not ready in time.
  231. *
  232. ****************************************************************/
  233. static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
  234. {
  235. struct Scsi_Host *shost; // Pointer to host data block
  236. PADAPTER240I padapter; // Pointer to adapter control structure
  237. USHORT *pports; // I/O port array
  238. Scsi_Cmnd *SCpnt;
  239. UCHAR status;
  240. int z;
  241. DEB(printk ("\npsi240i received interrupt\n"));
  242. shost = PsiHost[irq - 10];
  243. if ( !shost )
  244. panic ("Splunge!");
  245. padapter = HOSTDATA(shost);
  246. pports = padapter->ports;
  247. SCpnt = padapter->SCpnt;
  248. if ( !padapter->expectingIRQ )
  249. {
  250. DEB(printk ("\npsi240i Unsolicited interrupt\n"));
  251. return;
  252. }
  253. padapter->expectingIRQ = 0;
  254. status = inb_p (padapter->ports[PORT_STAT_CMD]); // read the device status
  255. if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
  256. goto irqerror;
  257. DEB(printk ("\npsi240i processing interrupt"));
  258. switch ( padapter->ide.ide.ides.cmd ) // decide how to handle the interrupt
  259. {
  260. case IDE_CMD_READ_MULTIPLE:
  261. if ( status & IDE_STATUS_DRQ )
  262. {
  263. insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);
  264. padapter->buffer += padapter->ide.ide.ides.sectors * 512;
  265. if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
  266. {
  267. SCpnt->result = DID_OK << 16;
  268. padapter->SCpnt = NULL;
  269. SCpnt->scsi_done (SCpnt);
  270. return;
  271. }
  272. if ( !(status = IdeCmd (padapter)) )
  273. return;
  274. }
  275. break;
  276. case IDE_CMD_WRITE_MULTIPLE:
  277. padapter->buffer += padapter->ide.ide.ides.sectors * 512;
  278. if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
  279. {
  280. SCpnt->result = DID_OK << 16;
  281. padapter->SCpnt = NULL;
  282. SCpnt->scsi_done (SCpnt);
  283. return;
  284. }
  285. if ( !(status = IdeCmd (padapter)) )
  286. return;
  287. break;
  288. case IDE_COMMAND_IDENTIFY:
  289. {
  290. PINQUIRYDATA pinquiryData = SCpnt->request_buffer;
  291. if ( status & IDE_STATUS_DRQ )
  292. {
  293. insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
  294. memset (pinquiryData, 0, SCpnt->request_bufflen); // Zero INQUIRY data structure.
  295. pinquiryData->DeviceType = 0;
  296. pinquiryData->Versions = 2;
  297. pinquiryData->AdditionalLength = 35 - 4;
  298. // Fill in vendor identification fields.
  299. for ( z = 0; z < 20; z += 2 )
  300. {
  301. pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1];
  302. pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
  303. }
  304. // Initialize unused portion of product id.
  305. for ( z = 0; z < 4; z++ )
  306. pinquiryData->ProductId[12 + z] = ' ';
  307. // Move firmware revision from IDENTIFY data to
  308. // product revision in INQUIRY data.
  309. for ( z = 0; z < 4; z += 2 )
  310. {
  311. pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
  312. pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
  313. }
  314. SCpnt->result = DID_OK << 16;
  315. padapter->SCpnt = NULL;
  316. SCpnt->scsi_done (SCpnt);
  317. return;
  318. }
  319. break;
  320. }
  321. default:
  322. SCpnt->result = DID_OK << 16;
  323. padapter->SCpnt = NULL;
  324. SCpnt->scsi_done (SCpnt);
  325. return;
  326. }
  327. irqerror:;
  328. DEB(printk ("\npsi240i error Device Status: %X\n", status));
  329. SCpnt->result = DecodeError (shost, status);
  330. SCpnt->scsi_done (SCpnt);
  331. }
  332. static irqreturn_t do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
  333. {
  334. unsigned long flags;
  335. struct Scsi_Host *dev = dev_id;
  336. spin_lock_irqsave(dev->host_lock, flags);
  337. Irq_Handler(irq, dev_id, regs);
  338. spin_unlock_irqrestore(dev->host_lock, flags);
  339. return IRQ_HANDLED;
  340. }
  341. /****************************************************************
  342. * Name: Psi240i_QueueCommand
  343. *
  344. * Description: Process a queued command from the SCSI manager.
  345. *
  346. * Parameters: SCpnt - Pointer to SCSI command structure.
  347. * done - Pointer to done function to call.
  348. *
  349. * Returns: Status code.
  350. *
  351. ****************************************************************/
  352. static int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
  353. {
  354. UCHAR *cdb = (UCHAR *)SCpnt->cmnd; // Pointer to SCSI CDB
  355. PADAPTER240I padapter = HOSTDATA (SCpnt->device->host); // Pointer to adapter control structure
  356. POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];// Pointer to device information
  357. UCHAR rc; // command return code
  358. SCpnt->scsi_done = done;
  359. padapter->ide.ide.ides.spigot = pdev->spigot;
  360. padapter->buffer = SCpnt->request_buffer;
  361. if (done)
  362. {
  363. if ( !pdev->device )
  364. {
  365. SCpnt->result = DID_BAD_TARGET << 16;
  366. done (SCpnt);
  367. return 0;
  368. }
  369. }
  370. else
  371. {
  372. printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
  373. return 0;
  374. }
  375. switch ( *cdb )
  376. {
  377. case SCSIOP_INQUIRY: // inquiry CDB
  378. {
  379. padapter->ide.ide.ide[6] = pdev->byte6;
  380. padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
  381. break;
  382. }
  383. case SCSIOP_TEST_UNIT_READY: // test unit ready CDB
  384. SCpnt->result = DID_OK << 16;
  385. done (SCpnt);
  386. return 0;
  387. case SCSIOP_READ_CAPACITY: // read capctiy CDB
  388. {
  389. PREAD_CAPACITY_DATA pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
  390. pdata->blksiz = 0x20000;
  391. XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
  392. SCpnt->result = DID_OK << 16;
  393. done (SCpnt);
  394. return 0;
  395. }
  396. case SCSIOP_VERIFY: // verify CDB
  397. *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
  398. padapter->ide.ide.ide[6] |= pdev->byte6;
  399. padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
  400. padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
  401. break;
  402. case SCSIOP_READ: // read10 CDB
  403. padapter->startSector = XSCSI2LONG (&cdb[2]);
  404. padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
  405. SetupTransfer (padapter, pdev->byte6);
  406. padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
  407. break;
  408. case SCSIOP_READ6: // read6 CDB
  409. padapter->startSector = SCSI2LONG (&cdb[1]);
  410. padapter->sectorCount = cdb[4];
  411. SetupTransfer (padapter, pdev->byte6);
  412. padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
  413. break;
  414. case SCSIOP_WRITE: // write10 CDB
  415. padapter->startSector = XSCSI2LONG (&cdb[2]);
  416. padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
  417. SetupTransfer (padapter, pdev->byte6);
  418. padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
  419. break;
  420. case SCSIOP_WRITE6: // write6 CDB
  421. padapter->startSector = SCSI2LONG (&cdb[1]);
  422. padapter->sectorCount = cdb[4];
  423. SetupTransfer (padapter, pdev->byte6);
  424. padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
  425. break;
  426. default:
  427. DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
  428. SCpnt->result = DID_ERROR << 16;
  429. done (SCpnt);
  430. return 0;
  431. }
  432. padapter->SCpnt = SCpnt; // Save this command data
  433. rc = IdeCmd (padapter);
  434. if ( rc )
  435. {
  436. padapter->expectingIRQ = 0;
  437. DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
  438. SCpnt->result = DID_ERROR << 16;
  439. done (SCpnt);
  440. return 0;
  441. }
  442. DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
  443. return 0;
  444. }
  445. /***************************************************************************
  446. * Name: ReadChipMemory
  447. *
  448. * Description: Read information from controller memory.
  449. *
  450. * Parameters: psetup - Pointer to memory image of setup information.
  451. * base - base address of memory.
  452. * length - lenght of data space in bytes.
  453. * port - I/O address of data port.
  454. *
  455. * Returns: Nothing.
  456. *
  457. **************************************************************************/
  458. static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
  459. {
  460. USHORT z, zz;
  461. UCHAR *pd = (UCHAR *)pdata;
  462. outb_p (SEL_NONE, port + REG_SEL_FAIL); // setup data port
  463. zz = 0;
  464. while ( zz < length )
  465. {
  466. outw_p (base, port + REG_ADDRESS); // setup address
  467. for ( z = 0; z < 8; z++ )
  468. {
  469. if ( (zz + z) < length )
  470. *pd++ = inb_p (port + z); // read data byte
  471. }
  472. zz += 8;
  473. base += 8;
  474. }
  475. }
  476. /****************************************************************
  477. * Name: Psi240i_Detect
  478. *
  479. * Description: Detect and initialize our boards.
  480. *
  481. * Parameters: tpnt - Pointer to SCSI host template structure.
  482. *
  483. * Returns: Number of adapters found.
  484. *
  485. ****************************************************************/
  486. static int Psi240i_Detect (struct scsi_host_template *tpnt)
  487. {
  488. int board;
  489. int count = 0;
  490. int unit;
  491. int z;
  492. USHORT port, port_range = 16;
  493. CHIP_CONFIG_N chipConfig;
  494. CHIP_DEVICE_N chipDevice[8];
  495. struct Scsi_Host *pshost;
  496. for ( board = 0; board < MAXBOARDS; board++ ) // scan for I/O ports
  497. {
  498. pshost = NULL;
  499. port = portAddr[board]; // get base address to test
  500. if ( !request_region (port, port_range, "psi240i") )
  501. continue;
  502. if ( inb_p (port + REG_FAIL) != CHIP_ID ) // do the first test for likley hood that it is us
  503. goto host_init_failure;
  504. outb_p (SEL_NONE, port + REG_SEL_FAIL); // setup EEPROM/RAM access
  505. outw (0, port + REG_ADDRESS); // setup EEPROM address zero
  506. if ( inb_p (port) != 0x55 ) // test 1st byte
  507. goto host_init_failure; // nope
  508. if ( inb_p (port + 1) != 0xAA ) // test 2nd byte
  509. goto host_init_failure; // nope
  510. // at this point our board is found and can be accessed. Now we need to initialize
  511. // our informatation and register with the kernel.
  512. ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
  513. ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
  514. ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
  515. if ( !chipConfig.numDrives ) // if no devices on this board
  516. goto host_init_failure;
  517. pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
  518. if(pshost == NULL)
  519. goto host_init_failure;
  520. PsiHost[chipConfig.irq - 10] = pshost;
  521. pshost->unique_id = port;
  522. pshost->io_port = port;
  523. pshost->n_io_port = 16; /* Number of bytes of I/O space used */
  524. pshost->irq = chipConfig.irq;
  525. for ( z = 0; z < 11; z++ ) // build regester address array
  526. HOSTDATA(pshost)->ports[z] = port + z;
  527. HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
  528. HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
  529. DEB (printk ("\nPorts ="));
  530. DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
  531. for ( z = 0; z < chipConfig.numDrives; ++z )
  532. {
  533. unit = chipDevice[z].channel & 0x0F;
  534. HOSTDATA(pshost)->device[unit].device = ChipSetup.setupDevice[unit].device;
  535. HOSTDATA(pshost)->device[unit].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0);
  536. HOSTDATA(pshost)->device[unit].spigot = (UCHAR)(1 << (unit >> 1));
  537. HOSTDATA(pshost)->device[unit].sectors = ChipSetup.setupDevice[unit].sectors;
  538. HOSTDATA(pshost)->device[unit].heads = ChipSetup.setupDevice[unit].heads;
  539. HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
  540. HOSTDATA(pshost)->device[unit].blocks = ChipSetup.setupDevice[unit].blocks;
  541. DEB (printk ("\nHOSTDATA->device = %X", HOSTDATA(pshost)->device[unit].device));
  542. DEB (printk ("\n byte6 = %X", HOSTDATA(pshost)->device[unit].byte6));
  543. DEB (printk ("\n spigot = %X", HOSTDATA(pshost)->device[unit].spigot));
  544. DEB (printk ("\n sectors = %X", HOSTDATA(pshost)->device[unit].sectors));
  545. DEB (printk ("\n heads = %X", HOSTDATA(pshost)->device[unit].heads));
  546. DEB (printk ("\n cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
  547. DEB (printk ("\n blocks = %lX", HOSTDATA(pshost)->device[unit].blocks));
  548. }
  549. if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 )
  550. {
  551. printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x IRQ = %d\n", port, chipConfig.irq);
  552. printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
  553. count++;
  554. continue;
  555. }
  556. printk ("Unable to allocate IRQ for PSI-240I controller.\n");
  557. host_init_failure:
  558. release_region (port, port_range);
  559. if (pshost)
  560. scsi_unregister (pshost);
  561. }
  562. return count;
  563. }
  564. static int Psi240i_Release(struct Scsi_Host *shost)
  565. {
  566. if (shost->irq)
  567. free_irq(shost->irq, NULL);
  568. if (shost->io_port && shost->n_io_port)
  569. release_region(shost->io_port, shost->n_io_port);
  570. scsi_unregister(shost);
  571. return 0;
  572. }
  573. /****************************************************************
  574. * Name: Psi240i_BiosParam
  575. *
  576. * Description: Process the biosparam request from the SCSI manager to
  577. * return C/H/S data.
  578. *
  579. * Parameters: disk - Pointer to SCSI disk structure.
  580. * dev - Major/minor number from kernel.
  581. * geom - Pointer to integer array to place geometry data.
  582. *
  583. * Returns: zero.
  584. *
  585. ****************************************************************/
  586. static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
  587. sector_t capacity, int geom[])
  588. {
  589. POUR_DEVICE pdev;
  590. pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]);
  591. geom[0] = pdev->heads;
  592. geom[1] = pdev->sectors;
  593. geom[2] = pdev->cylinders;
  594. return 0;
  595. }
  596. MODULE_LICENSE("GPL");
  597. static struct scsi_host_template driver_template = {
  598. .proc_name = "psi240i",
  599. .name = "PSI-240I EIDE Disk Controller",
  600. .detect = Psi240i_Detect,
  601. .release = Psi240i_Release,
  602. .queuecommand = Psi240i_QueueCommand,
  603. .bios_param = Psi240i_BiosParam,
  604. .can_queue = 1,
  605. .this_id = -1,
  606. .sg_tablesize = SG_NONE,
  607. .cmd_per_lun = 1,
  608. .use_clustering = DISABLE_CLUSTERING,
  609. };
  610. #include "scsi_module.c"