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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [armnommu/] [drivers/] [scsi/] [fas216_mod.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * linux/arch/arm/drivers/scsi/fas216.c
3
 *
4
 * Copyright (C) 1997 Russell King
5
 *
6
 * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and
7
 * other sources, including:
8
 *   the AMD Am53CF94 data sheet
9
 *
10
 * This is a generic driver.  To use it, have a look at cumana_2.c.  You
11
 * should define your own structure that overlays FAS216_Info, eg:
12
 * struct my_host_data {
13
 *    FAS216_Info info;
14
 *    ... my host specific data ...
15
 * };
16
 *
17
 * Changelog:
18
 *  30-08-1997  RMK     Created
19
 *  14-09-1997  RMK     Started disconnect support
20
 *  08-02-1998  RMK     Corrected real DMA support
21
 *  15-02-1998  RMK     Started sync xfer support
22
 *  06-04-1998  RMK     Tightened conditions for printing incomplete
23
 *                      transfers
24
 *  02-05-1998  RMK     Added extra checks in fas216_reset
25
 *  24-05-1998  RMK     Fixed synchronous transfers with period >= 200ns
26
 *  26-08-1998  RMK     Improved message support wrt MESSAGE_REJECT
27
 *
28
 * Todo:
29
 *  - allow individual devices to enable sync xfers.
30
 */
31
 
32
#define __NO_VERSION__
33
 
34
#include <linux/module.h>
35
#include <linux/blk.h>
36
#include <linux/kernel.h>
37
#include <linux/string.h>
38
#include <linux/ioport.h>
39
#include <linux/sched.h>
40
#include <linux/proc_fs.h>
41
#include <linux/unistd.h>
42
#include <linux/stat.h>
43
 
44
#include <asm/delay.h>
45
#include <asm/dma.h>
46
#include <asm/io.h>
47
#include <asm/irq.h>
48
#include <asm/ecard.h>
49
 
50
#define FAS216_C
51
 
52
#include "scsi.h"
53
#include "hosts.h"
54
#include "fas216.h"
55
 
56
#define VER_MAJOR       0
57
#define VER_MINOR       0
58
#define VER_PATCH       5
59
 
60
#define SCSI2_TAG
61
 
62
/* NOTE: SCSI2 Synchronous transfers *require* DMA according to
63
 *  the data sheet.  This restriction is crazy, especially when
64
 *  you only want to send 16 bytes!  What were the guys who
65
 *  designed this chip on at that time?  Did they read the SCSI2
66
 *  spec at all?  The following sections are taken from the SCSI2
67
 *  standard (s2r10) concerning this:
68
 *
69
 * > IMPLEMENTORS NOTES:
70
 * >   (1)  Re-negotiation at every selection is not recommended, since a
71
 * >   significant performance impact is likely.
72
 *
73
 * >  The implied synchronous agreement shall remain in effect until a BUS DEVICE
74
 * >  RESET message is received, until a hard reset condition occurs, or until one
75
 * >  of the two SCSI devices elects to modify the agreement.  The default data
76
 * >  transfer mode is asynchronous data transfer mode.  The default data transfer
77
 * >  mode is entered at power on, after a BUS DEVICE RESET message, or after a hard
78
 * >  reset condition.
79
 *
80
 *  In total, this means that once you have elected to use synchronous
81
 *  transfers, you must always use DMA.
82
 *
83
 *  I was thinking that this was a good chip until I found this restriction ;(
84
 */
85
#define SCSI2_SYNC
86
 
87
#define SCSI2_WIDE
88
 
89
#undef DEBUG_CONNECT
90
#undef DEBUG_BUSSERVICE
91
#undef DEBUG_FUNCTIONDONE
92
#undef DEBUG_MESSAGES
93
 
94
#undef CHECK_STRUCTURE
95
 
96
static struct { int stat, ssr, isr, ph; } list[8];
97
static int ptr;
98
 
99
static void fas216_dumpstate(FAS216_Info *info)
100
{
101
        printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X"
102
               " INST=%02X IS=%02X CFIS=%02X",
103
                inb(REG_CTCL(info)), inb(REG_CTCM(info)),
104
                inb(REG_CMD(info)),  inb(REG_STAT(info)),
105
                inb(REG_INST(info)), inb(REG_IS(info)),
106
                inb(REG_CFIS(info)));
107
        printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n",
108
                inb(REG_CNTL1(info)), inb(REG_CNTL2(info)),
109
                inb(REG_CNTL3(info)), inb(REG_CTCH(info)));
110
}
111
 
112
static void fas216_dumpinfo(FAS216_Info *info)
113
{
114
        static int used = 0;
115
        int i;
116
 
117
        if (used++)
118
                return;
119
 
120
        printk("FAS216_Info=\n");
121
        printk("  { magic_start=%lX host=%p SCpnt=%p origSCpnt=%p\n",
122
                info->magic_start, info->host, info->SCpnt,
123
                info->origSCpnt);
124
        printk("    scsi={ io_port=%X io_shift=%X irq=%X cfg={ %X %X %X %X }\n",
125
                info->scsi.io_port, info->scsi.io_shift, info->scsi.irq,
126
                info->scsi.cfg[0], info->scsi.cfg[1], info->scsi.cfg[2],
127
                info->scsi.cfg[3]);
128
        printk("           type=%p phase=%X reconnected={ target=%d lun=%d tag=%d }\n",
129
                info->scsi.type, info->scsi.phase,
130
                info->scsi.reconnected.target,
131
                info->scsi.reconnected.lun, info->scsi.reconnected.tag);
132
        printk("           SCp={ ptr=%p this_residual=%X buffer=%p buffers_residual=%X }\n",
133
                info->scsi.SCp.ptr, info->scsi.SCp.this_residual,
134
                info->scsi.SCp.buffer, info->scsi.SCp.buffers_residual);
135
        printk("      msgs async_stp=%X disconnectable=%d aborting=%d }\n",
136
                info->scsi.async_stp,
137
                info->scsi.disconnectable, info->scsi.aborting);
138
        printk("    stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"
139
               "            disconnects=%X aborts=%X resets=%X }\n",
140
                info->stats.queues, info->stats.removes, info->stats.fins,
141
                info->stats.reads, info->stats.writes, info->stats.miscs,
142
                info->stats.disconnects, info->stats.aborts, info->stats.resets);
143
        printk("    ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n",
144
                info->ifcfg.clockrate, info->ifcfg.select_timeout,
145
                info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);
146
        for (i = 0; i < 8; i++) {
147
                printk("    busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n",
148
                        i, info->busyluns[i], i,
149
                        info->device[i].disconnect_ok, info->device[i].stp,
150
                        info->device[i].sof, info->device[i].sync_state);
151
        }
152
        printk("    dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n",
153
                info->dma.transfer_type, info->dma.setup,
154
                info->dma.pseudo, info->dma.stop);
155
        printk("    internal_done=%X magic_end=%lX }\n",
156
                info->internal_done, info->magic_end);
157
}
158
 
159
#ifdef CHECK_STRUCTURE
160
static void fas216_checkmagic(FAS216_Info *info, const char *func)
161
{
162
        int corruption = 0;
163
        if (info->magic_start != MAGIC) {
164
                printk(KERN_CRIT "FAS216 Error: magic at start corrupted\n");
165
                corruption++;
166
        }
167
        if (info->magic_end != MAGIC) {
168
                printk(KERN_CRIT "FAS216 Error: magic at end corrupted\n");
169
                corruption++;
170
        }
171
        if (corruption) {
172
                fas216_dumpinfo(info);
173
                panic("scsi memory space corrupted in %s", func);
174
        }
175
}
176
#else
177
#define fas216_checkmagic(info,func)
178
#endif
179
 
180
static const char *fas216_bus_phase(int stat)
181
{
182
        static const char *phases[] = {
183
                "DATA OUT", "DATA IN",
184
                "COMMAND", "STATUS",
185
                "MISC OUT", "MISC IN",
186
                "MESG OUT", "MESG IN"
187
        };
188
 
189
        return phases[stat & STAT_BUSMASK];
190
}
191
 
192
static const char *fas216_drv_phase(FAS216_Info *info)
193
{
194
        switch (info->scsi.phase) {
195
        case PHASE_IDLE:                return "idle";
196
        case PHASE_SELECTION:           return "selection";
197
        case PHASE_COMMAND:             return "command";
198
        case PHASE_RECONNECTED:         return "reconnected";
199
        case PHASE_DATAOUT:             return "data out";
200
        case PHASE_DATAIN:              return "data in";
201
        case PHASE_MSGIN:               return "message in";
202
        case PHASE_MSGIN_DISCONNECT:    return "disconnect";
203
        case PHASE_MSGOUT_EXPECT:       return "expect message out";
204
        case PHASE_MSGOUT:              return "message out";
205
        case PHASE_STATUS:              return "status";
206
        case PHASE_DONE:                return "done";
207
        default:                        return "???";
208
        }
209
}
210
 
211
static char fas216_target(FAS216_Info *info)
212
{
213
        if (info->SCpnt)
214
                return '0' + info->SCpnt->target;
215
        else
216
                return 'H';
217
}
218
 
219
static void add_debug_list(int stat, int ssr, int isr, int ph)
220
{
221
        list[ptr].stat = stat;
222
        list[ptr].ssr = ssr;
223
        list[ptr].isr = isr;
224
        list[ptr].ph = ph;
225
 
226
        ptr = (ptr + 1) & 7;
227
}
228
 
229
static void print_debug_list(void)
230
{
231
        int i;
232
 
233
        i = ptr;
234
 
235
        printk(KERN_ERR "SCSI IRQ trail: ");
236
        do {
237
                printk("%02X:%02X:%02X:%1X ",
238
                        list[i].stat, list[i].ssr,
239
                        list[i].isr, list[i].ph);
240
                i = (i + 1) & 7;
241
        } while (i != ptr);
242
        printk("\n");
243
}
244
 
245
static void fas216_done(FAS216_Info *info, unsigned int result);
246
 
247
/* Function: int fas216_clockrate(unsigned int clock)
248
 * Purpose : calculate correct value to be written into clock conversion
249
 *           factor register.
250
 * Params  : clock - clock speed in MHz
251
 * Returns : CLKF_ value
252
 */
253
static int fas216_clockrate(int clock)
254
{
255
        if (clock <= 10 || clock > 40) {
256
                printk(KERN_CRIT
257
                       "fas216: invalid clock rate: check your driver!\n");
258
                clock = -1;
259
        } else
260
                clock = ((clock - 1) / 5 + 1) & 7;
261
 
262
        return clock;
263
}
264
 
265
/* Function: unsigned short fas216_get_last_msg(FAS216_Info *info, int pos)
266
 * Purpose : retrieve a last message from the list, using position in fifo
267
 * Params  : info - interface to search
268
 *         : pos  - current fifo position
269
 */
270
static inline unsigned short
271
fas216_get_last_msg(FAS216_Info *info, int pos)
272
{
273
        unsigned short packed_msg = NOP;
274
        struct message *msg;
275
        int msgnr = 0;
276
 
277
        while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
278
                if (pos >= msg->fifo)
279
                        break;
280
        }
281
 
282
        if (msg) {
283
                if (msg->msg[0] == EXTENDED_MESSAGE)
284
                        packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8;
285
                else
286
                        packed_msg = msg->msg[0];
287
        }
288
 
