OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [drivers/] [scsi/] [pci2220i.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*+M*************************************************************************
2
 * Perceptive Solutions, Inc. PCI-2000 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:              pci2220i.c
22
 *
23
 *      Description:    SCSI driver for the PCI2220I EIDE interface card.
24
 *
25
 *-M*************************************************************************/
26
 
27
#include <linux/module.h>
28
 
29
#include <linux/kernel.h>
30
#include <linux/head.h>
31
#include <linux/types.h>
32
#include <linux/string.h>
33
#include <linux/bios32.h>
34
#include <linux/pci.h>
35
#include <linux/ioport.h>
36
#include <linux/delay.h>
37
#include <linux/sched.h>
38
#include <linux/proc_fs.h>
39
#include <asm/dma.h>
40
#include <asm/system.h>
41
#include <asm/io.h>
42
#include <linux/blk.h>
43
#include "scsi.h"
44
#include "hosts.h"
45
 
46
#include "pci2220i.h"
47
#include "psi_dale.h"
48
 
49
#include<linux/stat.h>
50
 
51
struct proc_dir_entry Proc_Scsi_Pci2220i =
52
        { PROC_SCSI_PCI2220I, 7, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 };
53
 
54
//#define DEBUG 1
55
 
56
#ifdef DEBUG
57
#define DEB(x) x
58
#define STOP_HERE       {int st;for(st=0;st<100;st++){st=1;}}
59
#else
60
#define DEB(x)
61
#define STOP_HERE
62
#endif
63
 
64
#define MAXADAPTER 4    /* Increase this and the sizes of the arrays below, if you need more. */
65
 
66
#define MAX_BUS_MASTER_BLOCKS   1               // This is the maximum we can bus master for (1024 bytes)
67
 
68
#define PORT_DATA                               0
69
#define PORT_ERROR                              1
70
#define PORT_SECTOR_COUNT               2
71
#define PORT_LBA_0                              3
72
#define PORT_LBA_8                              4
73
#define PORT_LBA_16                             5
74
#define PORT_LBA_24                             6
75
#define PORT_STAT_CMD                   7
76
#define PORT_STAT_SEL                   8
77
#define PORT_FAIL                               9
78
#define PORT_ALT_STAT                   10
79
 
80
typedef struct
81
        {
82
        UCHAR                   device;                         // device code
83
        UCHAR                   byte6;                          // device select register image
84
        UCHAR                   spigot;                         // spigot number
85
        UCHAR                   sparebyte;                      // placeholder
86
        USHORT                  sectors;                        // number of sectors per track
87
        USHORT                  heads;                          // number of heads
88
        USHORT                  cylinders;                      // number of cylinders for this device
89
        USHORT                  spareword;                      // placeholder
90
        ULONG                   blocks;                         // number of blocks on device
91
        }       OUR_DEVICE, *POUR_DEVICE;
92
 
93
typedef struct
94
        {
95
        USHORT           ports[12];
96
        USHORT           regDmaDesc;                                    // address of the DMA discriptor register for direction of transfer
97
        USHORT           regDmaCmdStat;                                 // Byte #1 of DMA command status register
98
        USHORT           regDmaAddrPci;                                 // 32 bit register for PCI address of DMA
99
        USHORT           regDmaAddrLoc;                                 // 32 bit register for local bus address of DMA
100
        USHORT           regDmaCount;                                   // 32 bit register for DMA transfer count
101
        USHORT           regDmaMode;                                            // 32 bit register for DMA mode control
102
        USHORT           regRemap;                                              // 32 bit local space remap
103
        USHORT           regDesc;                                               // 32 bit local region descriptor
104
        USHORT           regRange;                                              // 32 bit local range
105
        USHORT           regIrqControl;                                 // 16 bit Interrupt enable/disable and status
106
        USHORT           regScratchPad;                                 // scratch pad I/O base address
107
        USHORT           regBase;                                               // Base I/O register for data space
108
        USHORT           basePort;                                              // PLX base I/O port
109
        USHORT           timingMode;                                    // timing mode currently set for adapter
110
        ULONG            timingAddress;                                 // address to use on adapter for current timing mode
111
        OUR_DEVICE       device[4];
112
        IDE_STRUCT       ide;
113
        ULONG            startSector;
114
        USHORT           sectorCount;
115
        Scsi_Cmnd       *SCpnt;
116
        VOID            *buffer;
117
        USHORT           expectingIRQ;
118
        USHORT           readPhase;
119
        }       ADAPTER2220I, *PADAPTER2220I;
120
 
121
#define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata)
122
 
123
 
124
static struct   Scsi_Host          *PsiHost[MAXADAPTER] = {NULL,};  // One for each adapter
125
static                  int                             NumAdapters = 0;
126
static                  IDENTIFY_DATA   identifyData;
127
static                  SETUP                   DaleSetup;
128
 
129
/****************************************************************
130
 *      Name:   WriteData       :LOCAL
131
 *
132
 *      Description:    Write data to device.
133
 *
134
 *      Parameters:             padapter - Pointer adapter data structure.
135
 *
136
 *      Returns:                TRUE if drive does not assert DRQ in time.
137
 *
138
 ****************************************************************/
139
static int WriteData (PADAPTER2220I padapter)
140
        {
141
        ULONG   timer;
142
        USHORT *pports = padapter->ports;
143
 
144
        timer = jiffies + TIMEOUT_DRQ;                                                          // calculate the timeout value
145
        do  {
146
                if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
147
                        {
148
                        outb_p (0, padapter->regDmaDesc);                                                        // write operation
149
                        outl (padapter->timingAddress, padapter->regDmaAddrLoc);
150
                        outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
151
                        outl ((ULONG)padapter->ide.ide.ide[2] * (ULONG)512, padapter->regDmaCount);
152
                        outb_p (1, padapter->regDmaMode);                                                       // interrupts off
153
                        outb_p (0x03, padapter->regDmaCmdStat);                                         // kick the DMA engine in gear
154
                        return 0;
155
                        }
156
                }       while ( timer > jiffies );                                                                      // test for timeout
157
 
158
        padapter->ide.ide.ides.cmd = 0;                                                                  // null out the command byte
159
        return 1;
160
        }
161
/****************************************************************
162
 *      Name:   IdeCmd  :LOCAL
163
 *
164
 *      Description:    Process a queued command from the SCSI manager.
165
 *
166
 *      Parameters:             padapter - Pointer adapter data structure.
167
 *
168
 *      Returns:                Zero if no error or status register contents on error.
169
 *
170
 ****************************************************************/
171
static UCHAR IdeCmd (PADAPTER2220I padapter)
172
        {
173
        ULONG   timer;
174
        USHORT *pports = padapter->ports;
175
        UCHAR   status;
176
 
177
        outb_p (padapter->ide.ide.ides.spigot, pports[PORT_STAT_SEL]);  // select the spigot
178
        outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]);                 // select the drive
