psi240i.c 21 KB

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