289
#ifdef DEBUG_MESSAGES
290
        printk("Message: %04X found at position %02X\n",
291
                packed_msg, pos);
292
#endif
293
        return packed_msg;
294
}
295
 
296
/* Function: int fas216_syncperiod(FAS216_Info *info, int ns)
297
 * Purpose : Calculate value to be loaded into the STP register
298
 *           for a given period in ns
299
 * Params  : info - state structure for interface connected to device
300
 *         : ns   - period in ns (between subsequent bytes)
301
 * Returns : Value suitable for REG_STP
302
 */
303
static int
304
fas216_syncperiod(FAS216_Info *info, int ns)
305
{
306
        int value = (info->ifcfg.clockrate * ns) / 1000;
307
 
308
        fas216_checkmagic(info, "fas216_syncperiod");
309
 
310
        if (value < 4)
311
                value = 4;
312
        else if (value > 35)
313
                value = 35;
314
 
315
        return value & 31;
316
}
317
 
318
/* Function: void fas216_set_sync(FAS216_Info *info, int target)
319
 * Purpose : Correctly setup FAS216 chip for specified transfer period.
320
 * Params  : info   - state structure for interface
321
 *         : target - target
322
 * Notes   : we need to switch the chip out of FASTSCSI mode if we have
323
 *           a transfer period >= 200ns - otherwise the chip will violate
324
 *           the SCSI timings.
325
 */
326
static void
327
fas216_set_sync(FAS216_Info *info, int target)
328
{
329
        outb(info->device[target].sof, REG_SOF(info));
330
        outb(info->device[target].stp, REG_STP(info));
331
        if (info->device[target].period >= (200 / 4))
332
                outb(info->scsi.cfg[2] & ~CNTL3_FASTSCSI, REG_CNTL3(info));
333
        else
334
                outb(info->scsi.cfg[2], REG_CNTL3(info));
335
}
336
 
337
/* Synchronous transfer support
338
 *
339
 * Note: The SCSI II r10 spec says (5.6.12):
340
 *
341
 *  (2)  Due to historical problems with early host adapters that could
342
 *  not accept an SDTR message, some targets may not initiate synchronous
343
 *  negotiation after a power cycle as required by this standard.  Host
344
 *  adapters that support synchronous mode may avoid the ensuing failure
345
 *  modes when the target is independently power cycled by initiating a
346
 *  synchronous negotiation on each REQUEST SENSE and INQUIRY command.
347
 *  This approach increases the SCSI bus overhead and is not recommended
348
 *  for new implementations.  The correct method is to respond to an
349
 *  SDTR message with a MESSAGE REJECT message if the either the
350
 *  initiator or target devices does not support synchronous transfers
351
 *  or does not want to negotiate for synchronous transfers at the time.
352
 *  Using the correct method assures compatibility with wide data
353
 *  transfers and future enhancements.
354
 *
355
 * We will always initiate a synchronous transfer negociation request on
356
 * every INQUIRY or REQUEST SENSE message, unless the target itself has
357
 * at some point performed a synchronous transfer negociation request, or
358
 * we have synchronous transfers disabled for this device.
359
 */
360
 
361
/* Function: void fas216_handlesync(FAS216_Info *info, char *msg)
362
 * Purpose : Handle a synchronous transfer message from the target
363
 * Params  : info - state structure for interface
364
 *         : msg  - message from target
365
 */
366
static void
367
fas216_handlesync(FAS216_Info *info, char *msg)
368
{
369
        struct fas216_device *dev = &info->device[info->SCpnt->target];
370
        enum { sync, async, none, reject } res = none;
371
 
372
#ifdef SCSI2_SYNC
373
        switch (msg[0]) {
374
        case MESSAGE_REJECT:
375
                /* Synchronous transfer request failed.
376
                 * Note: SCSI II r10:
377
                 *
378
                 *  SCSI devices that are capable of synchronous
379
                 *  data transfers shall not respond to an SDTR
380
                 *  message with a MESSAGE REJECT message.
381
                 *
382
                 * Hence, if we get this condition, we disable
383
                 * negociation for this device.
384
                 */
385
                if (dev->sync_state == neg_inprogress) {
386
                        dev->sync_state = neg_invalid;
387
                        res = async;
388
                }
389
                break;
390
 
391
        case EXTENDED_MESSAGE:
392
                switch (dev->sync_state) {
393
                /* We don't accept synchronous transfer requests.
394
                 * Respond with a MESSAGE_REJECT to prevent a
395
                 * synchronous transfer agreement from being reached.
396
                 */
397
                case neg_invalid:
398
                        res = reject;
399
                        break;
400
 
401
                /* We were not negociating a synchronous transfer,
402
                 * but the device sent us a negociation request.
403
                 * Honour the request by sending back a SDTR
404
                 * message containing our capability, limited by
405
                 * the targets capability.
406
                 */
407
                default:
408
                        outb(CMD_SETATN, REG_CMD(info));
409
                        if (msg[4] > info->ifcfg.sync_max_depth)
410
                                msg[4] = info->ifcfg.sync_max_depth;
411
                        if (msg[3] < 1000 / info->ifcfg.clockrate)
412
                                msg[3] = 1000 / info->ifcfg.clockrate;
413
 
414
                        msgqueue_flush(&info->scsi.msgs);
415
                        msgqueue_addmsg(&info->scsi.msgs, 5,
416
                                        EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
417
                                        msg[3], msg[4]);
418
                        info->scsi.phase = PHASE_MSGOUT_EXPECT;
419
 
420
                        /* This is wrong.  The agreement is not in effect
421
                         * until this message is accepted by the device
422
                         */
423
                        dev->sync_state = neg_targcomplete;
424
                        res = sync;
425
                        break;
426
 
427
                /* We initiated the synchronous transfer negociation,
428
                 * and have successfully received a response from the
429
                 * target.  The synchronous transfer agreement has been
430
                 * reached.  Note: if the values returned are out of our
431
                 * bounds, we must reject the message.
432
                 */
433
                case neg_inprogress:
434
                        res = reject;
435
                        if (msg[4] <= info->ifcfg.sync_max_depth &&
436
                            msg[3] >= 1000 / info->ifcfg.clockrate) {
437
                                dev->sync_state = neg_complete;
438
                                res = sync;
439
                        }
440
                        break;
441
                }
442
        }
443
#else
444
        res = reject;
445
#endif
446
 
447
        switch (res) {
448
        case sync:
449
                dev->period = msg[3];
450
                dev->sof    = msg[4];
451
                dev->stp    = fas216_syncperiod(info, msg[3] * 4);
452
                fas216_set_sync(info, info->SCpnt->target);
453
                break;
454
 
455
        case reject:
456
                outb(CMD_SETATN, REG_CMD(info));
457
                msgqueue_flush(&info->scsi.msgs);
458
                msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
459
                info->scsi.phase = PHASE_MSGOUT_EXPECT;
460
 
461
        case async:
462
                dev->period = info->ifcfg.asyncperiod / 4;
463
                dev->sof    = 0;
464
                dev->stp    = info->scsi.async_stp;
465
                fas216_set_sync(info, info->SCpnt->target);
466
                break;
467
 
468
        case none:
469
                break;
470
        }
471
}
472
 
473
/* Function: void fas216_handlewide(FAS216_Info *info, char *msg)
474
 * Purpose : Handle a wide transfer message from the target
475
 * Params  : info - state structure for interface
476
 *         : msg  - message from target
477
 */
478
static void
479
fas216_handlewide(FAS216_Info *info, char *msg)
480
{
481
        struct fas216_device *dev = &info->device[info->SCpnt->target];
482
        enum { wide, bit8, none, reject } res = none;
483
 
484
#ifdef SCSI2_WIDE
485
        switch (msg[0]) {
486
        case MESSAGE_REJECT:
487
                /* Wide transfer request failed.
488
                 * Note: SCSI II r10:
489
                 *
490
                 *  SCSI devices that are capable of wide
491
                 *  data transfers shall not respond to a
492
                 *  WDTR message with a MESSAGE REJECT message.
493
                 *
494
                 * Hence, if we get this condition, we never
495
                 * reattempt negociation for this device.
496
                 */
497
                if (dev->wide_state == neg_inprogress) {
498
                        dev->wide_state = neg_invalid;
499
                        res = bit8;
500
                }
501
                break;
502
 
503
        case EXTENDED_MESSAGE:
504
                switch (dev->wide_state) {
505
                /* We don't accept wide data transfer requests.
506
                 * Respond with a MESSAGE REJECT to prevent a
507
                 * wide data transfer agreement from being reached.
508
                 */
509
                case neg_invalid:
510
                        res = reject;
511
                        break;
512
 
513
                /* We were not negociating a wide data transfer,
514
                 * but the device sent is a negociation request.
515
                 * Honour the request by sending back a WDTR
516
                 * message containing our capability, limited by
517
                 * the targets capability.
518
                 */
519
                default:
520
                        outb(CMD_SETATN, REG_CMD(info));
521
                        if (msg[3] > info->ifcfg.wide_max_size)
522
                                msg[3] = info->ifcfg.wide_max_size;
523
 
524
                        msgqueue_flush(&info->scsi.msgs);
525
                        msgqueue_addmsg(&info->scsi.msgs, 4,
526
                                        EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
527
                                        msg[3]);
528
                        info->scsi.phase = PHASE_MSGOUT_EXPECT;
529
                        res = wide;
530
                        break;
531
 
532
                /* We initiated the wide data transfer negociation,
533
                 * and have successfully received a response from the
534
                 * target.  The synchronous transfer agreement has been
535
                 * reached.  Note: if the values returned are out of our
536
                 * bounds, we must reject the message.
537
                 */
538
                case neg_inprogress:
539
                        res = reject;
540
                        if (msg[3] <= info->ifcfg.wide_max_size) {
541
                                dev->wide_state = neg_complete;
542
                                res = wide;
543
                        }
544
                        break;
545
                }
546
        }
547
#else
548
        res = reject;
549
#endif
550
 
551
        switch (res) {
552
        case wide:
553
                dev->wide_xfer = msg[3];
554
                break;
555
 
556
        case reject:
557
                outb(CMD_SETATN, REG_CMD(info));
558
                msgqueue_flush(&info->scsi.msgs);
559
                msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
560
                info->scsi.phase = PHASE_MSGOUT_EXPECT;
561
 
562
        case bit8:
563
                dev->wide_xfer = 0;
564
                break;
565
 
566
        case none:
567
                break;
568
        }
569
}
570
 
571
/* Function: void fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
572
 * Purpose : update data pointers after transfer suspended/paused
573
 * Params  : info              - interface's local pointer to update
574
 *           bytes_transferred - number of bytes transferred
575
 */
576
static void
577
fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
578
{
579
        unsigned char *ptr;
580
        unsigned int residual;
581
 
582
        fas216_checkmagic(info, "fas216_updateptrs");
583
 
584
        ptr = info->scsi.SCp.ptr;
585
        residual = info->scsi.SCp.this_residual;
586
 
587
        info->SCpnt->request_bufflen -= bytes_transferred;
588
 
589
        while (residual <= bytes_transferred && bytes_transferred) {
590
                /* We have used up this buffer */
591
                bytes_transferred -= residual;
592
                if (info->scsi.SCp.buffers_residual) {
593
                        info->scsi.SCp.buffer++;
594
                        info->scsi.SCp.buffers_residual--;
595
                        ptr = (unsigned char *)info->scsi.SCp.buffer->address;
596
                        residual = info->scsi.SCp.buffer->length;
597
                } else {
598
                        ptr = NULL;
599
                        residual = 0;
600
                }
601
        }
602
 
603
        residual -= bytes_transferred;
604
        ptr += bytes_transferred;
605
 
606
        if (residual == 0)
607
                ptr = NULL;
608
 
609
        info->scsi.SCp.ptr = ptr;
610
        info->scsi.SCp.this_residual = residual;
611
}
612
 