179
        timer = jiffies + TIMEOUT_READY;                                                        // calculate the timeout value
180
        DEB(printk ("\npci2220i Issueing new command: 0x%X",padapter->ide.ide.ides.cmd));
181
        do  {
182
                status = inb_p (padapter->ports[PORT_STAT_CMD]);
183
                if ( status & IDE_STATUS_DRDY )
184
                        {
185
                        outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
186
                        outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
187
                        outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
188
                        outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
189
                        padapter->expectingIRQ = 1;
190
                        outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
191
 
192
                        if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
193
                                return (WriteData (padapter));
194
                        return 0;
195
                        }
196
                }       while ( timer > jiffies );                                                                      // test for timeout
197
 
198
        padapter->ide.ide.ides.cmd = 0;                                                                  // null out the command byte
199
        return status;
200
        }
201
/****************************************************************
202
 *      Name:   SetupTransfer   :LOCAL
203
 *
204
 *      Description:    Setup a data transfer command.
205
 *
206
 *      Parameters:             padapter - Pointer adapter data structure.
207
 *                                      drive    - Drive/head register upper nibble only.
208
 *
209
 *      Returns:                TRUE if no data to transfer.
210
 *
211
 ****************************************************************/
212
static int SetupTransfer (PADAPTER2220I padapter, UCHAR drive)
213
        {
214
        if ( padapter->sectorCount )
215
                {
216
                *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
217
                padapter->ide.ide.ide[6] |= drive;
218
//              padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
219
                padapter->ide.ide.ides.sectors = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
220
                padapter->sectorCount -= padapter->ide.ide.ides.sectors;        // bump the start and count for next xfer
221
                padapter->startSector += padapter->ide.ide.ides.sectors;
222
                return 0;
223
                }
224
        else
225
                {
226
                padapter->ide.ide.ides.cmd = 0;                                                          // null out the command byte
227
                padapter->SCpnt = NULL;
228
                return 1;
229
                }
230
        }
