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