613
/* Function: void fas216_pio(FAS216_Info *info, fasdmadir_t direction)
614
 * Purpose : transfer data off of/on to card using programmed IO
615
 * Params  : info      - interface to transfer data to/from
616
 *           direction - direction to transfer data (DMA_OUT/DMA_IN)
617
 * Notes   : this is incredibly slow
618
 */
619
static void
620
fas216_pio(FAS216_Info *info, fasdmadir_t direction)
621
{
622
        unsigned int residual;
623
        char *ptr;
624
        int correction;
625
 
626
        fas216_checkmagic(info, "fas216_pio");
627
 
628
        residual = info->scsi.SCp.this_residual;
629
        ptr = info->scsi.SCp.ptr;
630
 
631
        if (direction == DMA_OUT) {
632
//              while (residual > 0) {
633
//                      if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) {
634
                                outb(*ptr++, REG_FF(info));
635
                                residual -= 1;
636
//                      }
637
//                      if (inb(REG_STAT(info)) & STAT_INT)
638
//                              break;
639
//              }
640
//              correction = inb(REG_CFIS(info)) & CFIS_CF;
641
correction = 0;
642
        } else {
643
//              while (residual > 0) {
644
//                      if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) {
645
                                *ptr++ = inb(REG_FF(info));
646
                                residual -= 1;
647
//                      }
648
//                      if (inb(REG_STAT(info)) & STAT_INT)
649
//                              break;
650
//              }
651
                correction = 0;
652
        }
653
 
654
        ptr -= correction;
655
        residual += correction;
656
 
657
        if (residual == 0) {
658
                if (info->scsi.SCp.buffers_residual) {
659
                        info->scsi.SCp.buffer++;
660
                        info->scsi.SCp.buffers_residual--;
661
                        ptr = (unsigned char *)info->scsi.SCp.buffer->address;
662
                        residual = info->scsi.SCp.buffer->length;
663
                } else {
664
                        ptr = NULL;
665
                        residual = 0;
666
                }
667
        }
668
 
669
        info->scsi.SCp.ptr = ptr;
670
        info->scsi.SCp.this_residual = residual;
671
}
672
 
673
/* Function: void fas216_starttransfer(FAS216_Info *info,
674
 *                                     fasdmadir_t direction)
675
 * Purpose : Start a DMA/PIO transfer off of/on to card
676
 * Params  : info      - interface from which device disconnected from
677
 *           direction - transfer direction (DMA_OUT/DMA_IN)
678
 */
679
static void
680
fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction, int flush_fifo)
681
{
682
        fasdmatype_t dmatype;
683
 
684
        fas216_checkmagic(info, "fas216_starttransfer");
685
 
686
        info->scsi.phase = (direction == DMA_OUT) ?
687
                                PHASE_DATAOUT : PHASE_DATAIN;
688
 
689
        if (info->dma.transfer_type != fasdma_none &&
690
            info->dma.transfer_type != fasdma_pio) {
691
                unsigned long total, residual;
692
 
693
                if (info->dma.transfer_type == fasdma_real_all)
694
                        total = info->SCpnt->request_bufflen;
695
                else
696
                        total = info->scsi.SCp.this_residual;
697
 
698
                residual = (inb(REG_CFIS(info)) & CFIS_CF) +
699
                            inb(REG_CTCL(info)) +
700
                            (inb(REG_CTCM(info)) << 8) +
701
                            (inb(REG_CTCH(info)) << 16);
702
                fas216_updateptrs(info, total - residual);
703
        }
704
        info->dma.transfer_type = fasdma_none;
705
 
706
        if (!info->scsi.SCp.ptr) {
707
                printk("scsi%d.%c: null buffer passed to "
708
                        "fas216_starttransfer\n", info->host->host_no,
709
                        fas216_target(info));
710
                return;
711
        }
712
 
713
        /* flush FIFO */
714
        if (flush_fifo)
715
                outb(CMD_FLUSHFIFO, REG_CMD(info));
716
 
717
        /*
718
         * Default to PIO mode or DMA mode if we have a synchronous
719
         * transfer agreement.
720
         */
721
        if (info->device[info->SCpnt->target].sof && info->dma.setup)
722
                dmatype = fasdma_real_all;
723
        else
724
                dmatype = fasdma_pio;
725
 
726
        if (info->dma.setup)
727
                dmatype = info->dma.setup(info->host, &info->scsi.SCp,
728
                                          direction, dmatype);
729
        info->dma.transfer_type = dmatype;
730
 
731
        switch (dmatype) {
732
        case fasdma_pio:
733
                outb(0, REG_SOF(info));
734
                outb(info->scsi.async_stp, REG_STP(info));
735
                outb(info->scsi.SCp.this_residual, REG_STCL(info));
736
                outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info));
737
                outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info));
738
                outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info));
739
                outb(CMD_TRANSFERINFO, REG_CMD(info));
740
                fas216_pio(info, direction);
741
                break;
742
 
743
        case fasdma_pseudo:
744
                outb(info->scsi.SCp.this_residual, REG_STCL(info));
745
                outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info));
746
                outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info));
747
                outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info));
748
                info->dma.pseudo(info->host, &info->scsi.SCp,
749
                                 direction, info->SCpnt->transfersize);
750
                break;
751
 
752
        case fasdma_real_block:
753
                outb(info->scsi.SCp.this_residual, REG_STCL(info));
754
                outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info));
755
                outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info));
756
                outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info));
757
                break;
758
 
759
        case fasdma_real_all:
760
                outb(info->SCpnt->request_bufflen, REG_STCL(info));
761
                outb(info->SCpnt->request_bufflen >> 8, REG_STCM(info));
762
                outb(info->SCpnt->request_bufflen >> 16, REG_STCH(info));
763
                outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info));
764
                break;
765
 
766
        default:
767
                printk(KERN_ERR "scsi%d.%d: invalid FAS216 DMA type\n",
768
                       info->host->host_no, fas216_target(info));
769
                break;
770
        }
771
}
772
 
773
/* Function: void fas216_stoptransfer(FAS216_Info *info)
774
 * Purpose : Stop a DMA transfer onto / off of the card
775
 * Params  : info      - interface from which device disconnected from
776
 */
777
static void
778
fas216_stoptransfer(FAS216_Info *info)
779
{
780
        fas216_checkmagic(info, "fas216_stoptransfer");
781
 
782
        if (info->dma.transfer_type != fasdma_none &&
783
            info->dma.transfer_type != fasdma_pio) {
784
                unsigned long total, residual;
785
 
786
                if ((info->dma.transfer_type == fasdma_real_all ||
787
                     info->dma.transfer_type == fasdma_real_block) &&
788
                    info->dma.stop)
789
                        info->dma.stop(info->host, &info->scsi.SCp);
790
 
791
                if (info->dma.transfer_type == fasdma_real_all)
792
                        total = info->SCpnt->request_bufflen;
793
                else
794
                        total = info->scsi.SCp.this_residual;
795
 
796
                residual = (inb(REG_CFIS(info)) & CFIS_CF) +
797
                            inb(REG_CTCL(info)) +
798
                            (inb(REG_CTCM(info)) << 8) +
799
                            (inb(REG_CTCH(info)) << 16);
800
if (residual > total) {
801
        printk("stopxfer: total=%ld, residual=%ld\n", total, residual);
802
        fas216_dumpstate(info);
803
        fas216_dumpinfo(info);
804
        residual = total;
805
}
806
                fas216_updateptrs(info, total - residual);
807
                info->dma.transfer_type = fasdma_none;
808
        }
809
        if (info->scsi.phase == PHASE_DATAOUT)
810
                outb(CMD_FLUSHFIFO, REG_CMD(info));
811
}
812
 
813
/* Function: void fas216_disconnected_intr(FAS216_Info *info)
814
 * Purpose : handle device disconnection
815
 * Params  : info - interface from which device disconnected from
816
 */
817
static void
818
fas216_disconnect_intr(FAS216_Info *info)
819
{
820
        fas216_checkmagic(info, "fas216_disconnected_intr");
821
 
822
#ifdef DEBUG_CONNECT
823
        printk("scsi%d.%c: disconnect phase=%02X\n", info->host->host_no,
824
                fas216_target(info), info->scsi.phase);
825
#endif
826
        msgqueue_flush(&info->scsi.msgs);
827
 
828
        switch (info->scsi.phase) {
829
        case PHASE_SELECTION:                   /* while selecting - no target          */
830
        case PHASE_SELSTEPS:
831
                fas216_done(info, DID_NO_CONNECT);
832
                break;
833
 
834
        case PHASE_MSGIN_DISCONNECT:                    /* message in - disconnecting           */
835
                outb(CMD_ENABLESEL, REG_CMD(info));
836
                info->scsi.disconnectable = 1;
837
                info->scsi.reconnected.tag = 0;
838
                info->scsi.phase = PHASE_IDLE;
839
                info->stats.disconnects += 1;
840
                break;
841
 
842
        case PHASE_DONE:                        /* at end of command - complete         */
843
                fas216_done(info, DID_OK);
844
                break;
845
 
846
        case PHASE_MSGOUT:                      /* message out - possible ABORT message */
847
                if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) {
848
                        info->scsi.aborting = 0;
849
                        fas216_done(info, DID_ABORT);
850
                        break;
851
                }
852
 
853
        default:                                /* huh?                                 */
854
                printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %s\n",
855
                        info->host->host_no, fas216_target(info), fas216_drv_phase(info));
856
                print_debug_list();
857
                fas216_stoptransfer(info);
858
                fas216_done(info, DID_ERROR);
859
                break;
860
        }
861
}
862
 
863
/* Function: void fas216_reselected_intr(FAS216_Info *info)
864
 * Purpose : Start reconnection of a device
865
 * Params  : info - interface which was reselected
866
 */
867
static void
868
fas216_reselected_intr(FAS216_Info *info)
869
{
870
        unsigned char target, identify_msg, ok;
871
 
872
        fas216_checkmagic(info, "fas216_reselected_intr");
873
 
874
        if ((info->scsi.phase == PHASE_SELECTION ||
875
             info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) {
876
                Scsi_Cmnd *SCpnt = info->SCpnt;
877
 
878
                info->origSCpnt = SCpnt;
879
                info->SCpnt = NULL;
880
 
881
                if (info->device[SCpnt->target].wide_state == neg_inprogress)
882
                        info->device[SCpnt->target].wide_state = neg_wait;
883
                if (info->device[SCpnt->target].sync_state == neg_inprogress)
884
                        info->device[SCpnt->target].sync_state = neg_wait;
885
        }
886
 
887
#ifdef DEBUG_CONNECT
888
        printk("scsi%d.%c: reconnect phase=%02X\n", info->host->host_no,
889
                fas216_target(info), info->scsi.phase);
890
#endif
891
 
892
        if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) {
893
                printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n",
894
                        info->host->host_no);
895
                outb(CMD_SETATN, REG_CMD(info));
896
                outb(CMD_MSGACCEPTED, REG_CMD(info));
897
                msgqueue_flush(&info->scsi.msgs);
898
                msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
899
                info->scsi.phase = PHASE_MSGOUT_EXPECT;
900
                return;
901
        }