231
/****************************************************************
232
 *      Name:   DecodeError     :LOCAL
233
 *
234
 *      Description:    Decode and process device errors.
235
 *
236
 *      Parameters:             pshost - Pointer to host data block.
237
 *                                      status - Status register code.
238
 *
239
 *      Returns:                The driver status code.
240
 *
241
 ****************************************************************/
242
static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
243
        {
244
        PADAPTER2220I   padapter = HOSTDATA(pshost);
245
        UCHAR                   error;
246
 
247
        padapter->expectingIRQ = 0;
248
        padapter->SCpnt = NULL;
249
        if ( status & IDE_STATUS_WRITE_FAULT )
250
                {
251
                return DID_PARITY << 16;
252
                }
253
        if ( status & IDE_STATUS_BUSY )
254
                return DID_BUS_BUSY << 16;
255
 
256
        error = inb_p (padapter->ports[PORT_ERROR]);
257
        DEB(printk ("\npci2220i error register: %x", error));
258
        switch ( error )
259
                {
260
                case IDE_ERROR_AMNF:
261
                case IDE_ERROR_TKONF:
262
                case IDE_ERROR_ABRT:
263
                case IDE_ERROR_IDFN:
264
                case IDE_ERROR_UNC:
265
                case IDE_ERROR_BBK:
266
                default:
267
                        return DID_ERROR << 16;
268
                }
269
        return DID_ERROR << 16;
270
        }
271
/****************************************************************
272
 *      Name:   Irq_Handler     :LOCAL
273
 *
274
 *      Description:    Interrupt handler.
275
 *
276
 *      Parameters:             irq             - Hardware IRQ number.
277
 *                                      dev_id  -
278
 *                                      regs    -
279
 *
280
 *      Returns:                TRUE if drive is not ready in time.
281
 *
282
 ****************************************************************/
