1 /*+M************************************************************************* 2 * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux. 4 * Copyright (c) 1997 Perceptive Solutions, Inc. 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 16 * You should have received a copy of the GNU General Public License 17 * along with this program; see the file COPYING. If not, write to 18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 21 * File Name: psi240i.c 23 * Description: SCSI driver for the PSI240I EIDE interface card. 25 *-M*************************************************************************/ 27 #include <linux/module.h> 29 #include <linux/kernel.h> 30 #include <linux/types.h> 31 #include <linux/string.h> 32 #include <linux/ioport.h> 33 #include <linux/delay.h> 34 #include <linux/sched.h> 35 #include <linux/proc_fs.h> 36 #include <linux/spinlock.h> 38 #include <asm/system.h> 40 #include <linux/blk.h> 47 #include<linux/stat.h> 49 struct proc_dir_entry Proc_Scsi_Psi240i
= 50 { PROC_SCSI_PSI240I
,7,"psi240i", S_IFDIR
| S_IRUGO
| S_IXUGO
,2}; 60 #define MAXBOARDS 2/* Increase this and the sizes of the arrays below, if you need more. */ 64 #define PORT_SECTOR_COUNT 2 69 #define PORT_STAT_CMD 7 70 #define PORT_SEL_FAIL 8 71 #define PORT_IRQ_STATUS 9 72 #define PORT_ADDRESS 10 74 #define PORT_ALT_STAT 12 78 UCHAR device
;// device code 79 UCHAR byte6
;// device select register image 80 UCHAR spigot
;// spigot number 81 UCHAR expectingIRQ
;// flag for expecting and interrupt 82 USHORT sectors
;// number of sectors per track 83 USHORT heads
;// number of heads 84 USHORT cylinders
;// number of cylinders for this device 85 USHORT spareword
;// placeholder 86 ULONG blocks
;// number of blocks on device 87 } OUR_DEVICE
, *POUR_DEVICE
; 100 } ADAPTER240I
, *PADAPTER240I
; 102 #define HOSTDATA(host) ((PADAPTER240I)&host->hostdata) 104 static struct Scsi_Host
*PsiHost
[6] = {NULL
,};/* One for each IRQ level (10-15) */ 105 static IDENTIFY_DATA identifyData
; 106 static SETUP ChipSetup
; 108 static USHORT portAddr
[6] = {CHIP_ADRS_0
, CHIP_ADRS_1
, CHIP_ADRS_2
, CHIP_ADRS_3
, CHIP_ADRS_4
, CHIP_ADRS_5
}; 110 /**************************************************************** 111 * Name: WriteData :LOCAL 113 * Description: Write data to device. 115 * Parameters: padapter - Pointer adapter data structure. 117 * Returns: TRUE if drive does not assert DRQ in time. 119 ****************************************************************/ 120 static intWriteData(PADAPTER240I padapter
) 123 USHORT
*pports
= padapter
->ports
; 125 timer
= jiffies
+ TIMEOUT_DRQ
;// calculate the timeout value 127 if(inb_p(pports
[PORT_STAT_CMD
]) & IDE_STATUS_DRQ
) 129 outsw(pports
[PORT_DATA
], padapter
->buffer
, (USHORT
)padapter
->ide
.ide
.ide
[2] *256); 132 }while(time_after(timer
, jiffies
) );// test for timeout 134 padapter
->ide
.ide
.ides
.cmd
=0;// null out the command byte 137 /**************************************************************** 138 * Name: IdeCmd :LOCAL 140 * Description: Process a queued command from the SCSI manager. 142 * Parameters: padapter - Pointer adapter data structure. 144 * Returns: Zero if no error or status register contents on error. 146 ****************************************************************/ 147 static UCHAR
IdeCmd(PADAPTER240I padapter
) 150 USHORT
*pports
= padapter
->ports
; 153 outb_p(padapter
->ide
.ide
.ides
.spigot
, pports
[PORT_SEL_FAIL
]);// select the spigot 154 outb_p(padapter
->ide
.ide
.ide
[6], pports
[PORT_LBA_24
]);// select the drive 155 timer
= jiffies
+ TIMEOUT_READY
;// calculate the timeout value 157 status
=inb_p(padapter
->ports
[PORT_STAT_CMD
]); 158 if( status
& IDE_STATUS_DRDY
) 160 outb_p(padapter
->ide
.ide
.ide
[2], pports
[PORT_SECTOR_COUNT
]); 161 outb_p(padapter
->ide
.ide
.ide
[3], pports
[PORT_LBA_0
]); 162 outb_p(padapter
->ide
.ide
.ide
[4], pports
[PORT_LBA_8
]); 163 outb_p(padapter
->ide
.ide
.ide
[5], pports
[PORT_LBA_16
]); 164 padapter
->expectingIRQ
=1; 165 outb_p(padapter
->ide
.ide
.ide
[7], pports
[PORT_STAT_CMD
]); 167 if( padapter
->ide
.ide
.ides
.cmd
== IDE_CMD_WRITE_MULTIPLE
) 168 return(WriteData(padapter
)); 172 }while(time_after(timer
, jiffies
) );// test for timeout 174 padapter
->ide
.ide
.ides
.cmd
=0;// null out the command byte 177 /**************************************************************** 178 * Name: SetupTransfer :LOCAL 180 * Description: Setup a data transfer command. 182 * Parameters: padapter - Pointer adapter data structure. 183 * drive - Drive/head register upper nibble only. 185 * Returns: TRUE if no data to transfer. 187 ****************************************************************/ 188 static intSetupTransfer(PADAPTER240I padapter
, UCHAR drive
) 190 if( padapter
->sectorCount
) 192 *(ULONG
*)padapter
->ide
.ide
.ides
.lba
= padapter
->startSector
; 193 padapter
->ide
.ide
.ide
[6] |= drive
; 194 padapter
->ide
.ide
.ides
.sectors
= ( padapter
->sectorCount
> SECTORSXFER
) ? SECTORSXFER
: padapter
->sectorCount
; 195 padapter
->sectorCount
-= padapter
->ide
.ide
.ides
.sectors
;// bump the start and count for next xfer 196 padapter
->startSector
+= padapter
->ide
.ide
.ides
.sectors
; 201 padapter
->ide
.ide
.ides
.cmd
=0;// null out the command byte 202 padapter
->SCpnt
= NULL
; 206 /**************************************************************** 207 * Name: DecodeError :LOCAL 209 * Description: Decode and process device errors. 211 * Parameters: pshost - Pointer to host data block. 212 * status - Status register code. 214 * Returns: The driver status code. 216 ****************************************************************/ 217 static ULONG
DecodeError(struct Scsi_Host
*pshost
, UCHAR status
) 219 PADAPTER240I padapter
=HOSTDATA(pshost
); 222 padapter
->expectingIRQ
=0; 223 padapter
->SCpnt
= NULL
; 224 if( status
& IDE_STATUS_WRITE_FAULT
) 226 return DID_PARITY
<<16; 228 if( status
& IDE_STATUS_BUSY
) 229 return DID_BUS_BUSY
<<16; 231 error
=inb_p(padapter
->ports
[PORT_ERROR
]); 232 DEB(printk("\npsi240i error register: %x", error
)); 236 case IDE_ERROR_TKONF
: 242 return DID_ERROR
<<16; 244 return DID_ERROR
<<16; 246 /**************************************************************** 247 * Name: Irq_Handler :LOCAL 249 * Description: Interrupt handler. 251 * Parameters: irq - Hardware IRQ number. 255 * Returns: TRUE if drive is not ready in time. 257 ****************************************************************/ 258 static voidIrq_Handler(int irq
,void*dev_id
,struct pt_regs
*regs
) 260 struct Scsi_Host
*shost
;// Pointer to host data block 261 PADAPTER240I padapter
;// Pointer to adapter control structure 262 USHORT
*pports
;// I/O port array 267 DEB(printk("\npsi240i received interrupt\n")); 269 shost
= PsiHost
[irq
-10]; 273 padapter
=HOSTDATA(shost
); 274 pports
= padapter
->ports
; 275 SCpnt
= padapter
->SCpnt
; 277 if( !padapter
->expectingIRQ
) 279 DEB(printk("\npsi240i Unsolicited interrupt\n")); 282 padapter
->expectingIRQ
=0; 284 status
=inb_p(padapter
->ports
[PORT_STAT_CMD
]);// read the device status 285 if( status
& (IDE_STATUS_ERROR
| IDE_STATUS_WRITE_FAULT
) ) 288 DEB(printk("\npsi240i processing interrupt")); 289 switch( padapter
->ide
.ide
.ides
.cmd
)// decide how to handle the interrupt 291 case IDE_CMD_READ_MULTIPLE
: 292 if( status
& IDE_STATUS_DRQ
) 294 insw(pports
[PORT_DATA
], padapter
->buffer
, (USHORT
)padapter
->ide
.ide
.ides
.sectors
*256); 295 padapter
->buffer
+= padapter
->ide
.ide
.ides
.sectors
*512; 296 if(SetupTransfer(padapter
, padapter
->ide
.ide
.ide
[6] &0xF0) ) 298 SCpnt
->result
= DID_OK
<<16; 299 padapter
->SCpnt
= NULL
; 300 SCpnt
->scsi_done(SCpnt
); 303 if( !(status
=IdeCmd(padapter
)) ) 308 case IDE_CMD_WRITE_MULTIPLE
: 309 padapter
->buffer
+= padapter
->ide
.ide
.ides
.sectors
*512; 310 if(SetupTransfer(padapter
, padapter
->ide
.ide
.ide
[6] &0xF0) ) 312 SCpnt
->result
= DID_OK
<<16; 313 padapter
->SCpnt
= NULL
; 314 SCpnt
->scsi_done(SCpnt
); 317 if( !(status
=IdeCmd(padapter
)) ) 321 case IDE_COMMAND_IDENTIFY
: 323 PINQUIRYDATA pinquiryData
= SCpnt
->request_buffer
; 325 if( status
& IDE_STATUS_DRQ
) 327 insw(pports
[PORT_DATA
], &identifyData
,sizeof(identifyData
) >>1); 329 memset(pinquiryData
,0, SCpnt
->request_bufflen
);// Zero INQUIRY data structure. 330 pinquiryData
->DeviceType
=0; 331 pinquiryData
->Versions
=2; 332 pinquiryData
->AdditionalLength
=35-4; 334 // Fill in vendor identification fields. 335 for( z
=0; z
<20; z
+=2) 337 pinquiryData
->VendorId
[z
] = ((UCHAR
*)identifyData
.ModelNumber
)[z
+1]; 338 pinquiryData
->VendorId
[z
+1] = ((UCHAR
*)identifyData
.ModelNumber
)[z
]; 341 // Initialize unused portion of product id. 342 for( z
=0; z
<4; z
++ ) 343 pinquiryData
->ProductId
[12+ z
] =' '; 345 // Move firmware revision from IDENTIFY data to 346 // product revision in INQUIRY data. 347 for( z
=0; z
<4; z
+=2) 349 pinquiryData
->ProductRevisionLevel
[z
] = ((UCHAR
*)identifyData
.FirmwareRevision
)[z
+1]; 350 pinquiryData
->ProductRevisionLevel
[z
+1] = ((UCHAR
*)identifyData
.FirmwareRevision
)[z
]; 353 SCpnt
->result
= DID_OK
<<16; 354 padapter
->SCpnt
= NULL
; 355 SCpnt
->scsi_done(SCpnt
); 362 SCpnt
->result
= DID_OK
<<16; 363 padapter
->SCpnt
= NULL
; 364 SCpnt
->scsi_done(SCpnt
); 369 DEB(printk("\npsi240i error Device Status: %X\n", status
)); 370 SCpnt
->result
=DecodeError(shost
, status
); 371 SCpnt
->scsi_done(SCpnt
); 373 static voiddo_Irq_Handler(int irq
,void*dev_id
,struct pt_regs
*regs
) 377 spin_lock_irqsave(&io_request_lock
, flags
); 378 Irq_Handler(irq
, dev_id
, regs
); 379 spin_unlock_irqrestore(&io_request_lock
, flags
); 381 /**************************************************************** 382 * Name: Psi240i_QueueCommand 384 * Description: Process a queued command from the SCSI manager. 386 * Parameters: SCpnt - Pointer to SCSI command structure. 387 * done - Pointer to done function to call. 389 * Returns: Status code. 391 ****************************************************************/ 392 intPsi240i_QueueCommand(Scsi_Cmnd
*SCpnt
,void(*done
)(Scsi_Cmnd
*)) 394 UCHAR
*cdb
= (UCHAR
*)SCpnt
->cmnd
;// Pointer to SCSI CDB 395 PADAPTER240I padapter
=HOSTDATA(SCpnt
->host
);// Pointer to adapter control structure 396 POUR_DEVICE pdev
= &padapter
->device
[SCpnt
->target
];// Pointer to device information 397 UCHAR rc
;// command return code 399 SCpnt
->scsi_done
= done
; 400 padapter
->ide
.ide
.ides
.spigot
= pdev
->spigot
; 401 padapter
->buffer
= SCpnt
->request_buffer
; 406 SCpnt
->result
= DID_BAD_TARGET
<<16; 413 printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb
); 419 case SCSIOP_INQUIRY
:// inquiry CDB 421 padapter
->ide
.ide
.ide
[6] = pdev
->byte6
; 422 padapter
->ide
.ide
.ides
.cmd
= IDE_COMMAND_IDENTIFY
; 426 case SCSIOP_TEST_UNIT_READY
:// test unit ready CDB 427 SCpnt
->result
= DID_OK
<<16; 431 case SCSIOP_READ_CAPACITY
:// read capctiy CDB 433 PREAD_CAPACITY_DATA pdata
= (PREAD_CAPACITY_DATA
)SCpnt
->request_buffer
; 435 pdata
->blksiz
=0x20000; 436 XANY2SCSI((UCHAR
*)&pdata
->blks
, pdev
->blocks
); 437 SCpnt
->result
= DID_OK
<<16; 442 case SCSIOP_VERIFY
:// verify CDB 443 *(ULONG
*)padapter
->ide
.ide
.ides
.lba
=XSCSI2LONG(&cdb
[2]); 444 padapter
->ide
.ide
.ide
[6] |= pdev
->byte6
; 445 padapter
->ide
.ide
.ide
[2] = (UCHAR
)((USHORT
)cdb
[8] | ((USHORT
)cdb
[7] <<8)); 446 padapter
->ide
.ide
.ides
.cmd
= IDE_COMMAND_VERIFY
; 449 case SCSIOP_READ
:// read10 CDB 450 padapter
->startSector
=XSCSI2LONG(&cdb
[2]); 451 padapter
->sectorCount
= (USHORT
)cdb
[8] | ((USHORT
)cdb
[7] <<8); 452 SetupTransfer(padapter
, pdev
->byte6
); 453 padapter
->ide
.ide
.ides
.cmd
= IDE_CMD_READ_MULTIPLE
; 456 case SCSIOP_READ6
:// read6 CDB 457 padapter
->startSector
=SCSI2LONG(&cdb
[1]); 458 padapter
->sectorCount
= cdb
[4]; 459 SetupTransfer(padapter
, pdev
->byte6
); 460 padapter
->ide
.ide
.ides
.cmd
= IDE_CMD_READ_MULTIPLE
; 463 case SCSIOP_WRITE
:// write10 CDB 464 padapter
->startSector
=XSCSI2LONG(&cdb
[2]); 465 padapter
->sectorCount
= (USHORT
)cdb
[8] | ((USHORT
)cdb
[7] <<8); 466 SetupTransfer(padapter
, pdev
->byte6
); 467 padapter
->ide
.ide
.ides
.cmd
= IDE_CMD_WRITE_MULTIPLE
; 469 case SCSIOP_WRITE6
:// write6 CDB 470 padapter
->startSector
=SCSI2LONG(&cdb
[1]); 471 padapter
->sectorCount
= cdb
[4]; 472 SetupTransfer(padapter
, pdev
->byte6
); 473 padapter
->ide
.ide
.ides
.cmd
= IDE_CMD_WRITE_MULTIPLE
; 477 DEB(printk("psi240i_queuecommand: Unsupported command %02X\n", *cdb
)); 478 SCpnt
->result
= DID_ERROR
<<16; 483 padapter
->SCpnt
= SCpnt
;// Save this command data 485 rc
=IdeCmd(padapter
); 488 padapter
->expectingIRQ
=0; 489 DEB(printk("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb
, padapter
->ide
.ide
.ides
.cmd
)); 490 SCpnt
->result
= DID_ERROR
<<16; 494 DEB(printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb
, padapter
->ide
.ide
.ides
.cmd
)); 498 static voidinternal_done(Scsi_Cmnd
* SCpnt
) 502 /**************************************************************** 503 * Name: Psi240i_Command 505 * Description: Process a command from the SCSI manager. 507 * Parameters: SCpnt - Pointer to SCSI command structure. 509 * Returns: Status code. 511 ****************************************************************/ 512 intPsi240i_Command(Scsi_Cmnd
*SCpnt
) 514 DEB(printk("psi240i_command: ..calling psi240i_queuecommand\n")); 516 Psi240i_QueueCommand(SCpnt
, internal_done
); 518 SCpnt
->SCp
.Status
=0; 519 while(!SCpnt
->SCp
.Status
) 521 return SCpnt
->result
; 523 /*************************************************************************** 524 * Name: ReadChipMemory 526 * Description: Read information from controller memory. 528 * Parameters: psetup - Pointer to memory image of setup information. 529 * base - base address of memory. 530 * length - lenght of data space in bytes. 531 * port - I/O address of data port. 535 **************************************************************************/ 536 voidReadChipMemory(void*pdata
, USHORT base
, USHORT length
, USHORT port
) 539 UCHAR
*pd
= (UCHAR
*)pdata
; 540 outb_p(SEL_NONE
, port
+ REG_SEL_FAIL
);// setup data port 544 outw_p(base
, port
+ REG_ADDRESS
);// setup address 546 for( z
=0; z
<8; z
++ ) 548 if( (zz
+ z
) < length
) 549 *pd
++ =inb_p(port
+ z
);// read data byte 555 /**************************************************************** 556 * Name: Psi240i_Detect 558 * Description: Detect and initialize our boards. 560 * Parameters: tpnt - Pointer to SCSI host template structure. 562 * Returns: Number of adapters found. 564 ****************************************************************/ 565 intPsi240i_Detect(Scsi_Host_Template
*tpnt
) 572 CHIP_CONFIG_N chipConfig
; 573 CHIP_DEVICE_N chipDevice
[8]; 574 struct Scsi_Host
*pshost
; 577 for( board
=0; board
<6; board
++ )// scan for I/O ports 579 port
= portAddr
[board
];// get base address to test 580 if(check_region(port
,16) )// test for I/O addresses available 582 if(inb_p(port
+ REG_FAIL
) != CHIP_ID
)// do the first test for likley hood that it is us 584 outb_p(SEL_NONE
, port
+ REG_SEL_FAIL
);// setup EEPROM/RAM access 585 outw(0, port
+ REG_ADDRESS
);// setup EEPROM address zero 586 if(inb_p(port
) !=0x55)// test 1st byte 588 if(inb_p(port
+1) !=0xAA)// test 2nd byte 591 // at this point our board is found and can be accessed. Now we need to initialize 592 // our informatation and register with the kernel. 595 ReadChipMemory(&chipConfig
, CHIP_CONFIG
,sizeof(chipConfig
), port
); 596 ReadChipMemory(&chipDevice
, CHIP_DEVICE
,sizeof(chipDevice
), port
); 597 ReadChipMemory(&ChipSetup
, CHIP_EEPROM_DATA
,sizeof(ChipSetup
), port
); 599 if( !chipConfig
.numDrives
)// if no devices on this board 602 pshost
=scsi_register(tpnt
,sizeof(ADAPTER240I
)); 606 if(request_irq(chipConfig
.irq
, do_Irq_Handler
,0,"psi240i", NULL
) ) 608 printk("Unable to allocate IRQ for PSI-240I controller.\n"); 609 restore_flags(flags
); 613 PsiHost
[chipConfig
.irq
-10] = pshost
; 614 pshost
->unique_id
= port
; 615 pshost
->io_port
= port
; 616 pshost
->n_io_port
=16;/* Number of bytes of I/O space used */ 617 pshost
->irq
= chipConfig
.irq
; 619 for( z
=0; z
<11; z
++ )// build regester address array 620 HOSTDATA(pshost
)->ports
[z
] = port
+ z
; 621 HOSTDATA(pshost
)->ports
[11] = port
+ REG_FAIL
; 622 HOSTDATA(pshost
)->ports
[12] = port
+ REG_ALT_STAT
; 623 DEB(printk("\nPorts =")); 624 DEB(for(z
=0;z
<13;z
++)printk(" %#04X",HOSTDATA(pshost
)->ports
[z
]);); 626 for( z
=0; z
< chipConfig
.numDrives
; ++z
) 628 unit
= chipDevice
[z
].channel
&0x0F; 629 HOSTDATA(pshost
)->device
[unit
].device
= ChipSetup
.setupDevice
[unit
].device
; 630 HOSTDATA(pshost
)->device
[unit
].byte6
= (UCHAR
)(((unit
&1) <<4) |0xE0); 631 HOSTDATA(pshost
)->device
[unit
].spigot
= (UCHAR
)(1<< (unit
>>1)); 632 HOSTDATA(pshost
)->device
[unit
].sectors
= ChipSetup
.setupDevice
[unit
].sectors
; 633 HOSTDATA(pshost
)->device
[unit
].heads
= ChipSetup
.setupDevice
[unit
].heads
; 634 HOSTDATA(pshost
)->device
[unit
].cylinders
= ChipSetup
.setupDevice
[unit
].cylinders
; 635 HOSTDATA(pshost
)->device
[unit
].blocks
= ChipSetup
.setupDevice
[unit
].blocks
; 636 DEB(printk("\nHOSTDATA->device = %X",HOSTDATA(pshost
)->device
[unit
].device
)); 637 DEB(printk("\nbyte6 = %X",HOSTDATA(pshost
)->device
[unit
].byte6
)); 638 DEB(printk("\nspigot = %X",HOSTDATA(pshost
)->device
[unit
].spigot
)); 639 DEB(printk("\nsectors = %X",HOSTDATA(pshost
)->device
[unit
].sectors
)); 640 DEB(printk("\nheads = %X",HOSTDATA(pshost
)->device
[unit
].heads
)); 641 DEB(printk("\ncylinders = %X",HOSTDATA(pshost
)->device
[unit
].cylinders
)); 642 DEB(printk("\nblocks = %lX",HOSTDATA(pshost
)->device
[unit
].blocks
)); 645 restore_flags(flags
); 646 printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x IRQ = %d\n", port
, chipConfig
.irq
); 647 printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n"); 652 scsi_unregister(pshost
); 656 /**************************************************************** 657 * Name: Psi240i_Abort 659 * Description: Process the Abort command from the SCSI manager. 661 * Parameters: SCpnt - Pointer to SCSI command structure. 663 * Returns: Allways snooze. 665 ****************************************************************/ 666 intPsi240i_Abort(Scsi_Cmnd
*SCpnt
) 668 DEB(printk("psi240i_abort\n")); 669 return SCSI_ABORT_SNOOZE
; 671 /**************************************************************** 672 * Name: Psi240i_Reset 674 * Description: Process the Reset command from the SCSI manager. 676 * Parameters: SCpnt - Pointer to SCSI command structure. 677 * flags - Flags about the reset command 679 * Returns: No active command at this time, so this means 680 * that each time we got some kind of response the 681 * last time through. Tell the mid-level code to 682 * request sense information in order to decide what 685 ****************************************************************/ 686 intPsi240i_Reset(Scsi_Cmnd
*SCpnt
,unsigned int reset_flags
) 688 return SCSI_RESET_PUNT
; 693 /**************************************************************** 694 * Name: Psi240i_BiosParam 696 * Description: Process the biosparam request from the SCSI manager to 699 * Parameters: disk - Pointer to SCSI disk structure. 700 * dev - Major/minor number from kernel. 701 * geom - Pointer to integer array to place geometry data. 705 ****************************************************************/ 706 intPsi240i_BiosParam(Scsi_Disk
*disk
, kdev_t dev
,int geom
[]) 710 pdev
= &(HOSTDATA(disk
->device
->host
)->device
[disk
->device
->id
]); 712 geom
[0] = pdev
->heads
; 713 geom
[1] = pdev
->sectors
; 714 geom
[2] = pdev
->cylinders
; 720 /* Eventually this will go into an include file, but this will be later */ 721 Scsi_Host_Template driver_template
= PSI240I
; 723 #include"scsi_module.c"