902
 
903
        target = inb(REG_FF(info));
904
        identify_msg = inb(REG_FF(info));
905
 
906
        ok = 1;
907
        if (!(target & (1 << info->host->this_id))) {
908
                printk(KERN_ERR "scsi%d.H: invalid host id on reselect\n", info->host->host_no);
909
                ok = 0;
910
        }
911
 
912
        if (!(identify_msg & 0x80)) {
913
                printk(KERN_ERR "scsi%d.H: no IDENTIFY message on reselect, got msg %02X\n",
914
                        info->host->host_no, identify_msg);
915
                ok = 0;
916
        }
917
 
918
        if (!ok) {
919
                /*
920
                 * Something went wrong - send an initiator error to
921
                 * the target.
922
                 */
923
                outb(CMD_SETATN, REG_CMD(info));
924
                outb(CMD_MSGACCEPTED, REG_CMD(info));
925
                msgqueue_flush(&info->scsi.msgs);
926
                msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
927
                info->scsi.phase = PHASE_MSGOUT_EXPECT;
928
                return;
929
        }
930
 
931
        target &= ~(1 << info->host->this_id);
932
        switch (target) {
933
        case   1:  target = 0; break;
934
        case   2:  target = 1; break;
935
        case   4:  target = 2; break;
936
        case   8:  target = 3; break;
937
        case  16:  target = 4; break;
938
        case  32:  target = 5; break;
939
        case  64:  target = 6; break;
940
        case 128:  target = 7; break;
941
        default:   target = info->host->this_id; break;
942
        }
943
 
944
        identify_msg &= 7;
945
        info->scsi.reconnected.target = target;
946
        info->scsi.reconnected.lun    = identify_msg;
947
        info->scsi.reconnected.tag    = 0;
948
 
949
        ok = 0;
950
        if (info->scsi.disconnectable && info->SCpnt &&
951
            info->SCpnt->target == target && info->SCpnt->lun == identify_msg)
952
                ok = 1;
953
 
954
        if (!ok && queue_probetgtlun(&info->queues.disconnected, target, identify_msg))
955
                ok = 1;
956
 
957
        msgqueue_flush(&info->scsi.msgs);
958
        if (ok) {
959
                info->scsi.phase = PHASE_RECONNECTED;
960
                outb(target, REG_SDID(info));
961
        } else {
962
                /*
963
                 * Our command structure not found - abort the
964
                 * command on the target.  Since we have no
965
                 * record of this command, we can't send
966
                 * an INITIATOR DETECTED ERROR message.
967
                 */
968
                outb(CMD_SETATN, REG_CMD(info));
969
                msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
970
                info->scsi.phase = PHASE_MSGOUT_EXPECT;
971
        }
972
        outb(CMD_MSGACCEPTED, REG_CMD(info));
973
}
974
 
975
/* Function: void fas216_finish_reconnect(FAS216_Info *info)
976
 * Purpose : finish reconnection sequence for device
977
 * Params  : info - interface which caused function done interrupt
978
 */
979
static void
980
fas216_finish_reconnect(FAS216_Info *info)
981
{
982
        fas216_checkmagic(info, "fas216_reconnect");
983
 
984
#ifdef DEBUG_CONNECT
985
        printk("Connected: %1X %1X %02X, reconnected: %1X %1X %02X\n",
986
                info->SCpnt->target, info->SCpnt->lun, info->SCpnt->tag,
987
                info->scsi.reconnected.target, info->scsi.reconnected.lun,
988
                info->scsi.reconnected.tag);
989
#endif
990
 
991
        if (info->scsi.disconnectable && info->SCpnt) {
992
                info->scsi.disconnectable = 0;
993
                if (info->SCpnt->target == info->scsi.reconnected.target &&
994
                    info->SCpnt->lun    == info->scsi.reconnected.lun &&
995
                    info->SCpnt->tag    == info->scsi.reconnected.tag) {
996
#ifdef DEBUG_CONNECT
997
                        printk("scsi%d.%c: reconnected",
998
                                info->host->host_no, fas216_target(info));
999
#endif
1000
                } else {
1001
                        queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);
1002
#ifdef DEBUG_CONNECT
1003
                        printk("scsi%d.%c: had to move command to disconnected queue\n",
1004
                                info->host->host_no, fas216_target(info));
1005
#endif
1006
                        info->SCpnt = NULL;
1007
                }
1008
        }
1009
        if (!info->SCpnt) {
1010
                info->SCpnt = queue_remove_tgtluntag(&info->queues.disconnected,
1011
                                        info->scsi.reconnected.target,
1012
                                        info->scsi.reconnected.lun,
1013
                                        info->scsi.reconnected.tag);
1014
#ifdef DEBUG_CONNECT
1015
                printk("scsi%d.%c: had to get command",
1016
                        info->host->host_no, fas216_target(info));
1017
#endif
1018
        }
1019
        if (!info->SCpnt) {
1020
                outb(CMD_SETATN, REG_CMD(info));
1021
                msgqueue_flush(&info->scsi.msgs);
1022
#if 0
1023
                if (info->scsi.reconnected.tag)
1024
                        msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, info->scsi.reconnected.tag);
1025
                else
1026
#endif
1027
                        msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
1028
                info->scsi.phase = PHASE_MSGOUT_EXPECT;
1029
                info->scsi.aborting = 1;
1030
        } else {
1031
                /*
1032
                 * Restore data pointer from SAVED data pointer
1033
                 */
1034
                info->scsi.SCp = info->SCpnt->SCp;
1035
#ifdef DEBUG_CONNECT
1036
                printk(", data pointers: [%p, %X]",
1037
                        info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
1038
#endif
1039
        }
1040
#ifdef DEBUG_CONNECT
1041
        printk("\n");
1042
#endif
1043
}
1044
 
1045
static unsigned char fas216_get_msg_byte(FAS216_Info *info)
1046
{
1047
        int tout;
1048
 
1049
        outb(CMD_MSGACCEPTED, REG_CMD(info));
1050
        for (tout = 1000000; tout; tout --)
1051
                if (inb(REG_STAT(info)) & STAT_INT)
1052
                        break;
1053
 
1054
        inb(REG_INST(info));
1055
 
1056
        outb(CMD_TRANSFERINFO, REG_CMD(info));
1057
 
1058
        for (tout = 1000000; tout; tout --)
1059
                if (inb(REG_STAT(info)) & STAT_INT)
1060
                        break;
1061
 
1062
        inb(REG_INST(info));
1063
 
1064
        return inb(REG_FF(info));
1065
}
1066
 
1067
/* Function: void fas216_message(FAS216_Info *info)
1068
 * Purpose : handle a function done interrupt from FAS216 chip
1069
 * Params  : info - interface which caused function done interrupt
1070
 */
1071
static void fas216_message(FAS216_Info *info)
1072
{
1073
        unsigned char message[16];
1074
        unsigned int msglen = 1;
1075
 
1076
        fas216_checkmagic(info, "fas216_message");
1077
 
1078
        message[0] = inb(REG_FF(info));
1079
 
1080
        if (message[0] == EXTENDED_MESSAGE) {
1081
                message[1] = fas216_get_msg_byte(info);
1082
 
1083
                for (msglen = 2; msglen < message[1] + 2; msglen++)
1084
                        message[msglen] = fas216_get_msg_byte(info);
1085
        }
1086
 
1087
#ifdef DEBUG_MESSAGES
1088
        {
1089
                int i;
1090
 
1091
                printk("scsi%d.%c: message in: ",
1092
                        info->host->host_no, fas216_target(info));
1093
                for (i = 0; i < msglen; i++)
1094
                        printk("%02X ", message[i]);
1095
                printk("\n");
1096
        }
1097
#endif
1098
 
1099
        if (info->scsi.phase == PHASE_RECONNECTED) {
1100
                if (message[0] == SIMPLE_QUEUE_TAG)
1101
                        info->scsi.reconnected.tag = message[1];
1102
                fas216_finish_reconnect(info);
1103
                info->scsi.phase = PHASE_MSGIN;
1104
        }
1105
 
1106
        switch (message[0]) {
1107
        case COMMAND_COMPLETE:
1108
                printk(KERN_ERR "scsi%d.%c: command complete with no "
1109
                        "status in MESSAGE_IN?\n",
1110
                        info->host->host_no, fas216_target(info));
1111
                break;
1112
 
1113
        case SAVE_POINTERS:
1114
                /*
1115
                 * Save current data pointer to SAVED data pointer
1116
                 * SCSI II standard says that we must not acknowledge
1117
                 * this until we have really saved pointers.
1118
                 * NOTE: we DO NOT save the command nor status pointers
1119
                 * as required by the SCSI II standard.  These always
1120
                 * point to the start of their respective areas.
1121
                 */
1122
                info->SCpnt->SCp = info->scsi.SCp;
1123
                info->SCpnt->SCp.sent_command = 0;
1124
#if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT)
1125
                printk("scsi%d.%c: save data pointers: [%p, %X]\n",
1126
                        info->host->host_no, fas216_target(info),
1127
                        info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
1128
#endif
1129
                break;
1130
 
1131
        case RESTORE_POINTERS:
1132
                /*
1133
                 * Restore current data pointer from SAVED data pointer
1134
                 */
1135
                info->scsi.SCp = info->SCpnt->SCp;
1136
#if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT)
1137
                printk("scsi%d.%c: restore data pointers: [%p, %X]\n",
1138
                        info->host->host_no, fas216_target(info),
1139
                        info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
1140
#endif
1141
                break;
1142
 
1143
        case DISCONNECT:
1144
                info->scsi.phase = PHASE_MSGIN_DISCONNECT;
1145
                break;
1146
 
1147
        case MESSAGE_REJECT:
1148
printk("scsi%d.%c: message reject at %02X (%X)\n", info->host->host_no, fas216_target(info), info->scsi.msgin_fifo,
1149
        fas216_get_last_msg(info, info->scsi.msgin_fifo));
1150
                switch(fas216_get_last_msg(info, info->scsi.msgin_fifo)) {
1151
                case EXTENDED_MESSAGE | EXTENDED_SDTR << 8:
1152
                        fas216_handlesync(info, message);
1153
                        break;
1154
 
1155
                case EXTENDED_MESSAGE | EXTENDED_WDTR << 8:
1156
                        fas216_handlewide(info, message);
1157
                        break;
1158
 
1159
                default:
1160
                        printk("scsi%d.%c: reject, last message %04X\n",
1161
                                info->host->host_no, fas216_target(info),
1162
                                fas216_get_last_msg(info, info->scsi.msgin_fifo));
1163
                }
1164
                break;
1165
 
1166
        case NOP:
1167
                break;
1168
 
1169
        case SIMPLE_QUEUE_TAG:
1170
                /* handled above */
1171
                printk("scsi%d.%c: reconnect queue tag %02X\n",
1172
                        info->host->host_no, fas216_target(info),
1173
                        message[1]);
1174
                break;
1175
 
1176
        case EXTENDED_MESSAGE:
1177
                switch (message[2]) {
1178
                case EXTENDED_SDTR:     /* Sync transfer negociation request/reply */
1179
                        fas216_handlesync(info, message);
1180
                        break;
1181
 
1182
                case EXTENDED_WDTR:     /* Wide transfer negociation request/reply */
1183
                        fas216_handlewide(info, message);
1184
                        break;
1185
 
1186
                default:
1187
                        printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n",
1188
                                info->host->host_no, fas216_target(info),
1189
                                message[2]);
1190
                        goto reject_message;
1191
                }
1192
                break;
1193
 
1194
        default:
1195
                printk("scsi%d.%c: unrecognised message %02X, rejecting\n",
1196
                        info->host->host_no, fas216_target(info),
1197
                        message[0]);
1198
                goto reject_message;
1199
        }
1200
        outb(CMD_MSGACCEPTED, REG_CMD(info));
1201
        return;
1202
 
1203
reject_message:
1204
        outb(CMD_SETATN, REG_CMD(info));
1205
        outb(CMD_MSGACCEPTED, REG_CMD(info));
1206
        msgqueue_flush(&info->scsi.msgs);
1207
        msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
1208
        info->scsi.phase = PHASE_MSGOUT_EXPECT;
1209
}
1210
 
1211
/* Function: void fas216_send_command(FAS216_Info *info)
1212
 * Purpose : send a command to a target after all message bytes have been sent
1213
 * Params  : info - interface which caused bus service
1214
 */
1215
static void fas216_send_command(FAS216_Info *info)
1216
{
1217
        int i;
1218
 
1219
        fas216_checkmagic(info, "fas216_send_command");
1220
 
1221
        outb(CMD_NOP|CMD_WITHDMA, REG_CMD(info));
1222
        outb(CMD_FLUSHFIFO, REG_CMD(info));
1223
 
1224
        /* load command */
1225
        for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++)
1226
                outb(info->SCpnt->cmnd[i], REG_FF(info));
1227
 
1228
        outb(CMD_TRANSFERINFO, REG_CMD(info));
1229
 
1230
        info->scsi.phase = PHASE_COMMAND;
1231
}
1232
 