283
static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
284
        {
285
        struct Scsi_Host   *shost = NULL;       // Pointer to host data block
286
        PADAPTER2220I           padapter;               // Pointer to adapter control structure
287
        USHORT                     *pports;                     // I/O port array
288
        Scsi_Cmnd                  *SCpnt;
289
        UCHAR                           status;
290
        int                                     z;
291
 
292
//      DEB(printk ("\npci2220i recieved interrupt\n"));
293
 
294
        for ( z = 0; z < NumAdapters;  z++ )                                                             // scan for interrupt to process
295
                {
296
                if ( PsiHost[z]->irq == (UCHAR)(irq & 0xFF) )
297
                        {
298
                        if ( inw_p (HOSTDATA(PsiHost[z])->regIrqControl) & 0x8000 )
299
                                {
300
                                shost = PsiHost[z];
301
                                break;
302
                                }
303
                        }
304
                }
305
 
306
        if ( !shost )
307
                {
308
                DEB (printk ("\npci2220i: not my interrupt"));
309
                return;
310
                }
311
 
312
        padapter = HOSTDATA(shost);
313
        pports = padapter->ports;
314
        SCpnt = padapter->SCpnt;
315
 
316
        if ( !padapter->expectingIRQ )
317
                {
318
                DEB(printk ("\npci2220i Unsolicited interrupt\n"));
319
                return;
320
                }
321
        padapter->expectingIRQ = 0;
322
 
323
        status = inb_p (padapter->ports[PORT_STAT_CMD]);                                        // read the device status
324
        if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
325
                goto irqerror;
326
 
327
        switch ( padapter->ide.ide.ides.cmd )                                                           // decide how to handle the interrupt
328
                {
329
                case IDE_CMD_READ_MULTIPLE:
330
                        if ( padapter->readPhase == 1 )                                                         // is this a bus master channel complete?
331
                                {
332
                                DEB(printk ("\npci2220i processing read interrupt cleanup"));
333
                                outb_p (0x08, padapter->regDmaCmdStat);                                 // cancel interrupt from DMA engine
334
                                padapter->buffer += padapter->ide.ide.ides.sectors * 512;
335
                                if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
336
                                        {
337
                                        SCpnt->result = DID_OK << 16;
338
                                        padapter->SCpnt = NULL;
339
                                        SCpnt->scsi_done (SCpnt);
340
                                        return;
341
                                        }
342
                                padapter->readPhase = 0;
343
                                if ( !(status = IdeCmd (padapter)) )
344
                                        {
345
                                        DEB (printk ("\npci2220i interrupt complete, waiting for another"));
346
                                        return;
347
                                        }
348
                                }
349
                        if ( status & IDE_STATUS_DRQ )
350
                                {
351
                                DEB(printk ("\npci2220i processing read interrupt start bus master cycle"));
352
                                outb_p (8, padapter->regDmaDesc);                                               // read operation
353
                                padapter->readPhase = 1;
354
                                padapter->expectingIRQ = 1;
355
                                outl   (padapter->timingAddress, padapter->regDmaAddrLoc);
356
                                outl   (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci);
357
                                outl   ((ULONG)padapter->ide.ide.ides.sectors * (ULONG)512, padapter->regDmaCount);
358
                                outb_p (5, padapter->regDmaMode);                                               // interrupt enable/disable
359
                                outb_p (0x03, padapter->regDmaCmdStat);                                 // kick the DMA engine in gear
360
                                return;
361
                                }
362
                        break;
363
 
364
                case IDE_CMD_WRITE_MULTIPLE:
365
                        DEB(printk ("\npci2220i processing write interrupt cleanup"));
366
                        padapter->buffer += padapter->ide.ide.ides.sectors * 512;
367
                        if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
368
                                {
369
                                SCpnt->result = DID_OK << 16;
370
                                padapter->SCpnt = NULL;
371
                                SCpnt->scsi_done (SCpnt);
372
                                return;
373
                                }
374
                        if ( !(status = IdeCmd (padapter)) )
375
                                {
376
                                DEB (printk ("\npci2220i interrupt complete, waiting for another"));
377
                                return;
378
                                }
379
                        break;
380
 
381
                case IDE_COMMAND_IDENTIFY:
382
                        {
383
                        PINQUIRYDATA    pinquiryData  = SCpnt->request_buffer;
384
 
385
                        DEB(printk ("\npci2220i processing verify interrupt cleanup"));
386
                        if ( status & IDE_STATUS_DRQ )
387
                                {
388
                                insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
389
 
390
                                memset (pinquiryData, 0, SCpnt->request_bufflen);                // Zero INQUIRY data structure.
391
                                pinquiryData->DeviceType = 0;
392
                                pinquiryData->Versions = 2;
393
                                pinquiryData->AdditionalLength = 35 - 4;
394
 
395
                                // Fill in vendor identification fields.
396
                                for ( z = 0;  z < 20;  z += 2 )
397
                                        {
398
                                        pinquiryData->VendorId[z]         = ((UCHAR *)identifyData.ModelNumber)[z + 1];
399
                                        pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
400
                                        }
401
 
402
                                // Initialize unused portion of product id.
403
                                for ( z = 0;  z < 4;  z++ )
404
                                        pinquiryData->ProductId[12 + z] = ' ';
405
 
406
                                // Move firmware revision from IDENTIFY data to
407
                                // product revision in INQUIRY data.
408
                                for ( z = 0;  z < 4;  z += 2 )
409
                                        {
410
                                        pinquiryData->ProductRevisionLevel[z]    = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
411
                                        pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
412
                                        }
413
 
414
                                SCpnt->result = DID_OK << 16;
415
                                padapter->SCpnt = NULL;
416
                                SCpnt->scsi_done (SCpnt);
417
                                return;
418
                                }
419
                        break;
420
                        }
421
 
422
                default:
423
                        DEB(printk ("\npci2220i no real process here!"));
424
                        SCpnt->result = DID_OK << 16;
425
                        padapter->SCpnt = NULL;
426
                        SCpnt->scsi_done (SCpnt);
427
                        return;
428
                }
429
 
430
irqerror:;
431
        DEB(printk ("\npci2220i error  Device Status: %X\n", status));
432
        SCpnt->result = DecodeError (shost, status);
433
        SCpnt->scsi_done (SCpnt);
434
        }
435
/****************************************************************
436
 *      Name:   Pci2220i_QueueCommand
437
 *
438
 *      Description:    Process a queued command from the SCSI manager.
439
 *
440
 *      Parameters:             SCpnt - Pointer to SCSI command structure.
441
 *                                      done  - Pointer to done function to call.
442
 *
443
 *      Returns:                Status code.
444
 *
445
 ****************************************************************/
446
int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
447
        {
448
        UCHAR              *cdb = (UCHAR *)SCpnt->cmnd;                                 // Pointer to SCSI CDB
449
        PADAPTER2220I   padapter = HOSTDATA(SCpnt->host);                       // Pointer to adapter control structure
450
        POUR_DEVICE             pdev     = &padapter->device[SCpnt->target];// Pointer to device information
451
        UCHAR                   rc;                                                                                     // command return code
452
 
453
        SCpnt->scsi_done = done;
454
        padapter->ide.ide.ides.spigot = pdev->spigot;
455
        padapter->buffer = SCpnt->request_buffer;
456
        if (done)
457
                {
458
                if ( !pdev->device || SCpnt->lun )
459
                        {
460
                        SCpnt->result = DID_BAD_TARGET << 16;
461
                        done (SCpnt);
462
                        return 0;
463
                        }
464
                }
465
        else
466
                {
467
                printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb);
468
                return 0;
469
                }
470
 
471
        DEB (if(*cdb) printk ("\nCDB: %X-  %X %X %X %X %X %X %X %X %X %X ", SCpnt->cmd_len, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]));
472
        switch ( *cdb )
473
                {
474
                case SCSIOP_INQUIRY:                                    // inquiry CDB
475
                        {
476
                        padapter->ide.ide.ide[6] = pdev->byte6;
477
                        padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
478
                        break;
479
                        }
480
 
481
                case SCSIOP_TEST_UNIT_READY:                    // test unit ready CDB
482
                        SCpnt->result = DID_OK << 16;
483
                        done (SCpnt);
484
                        return 0;
485
 
486
                case SCSIOP_READ_CAPACITY:                              // read capctiy CDB
487
                        {
488
                        PREAD_CAPACITY_DATA     pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
489
 
490
                        pdata->blksiz = 0x20000;
491
                        XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
492
                        SCpnt->result = DID_OK << 16;
493
                        done (SCpnt);
494
                        return 0;
495
                        }
496
 
497
                case SCSIOP_VERIFY:                                             // verify CDB
498
                        *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
499
                        padapter->ide.ide.ide[6] |= pdev->byte6;
500
                        padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
501
                        padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
502
                        break;
503
 
504
                case SCSIOP_READ:                                               // read10 CDB
505
                        padapter->startSector = XSCSI2LONG (&cdb[2]);
506
                        padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
507
                        SetupTransfer (padapter, pdev->byte6);
508
                        padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
509
                        padapter->readPhase = 0;
510
                        break;
511
 
512
                case SCSIOP_READ6:                                              // read6  CDB
513
                        padapter->startSector = SCSI2LONG (&cdb[1]);
514
                        padapter->sectorCount = cdb[4];
515
                        SetupTransfer (padapter, pdev->byte6);
516
                        padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
517
                        padapter->readPhase = 0;
518
                        break;
519
 
520
                case SCSIOP_WRITE:                                              // write10 CDB
521
                        padapter->startSector = XSCSI2LONG (&cdb[2]);
522
                        padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
523
                        SetupTransfer (padapter, pdev->byte6);
524
                        padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
525
                        break;
526
                case SCSIOP_WRITE6:                                             // write6  CDB
527
                        padapter->startSector = SCSI2LONG (&cdb[1]);
528
                        padapter->sectorCount = cdb[4];
529
                        SetupTransfer (padapter, pdev->byte6);
530
                        padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
531
                        break;
532
 
533
                default:
534
                        DEB (printk ("pci2220i_queuecommand: Unsupported command %02X\n", *cdb));
535
                        SCpnt->result = DID_ERROR << 16;
536
                        done (SCpnt);
537
                        return 0;
538
                }
539
 
540
        padapter->SCpnt = SCpnt;                                                                        // Save this command data
541
 
542
        rc = IdeCmd (padapter);
543
        if ( rc )
544
                {
545
                padapter->expectingIRQ = 0;
546
                DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
547
                SCpnt->result = DID_ERROR << 16;
548
                done (SCpnt);
549
                return 0;
550
                }
551
        if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