1233
/* Function: void fas216_send_messageout(FAS216_Info *info)
1234
 * Purpose : handle bus service to send a message
1235
 * Params  : info - interface which caused bus service
1236
 * Note    : We do not allow the device to change the data direction!
1237
 */
1238
static void fas216_send_messageout(FAS216_Info *info, int start)
1239
{
1240
        unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);
1241
 
1242
        fas216_checkmagic(info, "fas216_send_messageout");
1243
 
1244
        outb(CMD_FLUSHFIFO, REG_CMD(info));
1245
 
1246
        if (tot_msglen) {
1247
                struct message *msg;
1248
                int msgnr = 0;
1249
 
1250
                while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
1251
                        int i;
1252
 
1253
                        for (i = start; i < msg->length; i++)
1254
                                outb(msg->msg[i], REG_FF(info));
1255
 
1256
                        msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF);
1257
                        start = 0;
1258
                }
1259
        } else
1260
                outb(NOP, REG_FF(info));
1261
 
1262
        outb(CMD_TRANSFERINFO, REG_CMD(info));
1263
 
1264
        info->scsi.phase = PHASE_MSGOUT;
1265
}
1266
 
1267
/* Function: void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
1268
 * Purpose : handle a bus service interrupt from FAS216 chip
1269
 * Params  : info - interface which caused bus service interrupt
1270
 *           stat - Status register contents
1271
 *           ssr  - SCSI Status register contents
1272
 */
1273
static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
1274
{
1275
        fas216_checkmagic(info, "fas216_busservice_intr");
1276
 
1277
#ifdef DEBUG_BUSSERVICE
1278
        printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n",
1279
                info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase);
1280
#endif
1281
        switch (ssr & IS_BITS) {
1282
        case IS_MSGBYTESENT:            /* select with ATN and stop steps completed     */
1283
        case IS_COMPLETE:                       /* last action completed                */
1284
                outb(CMD_NOP, REG_CMD(info));
1285
 
1286
#define STATE(st,ph) ((ph) << 3 | (st))
1287
                /* This table describes the legal SCSI state transitions,
1288
                 * as described by the SCSI II spec.
1289
                 */
1290
                switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) {
1291
                                                        /* Reselmsgin   -> Data In      */
1292
                case STATE(STAT_DATAIN, PHASE_RECONNECTED):
1293
                        fas216_finish_reconnect(info);
1294
                case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In      */
1295
                case STATE(STAT_DATAIN, PHASE_DATAIN):  /* Data In      -> Data In      */
1296
                case STATE(STAT_DATAIN, PHASE_MSGOUT):  /* Message Out  -> Data In      */
1297
                case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command      -> Data In      */
1298
                case STATE(STAT_DATAIN, PHASE_MSGIN):   /* Message In   -> Data In      */
1299
                        fas216_starttransfer(info, DMA_IN, 0);
1300
                        return;
1301
 
1302
                case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out     -> Data Out     */
1303
                        fas216_starttransfer(info, DMA_OUT, 0);
1304
                        return;
1305
 
1306
                                                        /* Reselmsgin   -> Data Out     */
1307
                case STATE(STAT_DATAOUT, PHASE_RECONNECTED):
1308
                        fas216_finish_reconnect(info);
1309
                case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out     */
1310
                case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out  -> Data Out     */
1311
                case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command      -> Data Out     */
1312
                case STATE(STAT_DATAOUT, PHASE_MSGIN):  /* Message In   -> Data Out     */
1313
                        fas216_starttransfer(info, DMA_OUT, 1);
1314
                        return;
1315
 
1316
                                                        /* Reselmsgin   -> Status       */
1317
                case STATE(STAT_STATUS, PHASE_RECONNECTED):
1318
                        fas216_finish_reconnect(info);
1319
                        goto status;
1320
                case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out     -> Status       */
1321
                case STATE(STAT_STATUS, PHASE_DATAIN):  /* Data In      -> Status       */
1322
                        fas216_stoptransfer(info);
1323
                case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status       */
1324
                case STATE(STAT_STATUS, PHASE_MSGOUT):  /* Message Out  -> Status       */
1325
                case STATE(STAT_STATUS, PHASE_COMMAND): /* Command      -> Status       */
1326
                case STATE(STAT_STATUS, PHASE_MSGIN):   /* Message In   -> Status       */
1327
                status:
1328
                        outb(CMD_INITCMDCOMPLETE, REG_CMD(info));
1329
                        info->scsi.phase = PHASE_STATUS;
1330
                        return;
1331
 
1332
                case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */
1333
                case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */
1334
                        fas216_stoptransfer(info);
1335
                case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */
1336
                case STATE(STAT_MESGIN, PHASE_MSGOUT):  /* Message Out  -> Message In   */
1337
                        info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
1338
                        outb(CMD_TRANSFERINFO, REG_CMD(info));
1339
                        info->scsi.phase = PHASE_MSGIN;
1340
                        return;
1341
 
1342
                                                        /* Reselmsgin   -> Message In   */
1343
                case STATE(STAT_MESGIN, PHASE_RECONNECTED):
1344
                case STATE(STAT_MESGIN, PHASE_MSGIN):
1345
                        info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
1346
                        outb(CMD_TRANSFERINFO, REG_CMD(info));
1347
                        return;
1348
 
1349
                                                        /* Reselmsgin   -> Command      */
1350
                case STATE(STAT_COMMAND, PHASE_RECONNECTED):
1351
                        fas216_finish_reconnect(info);
1352
                case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out  -> Command      */
1353
                case STATE(STAT_COMMAND, PHASE_MSGIN):  /* Message In   -> Command      */
1354
                        fas216_send_command(info);
1355
                        info->scsi.phase = PHASE_COMMAND;
1356
                        return;
1357
                                                        /* Selection    -> Message Out  */
1358
                case STATE(STAT_MESGOUT, PHASE_SELECTION):
1359
                        fas216_send_messageout(info, 1);
1360
                        return;
1361
                                                        /* Any          -> Message Out  */
1362
                case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):
1363
                        fas216_send_messageout(info, 0);
1364
                        return;
1365
 
1366
                /* Error recovery rules.
1367
                 *   These either attempt to abort or retry the operation.
1368
                 * TODO: we need more of these
1369
                 */
1370
                case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command      -> Command      */
1371
                        /* error - we've sent out all the command bytes
1372
                         * we have.
1373
                         * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS
1374
                         * to include the command bytes sent for this to work
1375
                         * correctly.
1376
                         */
1377
                        printk(KERN_ERR "scsi%d.%c: "
1378
                                "target trying to receive more command bytes\n",
1379
                                info->host->host_no, fas216_target(info));
1380
                        outb(CMD_SETATN, REG_CMD(info));
1381
                        outb(15, REG_STCL(info));
1382
                        outb(0, REG_STCM(info));
1383
                        outb(0, REG_STCH(info));
1384
                        outb(CMD_PADBYTES | CMD_WITHDMA, REG_CMD(info));
1385
                        msgqueue_flush(&info->scsi.msgs);
1386
                        msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
1387
                        info->scsi.phase = PHASE_MSGOUT_EXPECT;
1388
                        return;
1389
 
1390
                                                        /* Selection    -> Message Out  */
1391
                case STATE(STAT_MESGOUT, PHASE_SELSTEPS):
1392
                case STATE(STAT_MESGOUT, PHASE_MSGOUT): /* Message Out  -> Message Out  */
1393
                        /* If we get another message out phase, this
1394
                         * usually means some parity error occurred.
1395
                         * Resend complete set of messages.  If we have
1396
                         * more than 1 byte to send, we need to assert
1397
                         * ATN again.
1398
                         */
1399
                        if (msgqueue_msglength(&info->scsi.msgs) > 1)
1400
                                outb(CMD_SETATN, REG_CMD(info));
1401
 
1402
                        fas216_send_messageout(info, 0);
1403
                        return;
1404
                }
1405
 
1406
                if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) {
1407
                        printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n",
1408
                                info->host->host_no, fas216_target(info),
1409
                                fas216_bus_phase(stat));
1410
                        msgqueue_flush(&info->scsi.msgs);
1411
                        outb(CMD_SETATN, REG_CMD(info));
1412
                        msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
1413
                        info->scsi.phase = PHASE_MSGOUT_EXPECT;
1414
                        info->scsi.aborting = 1;
1415
                        outb(CMD_TRANSFERINFO, REG_CMD(info));
1416
                        return;
1417
                }
1418
                printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n",
1419
                        info->host->host_no, fas216_target(info),
1420
                        fas216_bus_phase(stat),
1421
                        fas216_drv_phase(info));
1422
                return;
1423
 
1424
        default:
1425
                printk("scsi%d.%c: bus service at step %d?\n",
1426
                        info->host->host_no, fas216_target(info),
1427
                        ssr & IS_BITS);
1428
        }
1429
}
1430
 
1431
/* Function: void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
1432
 * Purpose : handle a function done interrupt from FAS216 chip
1433
 * Params  : info - interface which caused function done interrupt
1434
 *           stat - Status register contents
1435
 *           ssr  - SCSI Status register contents
1436
 */