552
                {
553
                if ( WriteData (padapter) )
554
                        {
555
                        padapter->expectingIRQ = 0;
556
                        DEB (printk ("pci2220i_queuecommand: %02X, %02X: Device failed to accept data\n", *cdb, padapter->ide.ide.ides.cmd));
557
                        SCpnt->result = DID_ERROR << 16;
558
                        done (SCpnt);
559
                        return 0;
560
                        }
561
                }
562
        DEB (printk("  now waiting for initial interrupt "));
563
        return 0;
564
        }
565
 
566
static void internal_done(Scsi_Cmnd * SCpnt)
567
        {
568
        SCpnt->SCp.Status++;
569
        }
570
/****************************************************************
571
 *      Name:   Pci2220i_Command
572
 *
573
 *      Description:    Process a command from the SCSI manager.
574
 *
575
 *      Parameters:             SCpnt - Pointer to SCSI command structure.
576
 *
577
 *      Returns:                Status code.
578
 *
579
 ****************************************************************/
580
int Pci2220i_Command (Scsi_Cmnd *SCpnt)
581
        {
582
        DEB(printk("pci2220i_command: ..calling pci2220i_queuecommand\n"));
583
 
584
        Pci2220i_QueueCommand (SCpnt, internal_done);
585
 
586
    SCpnt->SCp.Status = 0;
587
        while (!SCpnt->SCp.Status)
588
                barrier ();
589
        return SCpnt->result;
590
        }
591
/****************************************************************
592
 *      Name:                   ReadFlash
593
 *
594
 *      Description:    Read information from controller Flash memory.
595
 *
596
 *      Parameters:             hostdata - Pointer to host interface data structure.
597
 *                                      pdata    - Pointer to data structures.
598
 *                                      base     - base address in Flash.
599
 *                                      length   - lenght of data space in bytes.
600
 *
601
 *      Returns:                Nothing.
602
 *
603
 ****************************************************************/
604
VOID ReadFlash (PADAPTER2220I hostdata, VOID *pdata, ULONG base, ULONG length)
605
        {
606
        ULONG    oldremap;
607
        UCHAR    olddesc;
608
        ULONG    z;
609
        UCHAR   *pd = (UCHAR *)pdata;
610
 
611
        oldremap = inl (hostdata->regRemap);                                                                    // save values to restore later
612
        olddesc  = inb_p (hostdata->regDesc);
613
 
614
        outl (base | 1, hostdata->regRemap);                                                                    // remap to Flash space as specified
615
        outb_p (0x40, hostdata->regDesc);                                                                               // describe remap region as 8 bit
616
        for ( z = 0;  z < length;  z++)                                                                                  // get "length" data count
617
                *pd++ = inb_p (hostdata->regBase + z);                                                          // read in the data
618
 
619
        outl (oldremap, hostdata->regRemap);                                                                    // restore remap register values
620
        outb_p (olddesc, hostdata->regDesc);
621
        }
622
 
623
/****************************************************************
624
 *      Name:   Pci2220i_Detect
625
 *
626
 *      Description:    Detect and initialize our boards.
627
 *
628
 *      Parameters:             tpnt - Pointer to SCSI host template structure.
629
 *
630
 *      Returns:                Number of adapters found.
631
 *
632
 ****************************************************************/
633
int Pci2220i_Detect (Scsi_Host_Template *tpnt)
634
        {
635
        int                                     pci_index = 0;
636
        struct Scsi_Host   *pshost;
637
        PADAPTER2220I       hostdata;
638
        ULONG                           modearray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P};
639
        int                                     unit;
640
        int                                     z;
641
        int                                     setirq;
642
 
643
        if ( pcibios_present () )
644
                {
645
                for ( pci_index = 0;  pci_index <= MAXADAPTER;  ++pci_index )
646
                        {
647
                        UCHAR   pci_bus, pci_device_fn;
648
 
649
                        if ( pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, pci_index, &pci_bus, &pci_device_fn) != 0 )
650
                                break;
651
 
652
                        pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
653
                        hostdata = HOSTDATA(pshost);
654
 
655
                        pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &hostdata->basePort);
656
                        hostdata->basePort &= 0xFFFE;
657
                        DEB (printk ("\nBase Regs = %#04X", hostdata->basePort));
658
                        hostdata->regRemap              = hostdata->basePort + RTR_LOCAL_REMAP;                         // 32 bit local space remap
659
                        DEB (printk (" %#04X", hostdata->regRemap));