1437
static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
1438
{
1439
        int status, message;
1440
 
1441
        fas216_checkmagic(info, "fas216_funcdone_intr");
1442
 
1443
#ifdef DEBUG_FUNCTIONDONE
1444
        printk("scsi%d.%c: function done: stat=%X ssr=%X phase=%02X\n",
1445
                info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase);
1446
#endif
1447
        switch (info->scsi.phase) {
1448
        case PHASE_STATUS:                      /* status phase - read status and msg   */
1449
                status = inb(REG_FF(info));
1450
                message = inb(REG_FF(info));
1451
                info->scsi.SCp.Message = message;
1452
                info->scsi.SCp.Status = status;
1453
                info->scsi.phase = PHASE_DONE;
1454
                outb(CMD_MSGACCEPTED, REG_CMD(info));
1455
                break;
1456
 
1457
        case PHASE_IDLE:                        /* reselected?                          */
1458
        case PHASE_MSGIN:                       /* message in phase                     */
1459
        case PHASE_RECONNECTED:                 /* reconnected command                  */
1460
                if ((stat & STAT_BUSMASK) == STAT_MESGIN) {
1461
                        info->scsi.msgin_fifo = inb(REG_CFIS(info)) & CFIS_CF;
1462
                        fas216_message(info);
1463
                        break;
1464
                }
1465
 
1466
        default:
1467
                printk("scsi%d.%c: internal phase %s for function done?"
1468
                        "  What do I do with this?\n",
1469
                        info->host->host_no, fas216_target(info),
1470
                        fas216_drv_phase(info));
1471
        }
1472
}
1473
 
1474
/* Function: void fas216_intr(struct Scsi_Host *instance)
1475
 * Purpose : handle interrupts from the interface to progress a command
1476
 * Params  : instance - interface to service
1477
 */
1478
void fas216_intr(struct Scsi_Host *instance)
1479
{
1480
        FAS216_Info *info = (FAS216_Info *)instance->hostdata;
1481
        unsigned char isr, ssr, stat;
1482
 
1483
        fas216_checkmagic(info, "fas216_intr");
1484
 
1485
        stat = inb(REG_STAT(info));
1486
        ssr = inb(REG_IS(info));
1487
        isr = inb(REG_INST(info));
1488
 
1489
        add_debug_list(stat, ssr, isr, info->scsi.phase);
1490
 
1491
        if (stat & STAT_INT) {
1492
                if (isr & INST_BUSRESET)
1493
                        printk("scsi%d.H: bus reset detected\n", instance->host_no);
1494
                else if (isr & INST_ILLEGALCMD) {
1495
                        printk(KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no);
1496
                        fas216_dumpstate(info);
1497
                } else if (isr & INST_DISCONNECT)
1498
                        fas216_disconnect_intr(info);
1499
                else if (isr & INST_RESELECTED)         /* reselected                   */
1500
                        fas216_reselected_intr(info);
1501
                else if (isr & INST_BUSSERVICE)         /* bus service request          */
1502
                        fas216_busservice_intr(info, stat, ssr);
1503
                else if (isr & INST_FUNCDONE)           /* function done                */
1504
                        fas216_funcdone_intr(info, stat, ssr);
1505
                else
1506
                        printk("scsi%d.%c: unknown interrupt received:"
1507
                                " phase %s isr %02X ssr %02X stat %02X\n",
1508
                                instance->host_no, fas216_target(info),
1509
                                fas216_drv_phase(info), isr, ssr, stat);
1510
        }
1511
}
1512
 
1513
/* Function: void fas216_kick(FAS216_Info *info)
1514
 * Purpose : kick a command to the interface - interface should be idle
1515
 * Params  : info - our host interface to kick
1516
 * Notes   : Interrupts are always disabled!
1517
 */
1518
static void fas216_kick(FAS216_Info *info)
1519
{
1520
        Scsi_Cmnd *SCpnt;
1521
        int tot_msglen, from_queue = 0;
1522
 
1523
        fas216_checkmagic(info, "fas216_kick");
1524
 
1525
        if (info->origSCpnt) {
1526
                SCpnt = info->origSCpnt;
1527
                info->origSCpnt = NULL;
1528
        } else
1529
                SCpnt = NULL;
1530
 
1531
        /* retrieve next command */
1532
        if (!SCpnt) {
1533
                SCpnt = queue_remove_exclude(&info->queues.issue, info->busyluns);
1534
                from_queue = 1;
1535
        }
1536
 
1537
        if (!SCpnt) /* no command pending - just exit */
1538
                return;
1539
 
1540
        if (info->scsi.disconnectable && info->SCpnt) {
1541
                queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);
1542
                info->scsi.disconnectable = 0;
1543
                info->SCpnt = NULL;
1544
                printk("scsi%d.%c: moved command to disconnected queue\n",
1545
                        info->host->host_no, fas216_target(info));
1546
        }
1547
 
1548
        /*
1549
         * tagged queuing - allocate a new tag to this command
1550
         */
1551
        if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) {
1552
                SCpnt->device->current_tag += 1;
1553
                if (SCpnt->device->current_tag == 0)
1554
                    SCpnt->device->current_tag = 1;
1555
                SCpnt->tag = SCpnt->device->current_tag;
1556
        }
1557
 
1558
        /*
1559
         * claim host busy
1560
         */
1561
        info->scsi.phase = PHASE_SELECTION;
1562
        info->SCpnt = SCpnt;
1563
        info->scsi.SCp = SCpnt->SCp;
1564
        info->dma.transfer_type = fasdma_none;
1565
 
1566
#ifdef DEBUG_CONNECT
1567
        printk("scsi%d.%c: starting cmd %02X",
1568
                info->host->host_no, '0' + SCpnt->target,
1569
                SCpnt->cmnd[0]);
1570
#endif
1571
 
1572
        if (from_queue) {
1573
#ifdef SCSI2_TAG
1574
                if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE &&
1575
                    SCpnt->cmnd[0] != INQUIRY) {
1576
                    SCpnt->device->current_tag += 1;
1577
                        if (SCpnt->device->current_tag == 0)
1578
                            SCpnt->device->current_tag = 1;
1579
                                SCpnt->tag = SCpnt->device->current_tag;
1580
                } else
1581
#endif
1582
                        set_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
1583
 
1584
                info->stats.removes += 1;
1585
                switch (SCpnt->cmnd[0]) {
1586
                case WRITE_6:
1587
                case WRITE_10:
1588
                case WRITE_12:
1589
                        info->stats.writes += 1;
1590
                        break;
1591
                case READ_6:
1592
                case READ_10:
1593
                case READ_12:
1594
                        info->stats.reads += 1;
1595
                        break;
1596
                default:
1597
                        info->stats.miscs += 1;
1598
                        break;
1599
                }
1600
        }
1601
 
1602
        /* build outgoing message bytes */
1603
        msgqueue_flush(&info->scsi.msgs);
1604
 
1605
        if (info->device[SCpnt->target].disconnect_ok)
1606
                msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun));
1607
        else
1608
                msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(0, SCpnt->lun));
1609
 
1610
        /* add tag message if required */
1611
        if (SCpnt->tag)
1612
                msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);
1613
 
1614
#ifdef SCSI2_WIDE
1615
        if (info->device[SCpnt->target].wide_state == neg_wait) {
1616
                info->device[SCpnt->target].wide_state = neg_inprogress;
1617
                msgqueue_addmsg(&info->scsi.msgs, 4,
1618
                                EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
1619
                                info->ifcfg.wide_max_size);
1620
        }
1621
#ifdef SCSI2_SYNC
1622
        else
1623
#endif
1624
#endif
1625
#ifdef SCSI2_SYNC
1626
        if ((info->device[SCpnt->target].sync_state == neg_wait ||
1627
             info->device[SCpnt->target].sync_state == neg_complete) &&
1628
            (SCpnt->cmnd[0] == REQUEST_SENSE ||
1629
             SCpnt->cmnd[0] == INQUIRY)) {
1630
                info->device[SCpnt->target].sync_state = neg_inprogress;
1631
                msgqueue_addmsg(&info->scsi.msgs, 5,
1632
                                EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
1633
                                1000 / info->ifcfg.clockrate,
1634
                                info->ifcfg.sync_max_depth);
1635
        }
1636
#endif
1637
 
1638
        /* following what the ESP driver says */
1639
        outb(0, REG_STCL(info));
1640
        outb(0, REG_STCM(info));
1641
        outb(0, REG_STCH(info));
1642
        outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info));
1643
 
1644
        /* flush FIFO */
1645
        outb(CMD_FLUSHFIFO, REG_CMD(info));
1646
 
1647
        /* load bus-id and timeout */
1648
        outb(BUSID(SCpnt->target), REG_SDID(info));
1649
        outb(info->ifcfg.select_timeout, REG_STIM(info));
1650
 
1651
        /* synchronous transfers */
1652
        fas216_set_sync(info, SCpnt->target);
1653
 
1654
        tot_msglen = msgqueue_msglength(&info->scsi.msgs);
1655
 
1656
        if (tot_msglen == 1 || tot_msglen == 3) {
1657
                /*
1658
                 * We have an easy message length to send...
1659
                 */
1660
                struct message *msg;
1661
                int msgnr = 0, i;
1662
 
1663
                info->scsi.phase = PHASE_SELSTEPS;
1664
 
1665
                /* load message bytes */
1666
                while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
1667
                        for (i = 0; i < msg->length; i++)
1668
                                outb(msg->msg[i], REG_FF(info));
1669
                        msg->fifo = tot_msglen - (inb(REG_CFIS(info)) & CFIS_CF);
1670
                }
1671
 
1672
                /* load command */
1673
                for (i = 0; i < SCpnt->cmd_len; i++)
1674
                        outb(SCpnt->cmnd[i], REG_FF(info));
1675
 
1676
                if (tot_msglen == 1)
1677
                        outb(CMD_SELECTATN, REG_CMD(info));
1678
                else
1679
                        outb(CMD_SELECTATN3, REG_CMD(info));
1680
        } else {
1681
                /*
1682
                 * We have an unusual number of message bytes to send.
1683
                 *  Load first byte into fifo, and issue SELECT with ATN and
1684
                 *  stop steps.
1685
                 */
1686
                struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0);
1687
 
1688
                outb(msg->msg[0], REG_FF(info));
1689
                msg->fifo = 1;
1690
 
1691
                outb(CMD_SELECTATNSTOP, REG_CMD(info));
1692
        }
1693
 
1694
#ifdef DEBUG_CONNECT
1695
        printk(", data pointers [%p, %X]\n",
1696
                info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
1697
#endif
1698
        /* should now get either DISCONNECT or (FUNCTION DONE with BUS SERVICE) intr */
1699
}
1700
 
1701
/* Function: void fas216_done(FAS216_Info *info, unsigned int result)
1702
 * Purpose : complete processing for command
1703
 * Params  : info   - interface that completed
1704
 *           result - driver byte of result
1705
 */
1706
static void fas216_done(FAS216_Info *info, unsigned int result)
1707
{
1708
        Scsi_Cmnd *SCpnt;
1709
 
1710
        fas216_checkmagic(info, "fas216_done");
1711
 
1712
        SCpnt = info->SCpnt;
1713
 
1714
        if (info->scsi.aborting) {
1715
                printk("scsi%d.%c: uncaught abort - returning DID_ABORT\n",
1716
                        info->host->host_no, fas216_target(info));
1717
                result = DID_ABORT;
1718
                info->scsi.aborting = 0;
1719
        }
1720
 
1721
        info->stats.fins += 1;
1722
 
1723
        if (SCpnt) {
1724
                info->scsi.phase = PHASE_IDLE;
1725
                info->SCpnt = NULL;
1726
 
1727
                SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
1728
                                info->scsi.SCp.Status;
1729
 
1730
                /*
1731
                 * In theory, this should not happen, but just in case it does.
1732
                 */
1733
                if (info->scsi.SCp.ptr &&
1734
                    info->scsi.SCp.this_residual &&
1735
                    result == DID_OK) {
1736
                        switch (SCpnt->cmnd[0]) {
1737
                        case INQUIRY:
1738
                        case START_STOP:
1739
                        case READ_CAPACITY:
1740
                        case TEST_UNIT_READY:
1741
                        case MODE_SENSE:
1742
                                break;
1743
 
1744
                        default:
1745
                                switch (status_byte(SCpnt->result)) {
1746
                                case CHECK_CONDITION:
1747
                                case COMMAND_TERMINATED:
1748
                                case BUSY:
1749
                                case QUEUE_FULL:
1750
                                case RESERVATION_CONFLICT:
1751
                                        break;
1752
 
1753
                                default:
1754
                                        printk(KERN_ERR "scsi%d.H: incomplete data transfer "
1755
                                                "detected: res=%08X ptr=%p len=%X command=",
1756
                                                info->host->host_no, SCpnt->result,
1757
                                                info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
1758
                                        print_command(SCpnt->cmnd);
1759
                                }
1760
                        }
1761
                }
1762
#ifdef DEBUG_CONNECT
1763
                printk("scsi%d.%c: scsi command (%p) complete, result=%08X\n",
1764
                        info->host->host_no, fas216_target(info),
1765
                        SCpnt, SCpnt->result);
1766
#endif
1767
 
1768
                if (!SCpnt->scsi_done)
1769
                        panic("scsi%d.H: null scsi_done function in "
1770
                                "fas216_done", info->host->host_no);
1771
 
1772
                clear_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns);
1773
 
1774
                SCpnt->scsi_done(SCpnt);
1775
        } else
1776
                panic("scsi%d.H: null command in fas216_done", info->host->host_no);
1777
 
1778
        if (info->scsi.irq != NO_IRQ)
1779
                fas216_kick(info);
1780
}
1781
 
1782
/* Function: int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
1783
 * Purpose : queue a command for adapter to process.
1784
 * Params  : SCpnt - Command to queue
1785
 *           done  - done function to call once command is complete
1786
 * Returns : 0 - success, else error
1787
 */
1788
int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
1789
{
1790
        FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
1791
 
1792
        fas216_checkmagic(info, "fas216_queue_command");
1793
 
1794
#ifdef DEBUG_CONNECT
1795
        printk("scsi%d.%c: received queuable command (%p) %02X\n",
1796
                SCpnt->host->host_no, '0' + SCpnt->target,
1797
                SCpnt, SCpnt->cmnd[0]);
1798
#endif
1799
 
1800
        SCpnt->scsi_done = done;
1801
        SCpnt->host_scribble = NULL;
1802
        SCpnt->result = 0;
1803
        SCpnt->SCp.Message = 0;
1804
        SCpnt->SCp.Status = 0;
1805
 
1806
        if (SCpnt->use_sg) {
1807
                unsigned long len = 0;
1808
                int buf;
1809
 
1810
                SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
1811
                SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
1812
                SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address;
1813
                SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
1814
                /*
1815
                 * Calculate correct buffer length
1816
                 */
1817
                for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++)
1818
                        len += SCpnt->SCp.buffer[buf].length;
1819
                SCpnt->request_bufflen = len;
1820
        } else {
1821
                SCpnt->SCp.buffer = NULL;
1822
                SCpnt->SCp.buffers_residual = 0;
1823
                SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer;
1824
                SCpnt->SCp.this_residual = SCpnt->request_bufflen;
1825
        }
1826
 
1827
        info->stats.queues += 1;
1828
        SCpnt->tag = 0;
1829
 
1830
        if (info->scsi.irq != NO_IRQ) {
1831
                unsigned long flags;
1832
 
1833
                /* add command into execute queue and let it complete under
1834
                 * the drivers interrupts.
1835
                 */
1836
                if (!queue_add_cmd_ordered(&info->queues.issue, SCpnt)) {
1837
                        SCpnt->result = DID_ERROR << 16;
1838
                        done(SCpnt);
1839
                }
1840
                save_flags_cli(flags);
1841
                if (!info->SCpnt || info->scsi.disconnectable)
1842
                        fas216_kick(info);
1843
                restore_flags(flags);
1844
        } else {
1845
                /* no interrupts to rely on - we'll have to handle the
1846
                 * command ourselves.  For now, we give up.
1847
                 */
1848
                SCpnt->result = DID_ERROR << 16;
1849
                done(SCpnt);
1850
        }
1851
        return 0;
1852
}
1853
 
1854
/* Function: void fas216_internal_done(Scsi_Cmnd *SCpnt)
1855
 * Purpose : trigger restart of a waiting thread in fas216_command
1856
 * Params  : SCpnt - Command to wake
1857
 */
1858
static void fas216_internal_done(Scsi_Cmnd *SCpnt)
1859
{
1860
        FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
1861
 
1862
        fas216_checkmagic(info, "fas216_internal_done");
1863
 
1864
        info->internal_done = 1;
1865
}
1866
 
1867
/* Function: int fas216_command(Scsi_Cmnd *SCpnt)
1868
 * Purpose : queue a command for adapter to process.
1869
 * Params  : SCpnt - Command to queue
1870
 * Returns : scsi result code
1871
 */
1872
int fas216_command(Scsi_Cmnd *SCpnt)
1873
{
1874
        FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
1875
        unsigned long flags;
1876
 
1877
        fas216_checkmagic(info, "fas216_command");
1878
 
1879
        info->internal_done = 0;
1880
        fas216_queue_command(SCpnt, fas216_internal_done);
1881
 
1882
        /*
1883
         * This wastes time, since we can't return until the command is
1884
         * complete. We can't seep either since we may get re-entered!
1885
         * However, we must re-enable interrupts, or else we'll be
1886
         * waiting forever.
1887
         */
1888
        save_flags(flags);
1889
        sti();
1890
 
1891
        while (!info->internal_done)
1892
                barrier();
1893
 
1894
        restore_flags(flags);
1895
 
1896
        return SCpnt->result;
1897
}
1898
 
1899
/* Prototype: void fas216_reportstatus(Scsi_Cmnd **SCpntp1,
1900
 *                                     Scsi_Cmnd **SCpntp2, int result)
1901
 * Purpose  : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
1902
 * Params   : SCpntp1 - pointer to command to return
1903
 *            SCpntp2 - pointer to command to check
1904
 *            result  - result to pass back to mid-level done function
1905
 * Returns  : *SCpntp2 = NULL if *SCpntp1 is the same command
1906
 *            structure as *SCpntp2.
1907
 */
1908
static void fas216_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2,
1909
                                int result)
1910
{
1911
        Scsi_Cmnd *SCpnt = *SCpntp1;
1912
 
1913
        if (SCpnt) {
1914
                *SCpntp1 = NULL;
1915
 
1916
                SCpnt->result = result;
1917
                SCpnt->scsi_done(SCpnt);
1918
        }
1919
 
1920
        if (SCpnt == *SCpntp2)
1921
                *SCpntp2 = NULL;
1922
}
1923
 
1924
/* Function: int fas216_abort(Scsi_Cmnd *SCpnt)
1925
 * Purpose : abort a command if something horrible happens.
1926
 * Params  : SCpnt - Command that is believed to be causing a problem.
1927
 * Returns : one of SCSI_ABORT_ macros.
1928
 */
1929
int fas216_abort(Scsi_Cmnd *SCpnt)
1930
{
1931
        FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
1932
        int result = SCSI_ABORT_SNOOZE;
1933
 
1934
        fas216_checkmagic(info, "fas216_abort");
1935
 
1936
        info->stats.aborts += 1;
1937
 
1938
        print_debug_list();
1939
        fas216_dumpstate(info);
1940
        fas216_dumpinfo(info);
1941
        printk(KERN_WARNING "scsi%d: fas216_abort: ", info->host->host_no);
1942
 
1943
        do {
1944
                /* If command is waiting in the issue queue, then we can
1945
                 * simply remove the command and return abort status
1946
                 */
1947
                if (queue_removecmd(&info->queues.issue, SCpnt)) {
1948
                        SCpnt->result = DID_ABORT << 16;
1949
                        SCpnt->scsi_done(SCpnt);
1950
                        printk("command on issue queue");
1951
                        result = SCSI_ABORT_SUCCESS;
1952
                        break;
1953
                }
1954
 
1955
                /* If the command is on the disconencted queue, we need to
1956
                 * reconnect to the device
1957
                 */
1958
                if (queue_cmdonqueue(&info->queues.disconnected, SCpnt))
1959
                        printk("command on disconnected queue");
1960
 
1961
                /* If the command is connected, we need to flag that the
1962
                 * command needs to be aborted
1963
                 */
1964
                if (info->SCpnt == SCpnt)
1965
                        printk("command executing");
1966
 
1967
                /* If the command is pending for execution, then again
1968
                 * this is simple - we remove it and report abort status
1969
                 */
1970
                if (info->origSCpnt == SCpnt) {
1971
                        info->origSCpnt = NULL;
1972
                        SCpnt->result = DID_ABORT << 16;
1973
                        SCpnt->scsi_done(SCpnt);
1974
                        printk("command waiting for execution");
1975
                        result = SCSI_ABORT_SUCCESS;
1976
                        break;
1977
                }
1978
        } while (0);
1979
 
1980
        printk("\n");
1981
 
1982
        return result;
1983
}
1984
 
1985
/* Function: void fas216_reset_state(FAS216_Info *info)
1986
 * Purpose : Initialise driver internal state
1987
 * Params  : info - state to initialise
1988
 */
1989
static void fas216_reset_state(FAS216_Info *info)
1990
{
1991
        neg_t sync_state, wide_state;
1992
        int i;
1993
 
1994
        fas216_checkmagic(info, "fas216_reset_state");
1995
 
1996
        /*
1997
         * Clear out all stale info in our state structure
1998
         */
1999
        memset(info->busyluns, 0, sizeof(info->busyluns));
2000
        msgqueue_flush(&info->scsi.msgs);
2001
        info->scsi.reconnected.target = 0;
2002
        info->scsi.reconnected.lun = 0;
2003
        info->scsi.reconnected.tag = 0;
2004
        info->scsi.disconnectable = 0;
2005
        info->scsi.aborting = 0;
2006
        info->scsi.phase = PHASE_IDLE;
2007
        info->scsi.async_stp =
2008
                        fas216_syncperiod(info, info->ifcfg.asyncperiod);
2009
 
2010
        if (info->ifcfg.wide_max_size == 0)
2011
                wide_state = neg_invalid;
2012
        else
2013
#ifdef SCSI2_WIDE
2014
                wide_state = neg_wait;
2015
#else
2016
                wide_state = neg_invalid;
2017
#endif
2018
 
2019
        if (info->host->dma_channel == NO_DMA || !info->dma.setup)
2020
                sync_state = neg_invalid;
2021
        else
2022
#ifdef SCSI2_SYNC
2023
                sync_state = neg_wait;
2024
#else
2025
                sync_state = neg_invalid;
2026
#endif
2027
 
2028
        for (i = 0; i < 8; i++) {
2029
                info->device[i].disconnect_ok   = info->ifcfg.disconnect_ok;
2030
                info->device[i].sync_state      = sync_state;
2031
                info->device[i].wide_state      = wide_state;
2032
                info->device[i].period          = info->ifcfg.asyncperiod / 4;
2033
                info->device[i].stp             = info->scsi.async_stp;
2034
                info->device[i].sof             = 0;
2035
                info->device[i].wide_xfer       = 0;
2036
        }
2037
}
2038
 