660
                        hostdata->regDesc               = hostdata->basePort + RTR_REGIONS;                                     // 32 bit local region descriptor
661
                        DEB (printk (" %#04X", hostdata->regDesc));
662
                        hostdata->regRange              = hostdata->basePort + RTR_LOCAL_RANGE;                         // 32 bit local range
663
                        DEB (printk (" %#04X", hostdata->regRange));
664
                        hostdata->regIrqControl = hostdata->basePort + RTR_INT_CONTROL_STATUS;          // 16 bit interupt control and status
665
                        DEB (printk (" %#04X", hostdata->regIrqControl));
666
                        hostdata->regScratchPad = hostdata->basePort + RTR_MAILBOX;                                     // 16 byte scratchpad I/O base address
667
                        DEB (printk (" %#04X", hostdata->regScratchPad));
668
 
669
                        pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &hostdata->regBase);
670
                        hostdata->regBase &= 0xFFFE;
671
                        for ( z = 0;  z < 9;  z++ )                                                                                                      // build regester address array
672
                                hostdata->ports[z] = hostdata->regBase + 0x80 + (z * 4);
673
                        hostdata->ports[PORT_FAIL] = hostdata->regBase + REG_FAIL;
674
                        hostdata->ports[PORT_ALT_STAT] = hostdata->regBase + REG_ALT_STAT;
675
                        DEB (printk ("\nPorts ="));
676
                        DEB (for (z=0;z<11;z++) printk(" %#04X", hostdata->ports[z]););
677
 
678
                        hostdata->regDmaDesc    = hostdata->regBase + RTL_DMA1_DESC_PTR;                        // address of the DMA discriptor register for direction of transfer
679
                        DEB (printk ("\nDMA Regs = %#04X", hostdata->regDmaDesc));
680
                        hostdata->regDmaCmdStat = hostdata->regBase + RTL_DMA_COMMAND_STATUS + 1;       // Byte #1 of DMA command status register
681
                        DEB (printk (" %#04X", hostdata->regDmaCmdStat));
682
                        hostdata->regDmaAddrPci = hostdata->regBase + RTL_DMA1_PCI_ADDR;                        // 32 bit register for PCI address of DMA
683
                        DEB (printk (" %#04X", hostdata->regDmaAddrPci));
684
                        hostdata->regDmaAddrLoc = hostdata->regBase + RTL_DMA1_LOCAL_ADDR;                      // 32 bit register for local bus address of DMA
685
                        DEB (printk (" %#04X", hostdata->regDmaAddrLoc));
686
                        hostdata->regDmaCount   = hostdata->regBase + RTL_DMA1_COUNT;                           // 32 bit register for DMA transfer count
687
                        DEB (printk (" %#04X", hostdata->regDmaCount));
688
                        hostdata->regDmaMode    = hostdata->regBase + RTL_DMA1_MODE + 1;                        // 32 bit register for DMA mode control
689
                        DEB (printk (" %#04X", hostdata->regDmaMode));
690
 
691
                        if ( !inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES) )                                       // if no devices on this board
692
                                goto unregister;
693
 
694
                        pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq);
695
                        setirq = 1;
696
                        for ( z = 0;  z < pci_index;  z++ )                                                                                      // scan for shared interrupts
697
                                {
698
                                if ( PsiHost[z]->irq == pshost->irq )                                           // if shared then, don't posses
699
                                        setirq = 0;
700
                                }
701
                        if ( setirq )                                                                                                                           // if not shared, posses
702
                                {
703
                                if ( request_irq (pshost->irq, Irq_Handler, 0, "pci2220i", NULL) )
704
                                        {
705
                                        printk ("Unable to allocate IRQ for PSI-2220I controller.\n");
706
                                        goto unregister;
707
                                        }
708
                                }
709
                        PsiHost[pci_index]      = pshost;                                                                                               // save SCSI_HOST pointer
710
 
711
                        pshost->unique_id       = hostdata->regBase;
712
                        pshost->max_id          = 4;
713
 
714
                        outb_p (0x01, hostdata->regRange);                                                                                      // fix our range register because other drivers want to tromp on it
715
 
716
                        hostdata->timingMode    = inb_p (hostdata->regScratchPad + DALE_TIMING_MODE);
717
                        hostdata->timingAddress = modearray[hostdata->timingMode - 2];
718
                        ReadFlash (hostdata, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
719
 
720
                        for ( z = 0;  z < inb_p (hostdata->regScratchPad + DALE_NUM_DRIVES);  ++z )
721
                                {
722
                                unit = inb_p (hostdata->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F;
723
                                hostdata->device[unit].device    = inb_p (hostdata->regScratchPad + DALE_SCRATH_DEVICE_0 + unit);
724
                                hostdata->device[unit].byte6     = (UCHAR)(((unit & 1) << 4) | 0xE0);
725
                                hostdata->device[unit].spigot    = (UCHAR)(1 << (unit >> 1));
726
                                hostdata->device[unit].sectors   = DaleSetup.setupDevice[unit].sectors;
727
                                hostdata->device[unit].heads     = DaleSetup.setupDevice[unit].heads;
728
                                hostdata->device[unit].cylinders = DaleSetup.setupDevice[unit].cylinders;
729
                                hostdata->device[unit].blocks    = DaleSetup.setupDevice[unit].blocks;
730
                                DEB (printk ("\nHOSTDATA->device    = %X", hostdata->device[unit].device));
731
                                DEB (printk ("\n          byte6     = %X", hostdata->device[unit].byte6));
732
                                DEB (printk ("\n          spigot    = %X", hostdata->device[unit].spigot));
733
                                DEB (printk ("\n          sectors   = %X", hostdata->device[unit].sectors));
734
                                DEB (printk ("\n          heads     = %X", hostdata->device[unit].heads));
735
                                DEB (printk ("\n          cylinders = %X", hostdata->device[unit].cylinders));
736
                                DEB (printk ("\n          blocks    = %lX", hostdata->device[unit].blocks));
737
                                }
738
 
739
                        printk("\nPSI-2220I EIDE CONTROLLER: at I/O = %X/%X  IRQ = %d\n", hostdata->basePort, hostdata->regBase, pshost->irq);
740
                        printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
741
 
742
                        NumAdapters++;
743
                        continue;
744
unregister:;
745
                        scsi_unregister (pshost);
746
                        }
747
                }
748
        return NumAdapters;
749
        }
750
/****************************************************************
751
 *      Name:   Pci2220i_Abort
752
 *
753
 *      Description:    Process the Abort command from the SCSI manager.
754
 *
755
 *      Parameters:             SCpnt - Pointer to SCSI command structure.
756
 *
757
 *      Returns:                Allways snooze.
758
 *
759
 ****************************************************************/
760
int Pci2220i_Abort (Scsi_Cmnd *SCpnt)
761
        {
762
        DEB (printk ("pci2220i_abort\n"));
763
        return SCSI_ABORT_SNOOZE;
764
        }
765
/****************************************************************
766
 *      Name:   Pci2220i_Reset
767
 *
768
 *      Description:    Process the Reset command from the SCSI manager.
769
 *
770
 *      Parameters:             SCpnt - Pointer to SCSI command structure.
771
 *                                      flags - Flags about the reset command
772
 *
773
 *      Returns:                No active command at this time, so this means
774
 *                                      that each time we got some kind of response the
775
 *                                      last time through.  Tell the mid-level code to
776
 *                                      request sense information in order to decide what
777
 *                                      to do next.
778
 *
779
 ****************************************************************/
780
int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
781
        {
782
        return SCSI_RESET_PUNT;
783
        }
784
 
785
#include "sd.h"
786
 
787
/****************************************************************
788
 *      Name:   Pci2220i_BiosParam
789
 *
790
 *      Description:    Process the biosparam request from the SCSI manager to
791
 *                                      return C/H/S data.
792
 *
793
 *      Parameters:             disk - Pointer to SCSI disk structure.
794
 *                                      dev      - Major/minor number from kernel.
795
 *                                      geom - Pointer to integer array to place geometry data.
796
 *
797
 *      Returns:                zero.
798
 *
799
 ****************************************************************/
800
int Pci2220i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
801
        {
802
        POUR_DEVICE     pdev;
803
 
804
        pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]);
805
 
806
        geom[0] = pdev->heads;
807
        geom[1] = pdev->sectors;
808
        geom[2] = pdev->cylinders;
809
        return 0;
810
        }
811
 
812
 
813
#ifdef MODULE
814
/* Eventually this will go into an include file, but this will be later */
815
Scsi_Host_Template driver_template = PCI2220I;
816
 
817
#include "scsi_module.c"
818
#endif
819
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.