2039
/* Function: void fas216_init_chip(FAS216_Info *info)
2040
 * Purpose : Initialise FAS216 state after reset
2041
 * Params  : info - state structure for interface
2042
 */
2043
static void fas216_init_chip(FAS216_Info *info)
2044
{
2045
        fas216_checkmagic(info, "fas216_init_chip");
2046
 
2047
        outb(fas216_clockrate(info->ifcfg.clockrate), REG_CLKF(info));
2048
        outb(info->scsi.cfg[0], REG_CNTL1(info));
2049
        outb(info->scsi.cfg[1], REG_CNTL2(info));
2050
        outb(info->scsi.cfg[2], REG_CNTL3(info));
2051
        outb(info->ifcfg.select_timeout, REG_STIM(info));
2052
        outb(0, REG_SOF(info));
2053
        outb(info->scsi.async_stp, REG_STP(info));
2054
        outb(info->scsi.cfg[0], REG_CNTL1(info));
2055
}
2056
 
2057
/* Function: int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
2058
 * Purpose : resets the adapter if something horrible happens.
2059
 * Params  : SCpnt - Command that is believed to be causing a problem.
2060
 *           reset_flags - flags indicating reset type that is believed
2061
 *           to be required.
2062
 * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET
2063
 *           macros.
2064
 */
2065
int fas216_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
2066
{
2067
        FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
2068
        Scsi_Cmnd *SCptr;
2069
        int result = 0;
2070
 
2071
        fas216_checkmagic(info, "fas216_reset");
2072
 
2073
        /*
2074
         * Validate that command is actually on one of our queues if we're doing
2075
         * an asynchronous reset
2076
         */
2077
        if (reset_flags & SCSI_RESET_ASYNCHRONOUS &&
2078
            SCpnt &&
2079
            info->SCpnt != SCpnt &&
2080
            info->origSCpnt != SCpnt &&
2081
            !queue_cmdonqueue(&info->queues.disconnected, SCpnt) &&
2082
            !queue_cmdonqueue(&info->queues.issue, SCpnt)) {
2083
                printk("scsi%d: fas216_reset: asynchronous reset for unknown command\n",
2084
                       info->host->host_no);
2085
                return SCSI_RESET_NOT_RUNNING;
2086
        }
2087
 
2088
        info->stats.resets += 1;
2089
 
2090
        print_debug_list();
2091
        printk(KERN_WARNING "scsi%d: fas216_reset: ", info->host->host_no);
2092
        if (SCpnt)
2093
                printk(" for target %d ", SCpnt->target);
2094
 
2095
        outb(info->scsi.cfg[3], REG_CNTL3(info));
2096
 
2097
        fas216_stoptransfer(info);
2098
 
2099
        switch (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) {
2100
        case SCSI_RESET_SUGGEST_BUS_RESET:
2101
                outb(CMD_RESETSCSI, REG_CMD(info));
2102
                outb(CMD_NOP, REG_CMD(info));
2103
                result |= SCSI_RESET_BUS_RESET;
2104
                break;
2105
 
2106
        case SCSI_RESET_SUGGEST_HOST_RESET:
2107
                outb(CMD_RESETCHIP, REG_CMD(info));
2108
                outb(CMD_NOP, REG_CMD(info));
2109
                result |= SCSI_RESET_HOST_RESET;
2110
                break;
2111
 
2112
        default:
2113
                outb(CMD_RESETCHIP, REG_CMD(info));
2114
                outb(CMD_NOP, REG_CMD(info));
2115
                outb(CMD_RESETSCSI, REG_CMD(info));
2116
                result |= SCSI_RESET_HOST_RESET | SCSI_RESET_BUS_RESET;
2117
                break;
2118
        }
2119
 
2120
        udelay(300);
2121
        fas216_reset_state(info);
2122
        fas216_init_chip(info);
2123
 
2124
        /*
2125
         * Signal all commands in progress have been reset
2126
         */
2127
        fas216_reportstatus(&info->SCpnt, &SCpnt, DID_RESET << 16);
2128
 
2129
        while ((SCptr = queue_remove(&info->queues.disconnected)) != NULL)
2130
                fas216_reportstatus(&SCptr, &SCpnt, DID_RESET << 16);
2131
 
2132
        if (SCpnt) {
2133
                /*
2134
                 * Command not found on disconnected queue, nor currently
2135
                 * executing command - check pending commands
2136
                 */
2137
                if (info->origSCpnt == SCpnt)
2138
                        info->origSCpnt = NULL;
2139
 
2140
                queue_removecmd(&info->queues.issue, SCpnt);
2141
 
2142
                SCpnt->result = DID_RESET << 16;
2143
                SCpnt->scsi_done(SCpnt);
2144
        }
2145
 
2146
        printk("\n");
2147
 
2148
        return result | SCSI_RESET_SUCCESS;
2149
}
2150
 
2151
/* Function: int fas216_init(struct Scsi_Host *instance)
2152
 * Purpose : initialise FAS/NCR/AMD SCSI ic.
2153
 * Params  : instance - a driver-specific filled-out structure
2154
 * Returns : 0 on success
2155
 */
2156
int fas216_init(struct Scsi_Host *instance)
2157
{
2158
        FAS216_Info *info = (FAS216_Info *)instance->hostdata;
2159
        unsigned long flags;
2160
        int target_jiffies;
2161
 
2162
        info->magic_start = MAGIC;
2163
        info->magic_end = MAGIC;
2164
 
2165
        info->host = instance;
2166
        info->scsi.cfg[0] = instance->this_id;
2167
        info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE;
2168
        info->scsi.cfg[2] = info->ifcfg.cntl3 | CNTL3_ADIDCHK | CNTL3_G2CB;
2169
        info->scsi.type = "unknown";
2170
        info->SCpnt = NULL;
2171
        fas216_reset_state(info);
2172
 
2173
        memset(&info->stats, 0, sizeof(info->stats));
2174
 
2175
        msgqueue_initialise(&info->scsi.msgs);
2176
 
2177
        if (!queue_initialise(&info->queues.issue))
2178
                return 1;
2179
 
2180
        if (!queue_initialise(&info->queues.disconnected)) {
2181
                queue_free(&info->queues.issue);
2182
                return 1;
2183
        }
2184
 
2185
        outb(0, REG_CNTL3(info));
2186
        outb(CNTL2_S2FE, REG_CNTL2(info));
2187
 
2188
        if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE) {
2189
                info->scsi.type = "NCR53C90";
2190
        } else {
2191
                outb(0, REG_CNTL2(info));
2192
                outb(0, REG_CNTL3(info));
2193
                outb(5, REG_CNTL3(info));
2194
                if (inb(REG_CNTL3(info)) != 5) {
2195
                        info->scsi.type = "NCR53C90A";
2196
                } else {
2197
                        outb(0, REG_CNTL3(info));
2198
                        info->scsi.type = "NCR53C9x";
2199
                }
2200
        }
2201
 
2202
 
2203
        outb(CNTL3_ADIDCHK, REG_CNTL3(info));
2204
        outb(0, REG_CNTL3(info));
2205
 
2206
        outb(CMD_RESETCHIP, REG_CMD(info));
2207
        outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info));
2208
        outb(CNTL2_ENF, REG_CNTL2(info));
2209
        outb(CMD_RESETCHIP, REG_CMD(info));
2210
        switch (inb(REG1_ID(info))) {
2211
        case 12:
2212
                info->scsi.type = "Am53CF94";
2213
                break;
2214
        default:
2215
                break;
2216
        }
2217
 
2218
        udelay(300);
2219
        /* now for the real initialisation */
2220
        fas216_init_chip(info);
2221
 
2222
        outb(info->scsi.cfg[0] | CNTL1_DISR, REG_CNTL1(info));
2223
        outb(CMD_RESETSCSI, REG_CMD(info));
2224
 
2225
        /* scsi standard says 250ms */
2226
        target_jiffies = jiffies + (25 * HZ) / 100;
2227
        save_flags(flags);
2228
        sti();
2229
 
2230
        while (jiffies < target_jiffies) barrier();
2231
 
2232
        restore_flags(flags);
2233
 
2234
        outb(info->scsi.cfg[0], REG_CNTL1(info));
2235
        inb(REG_INST(info));
2236
 
2237
        /* now for the real initialisation */
2238
        fas216_init_chip(info);
2239
 
2240
        fas216_checkmagic(info, "fas216_init");
2241
 
2242
        return 0;
2243
}
2244
 
2245
/* Function: int fas216_release(struct Scsi_Host *instance)
2246
 * Purpose : release all resources and put everything to bed for
2247
 *           FAS/NCR/AMD SCSI ic.
2248
 * Params  : instance - a driver-specific filled-out structure
2249
 * Returns : 0 on success
2250
 */
2251
int fas216_release(struct Scsi_Host *instance)
2252
{
2253
        FAS216_Info *info = (FAS216_Info *)instance->hostdata;
2254
 
2255
        fas216_checkmagic(info, "fas216_release");
2256
 
2257
        outb(CMD_RESETCHIP, REG_CMD(info));
2258
        queue_free(&info->queues.disconnected);
2259
        queue_free(&info->queues.issue);
2260
 
2261
        return 0;
2262
}
2263
 
2264
int fas216_print_stats(FAS216_Info *info, char *buffer)
2265
{
2266
        return sprintf(buffer,
2267
                        "Queued commands: %-10u   Issued commands: %-10u\n"
2268
                        "Done commands  : %-10u   Reads          : %-10u\n"
2269
                        "Writes         : %-10u   Others         : %-10u\n"
2270
                        "Disconnects    : %-10u   Aborts         : %-10u\n"
2271
                        "Resets         : %-10u\n",
2272
                        info->stats.queues,      info->stats.removes,
2273
                        info->stats.fins,        info->stats.reads,
2274
                        info->stats.writes,      info->stats.miscs,
2275
                        info->stats.disconnects, info->stats.aborts,
2276
                        info->stats.resets);
2277
}
2278
 
2279
int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer)
2280
{
2281
        struct fas216_device *dev = &info->device[scd->id];
2282
        int len = 0;
2283
        char *p;
2284
 
2285
        proc_print_scsidevice(scd, buffer, &len, 0);
2286
        p = buffer + len;
2287
 
2288
        p += sprintf(p, "  Extensions: ");
2289
 
2290
        if (scd->tagged_supported)
2291
                p += sprintf(p, "TAG %sabled [%d] ",
2292
                             scd->tagged_queue ? "en" : "dis",
2293
                             scd->current_tag);
2294
 
2295
        p += sprintf(p, "\n  Transfers : %d-bit ",
2296
                     8 << dev->wide_xfer);
2297
 
2298
        if (dev->sof)
2299
                p += sprintf(p, "sync offset %d, %d ns\n",
2300
                                dev->sof, dev->period * 4);
2301
        else
2302
                p += sprintf(p, "async\n");
2303
 
2304
        return p - buffer;
2305
}

powered by: WebSVN 2.1.0

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