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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [armnommu/] [drivers/] [scsi/] [acornscsi.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/acornscsi.c
3
 *
4
 *  Acorn SCSI 3 driver
5
 *  By R.M.King.
6
 *
7
 * Abandoned using the Select and Transfer command since there were
8
 * some nasty races between our software and the target devices that
9
 * were not easy to solve, and the device errata had a lot of entries
10
 * for this command, some of them quite nasty...
11
 *
12
 * Changelog:
13
 *  26-Sep-1997 RMK     Re-jigged to use the queue module.
14
 *                      Re-coded state machine to be based on driver
15
 *                      state not scsi state.  Should be easier to debug.
16
 *                      Added acornscsi_release to clean up properly.
17
 *                      Updated proc/scsi reporting.
18
 *  05-Oct-1997 RMK     Implemented writing to SCSI devices.
19
 *  06-Oct-1997 RMK     Corrected small (non-serious) bug with the connect/
20
 *                      reconnect race condition causing a warning message.
21
 *  12-Oct-1997 RMK     Added catch for re-entering interrupt routine.
22
 *  15-Oct-1997 RMK     Improved handling of commands.
23
 */
24
#define DEBUG_NO_WRITE  1
25
#define DEBUG_QUEUES    2
26
#define DEBUG_DMA       4
27
#define DEBUG_ABORT     8
28
#define DEBUG_DISCON    16
29
#define DEBUG_CONNECT   32
30
#define DEBUG_PHASES    64
31
#define DEBUG_WRITE     128
32
#define DEBUG_LINK      256
33
#define DEBUG_MESSAGES  512
34
#define DEBUG_RESET     1024
35
#define DEBUG_ALL       (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\
36
                         DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\
37
                         DEBUG_DMA|DEBUG_QUEUES)
38
 
39
/* DRIVER CONFIGURATION
40
 *
41
 * SCSI-II Tagged queue support.
42
 *
43
 * I don't have any SCSI devices that support it, so it is totally untested
44
 * (except to make sure that it doesn't interfere with any non-tagging
45
 * devices).  It is not fully implemented either - what happens when a
46
 * tagging device reconnects???
47
 *
48
 * You can tell if you have a device that supports tagged queueing my
49
 * cating (eg) /proc/scsi/acornscsi/0 and see if the SCSI revision is reported
50
 * as '2 TAG'.
51
 */
52
#undef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
53
/*
54
 * SCSI-II Linked command support.
55
 *
56
 * The higher level code doesn't support linked commands yet, and so the option
57
 * is undef'd here.
58
 */
59
#undef CONFIG_SCSI_ACORNSCSI_LINK
60
/*
61
 * SCSI-II Synchronous transfer support.
62
 *
63
 * Tried and tested...
64
 *
65
 * SDTR_SIZE      - maximum number of un-acknowledged bytes (0 = off, 12 = max)
66
 * SDTR_PERIOD    - period of REQ signal (min=125, max=1020)
67
 * DEFAULT_PERIOD - default REQ period.
68
 */
69
#define CONFIG_SCSI_ACORNSCSI_SYNC
70
#define SDTR_SIZE       12
71
#define SDTR_PERIOD     180
72
#define DEFAULT_PERIOD  500
73
 
74
/*
75
 * Debugging information
76
 *
77
 * DEBUG          - bit mask from list above
78
 * DEBUG_TARGET   - is defined to the target number if you want to debug
79
 *                  a specific target. [only recon/write/dma].
80
 */
81
#define DEBUG (DEBUG_RESET)
82
/* only allow writing to SCSI device 0 */
83
#define NO_WRITE 0xFE
84
/*#define DEBUG_TARGET 2*/
85
/*
86
 * Select timeout time (in 10ms units)
87
 *
88
 * This is the timeout used between the start of selection and the WD33C93
89
 * chip deciding that the device isn't responding.
90
 */
91
#define TIMEOUT_TIME 10
92
/*
93
 * Define this if you want to have verbose explaination of SCSI
94
 * status/messages.
95
 */
96
#undef CONFIG_ACORNSCSI_CONSTANTS
97
/*
98
 * Define this if you want to use the on board DMAC [don't remove this option]
99
 * If not set, then use PIO mode (not currently supported).
100
 */
101
#define USE_DMAC
102
/*
103
 * List of devices that the driver will recognise
104
 */
105
#define ACORNSCSI_LIST { MANU_ACORN, PROD_ACORN_SCSI }
106
/*
107
 * ====================================================================================
108
 */
109
 
110
#ifdef DEBUG_TARGET
111
#define DBG(cmd,xxx...) \
112
  if (cmd->target == DEBUG_TARGET) { \
113
    xxx; \
114
  }
115
#else
116
#define DBG(cmd,xxx...) xxx
117
#endif
118
 
119
#ifndef STRINGIFY
120
#define STRINGIFY(x) #x
121
#endif
122
#define STR(x) STRINGIFY(x)
123
#define NO_WRITE_STR STR(NO_WRITE)
124
 
125
#include <linux/config.h>
126
#include <linux/module.h>
127
#include <linux/kernel.h>
128
#include <linux/sched.h>
129
#include <linux/string.h>
130
#include <linux/signal.h>
131
#include <linux/errno.h>
132
#include <linux/proc_fs.h>
133
#include <linux/stat.h>
134
#include <linux/ioport.h>
135
#include <asm/bitops.h>
136
#include <asm/delay.h>
137
#include <asm/system.h>
138
#include <asm/io.h>
139
#include <asm/ecard.h>
140
 
141
#include "../block/blk.h"
142
#include "scsi.h"
143
#include "hosts.h"
144
#include "acornscsi.h"
145
#include "constants.h"
146
#include "msgqueue.h"
147
 
148
#define VER_MAJOR 2
149
#define VER_MINOR 0
150
#define VER_PATCH 6
151
 
152
#ifndef ABORT_TAG
153
#define ABORT_TAG 0xd
154
#else
155
#error "Yippee!  ABORT TAG is now defined!  Remove this error!"
156
#endif
157
 
158
#ifndef NO_IRQ
159
#define NO_IRQ 255
160
#endif
161
 
162
#ifdef CONFIG_SCSI_ACORNSCSI_LINK
163
#error SCSI2 LINKed commands not supported (yet)!
164
#endif
165
 
166
#ifdef USE_DMAC
167
/*
168
 * DMAC setup parameters
169
 */
170
#define INIT_DEVCON0    (DEVCON0_RQL|DEVCON0_EXW|DEVCON0_CMP)
171
#define INIT_DEVCON1    (DEVCON1_BHLD)
172
#define DMAC_READ       (MODECON_READ)
173
#define DMAC_WRITE      (MODECON_WRITE)
174
#define INIT_SBICDMA    (CTRL_DMABURST)
175
 
176
#define scsi_xferred    have_data_in
177
 
178
/*
179
 * Size of on-board DMA buffer
180
 */
181
#define DMAC_BUFFER_SIZE        65536
182
#endif
183
 
184
#define STATUS_BUFFER_SIZE      32
185
#define STATUS_BUFFER_TO_PRINT  24
186
 
187
unsigned int sdtr_period = SDTR_PERIOD;
188
unsigned int sdtr_size   = SDTR_SIZE;
189
 
190
static struct proc_dir_entry proc_scsi_acornscsi = {
191
        PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2
192
};
193
 
194
static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
195
static int acornscsi_reconnect_finish(AS_Host *host);
196
static void acornscsi_dma_cleanup(AS_Host *host);
197
static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
198
 
199
/* ====================================================================================
200
 * Miscellaneous
201
 */
202
 
203
static inline void
204
sbic_arm_write(unsigned int io_port, int reg, int value)
205
{
206
    outb_t(reg, io_port);
207
    outb_t(value, io_port + 4);
208
}
209
 
210
#define sbic_arm_writenext(io,val) \
211
        outb_t((val), (io) + 4)
212
 
213
static inline
214
int sbic_arm_read(unsigned int io_port, int reg)
215
{
216
    if(reg == ASR)
217
           return inl_t(io_port) & 255;
218
    outb_t(reg, io_port);
219
    return inl_t(io_port + 4) & 255;
220
}
221
 
222
#define sbic_arm_readnext(io) \
223
        inb_t((io) + 4)
224
 
225
#ifdef USE_DMAC
226
#define dmac_read(io_port,reg) \
227
        inb((io_port) + (reg))
228
 
229
#define dmac_write(io_port,reg,value) \
230
        ({ outb((value), (io_port) + (reg)); })
231
 
232
#define dmac_clearintr(io_port) \
233
        ({ outb(0, (io_port)); })
234
 
235
static inline
236
unsigned int dmac_address(unsigned int io_port)
237
{
238
    return dmac_read(io_port, TXADRHI) << 16 |
239
           dmac_read(io_port, TXADRMD) << 8 |
240
           dmac_read(io_port, TXADRLO);
241
}
242
 
243
static
244
void acornscsi_dumpdma(AS_Host *host, char *where)
245
{
246
        unsigned int mode, addr, len;
247
 
248
        mode = dmac_read(host->dma.io_port, MODECON);
249
        addr = dmac_address(host->dma.io_port);
250
        len  = dmac_read(host->dma.io_port, TXCNTHI) << 8 |
251
               dmac_read(host->dma.io_port, TXCNTLO);
252
 
253
        printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",
254
                host->host->host_no, where,
255
                mode, addr, (len + 1) & 0xffff,
256
                dmac_read(host->dma.io_port, MASKREG));
257
 
258
        printk("DMA @%06x, ", host->dma.start_addr);
259
        printk("BH @%p +%04x, ", host->scsi.SCp.ptr,
260
                host->scsi.SCp.this_residual);
261
        printk("DT @+%04x ST @+%04x", host->dma.transferred,
262
                host->scsi.SCp.scsi_xferred);
263
        printk("\n");
264
}
265
#endif
266
 
267
static
268
unsigned long acornscsi_sbic_xfcount(AS_Host *host)
269
{
270
    unsigned long length;
271
 
272
    length = sbic_arm_read(host->scsi.io_port, TRANSCNTH) << 16;
273
    length |= sbic_arm_readnext(host->scsi.io_port) << 8;
274
    length |= sbic_arm_readnext(host->scsi.io_port);
275
 
276
    return length;
277
}
278
 
279
static int
280
acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg)
281
{
282
        int asr;
283
 
284
        do {
285
                asr = sbic_arm_read(host->scsi.io_port, ASR);
286
 
287
                if ((asr & stat_mask) == stat)
288
                        return 0;
289
 
290
                udelay(1);
291
        } while (--timeout);
292
 
293
        printk("scsi%d: timeout while %s\n", host->host->host_no, msg);
294
 
295
        return -1;
296
}
297
 
298
static
299
int acornscsi_sbic_issuecmd(AS_Host *host, int command)
300
{
301
    if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command"))
302
        return -1;
303
 
304
    sbic_arm_write(host->scsi.io_port, CMND, command);
305
 
306
    return 0;
307
}
308
 
309
static void
310
acornscsi_csdelay(unsigned int cs)
311
{
312
    unsigned long target_jiffies, flags;
313
 
314
    target_jiffies = jiffies + 1 + cs * HZ / 100;
315
 
316
    save_flags(flags);
317
    sti();
318
 
319
    while (jiffies < target_jiffies) barrier();
320
 
321
    restore_flags(flags);
322
}
323
 
324
static
325
void acornscsi_resetcard(AS_Host *host)
326
{
327
    unsigned int i, timeout;
328
 
329
    /* assert reset line */
330
    host->card.page_reg = 0x80;
331
    outb(host->card.page_reg, host->card.io_page);
332
 
333
    /* wait 3 cs.  SCSI standard says 25ms. */
334
    acornscsi_csdelay(3);
335
 
336
    host->card.page_reg = 0;
337
    outb(host->card.page_reg, host->card.io_page);
338
 
339
    /*
340
     * Should get a reset from the card
341
     */
342
    timeout = 1000;
343
    do {
344
        if (inb(host->card.io_intr) & 8)
345
            break;
346
        udelay(1);
347
    } while (--timeout);
348
 
349
    if (timeout == 0)
350
        printk("scsi%d: timeout while resetting card\n",
351
                host->host->host_no);
352
 
353
    sbic_arm_read(host->scsi.io_port, ASR);
354
    sbic_arm_read(host->scsi.io_port, SSR);
355
 
356
    /* setup sbic - WD33C93A */
357
    sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
358
    sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
359
 
360
    /*
361
     * Command should cause a reset interrupt
362
     */
363
    timeout = 1000;
364
    do {
365
        if (inb(host->card.io_intr) & 8)
366
            break;
367
        udelay(1);
368
    } while (--timeout);
369
 
370
    if (timeout == 0)
371
        printk("scsi%d: timeout while resetting card\n",
372
                host->host->host_no);
373
 
374
    sbic_arm_read(host->scsi.io_port, ASR);
375
    if (sbic_arm_read(host->scsi.io_port, SSR) != 0x01)
376
        printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n",
377
                host->host->host_no);
378
 
379
    sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
380
    sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
381
    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
382
    sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
383
 
384
    host->card.page_reg = 0x40;
385
    outb(host->card.page_reg, host->card.io_page);
386
 
387
    /* setup dmac - uPC71071 */
388
    dmac_write(host->dma.io_port, INIT, 0);
389
#ifdef USE_DMAC
390
    dmac_write(host->dma.io_port, INIT, INIT_8BIT);
391
    dmac_write(host->dma.io_port, CHANNEL, CHANNEL_0);
392
    dmac_write(host->dma.io_port, DEVCON0, INIT_DEVCON0);
393
    dmac_write(host->dma.io_port, DEVCON1, INIT_DEVCON1);
394
#endif
395
 
396
    host->SCpnt = NULL;
397
    host->scsi.phase = PHASE_IDLE;
398
    host->scsi.disconnectable = 0;
399
 
400
    for (i = 0; i < 8; i++) {
401
        host->busyluns[i] = 0;
402
        host->device[i].sync_state = SYNC_NEGOCIATE;
403
        host->device[i].disconnect_ok = 1;
404
    }
405
 
406
    /* wait 25 cs.  SCSI standard says 250ms. */
407
    acornscsi_csdelay(25);
408
}
409
 
410
/*=============================================================================================
411
 * Utility routines (eg. debug)
412
 */
413
#ifdef CONFIG_ACORNSCSI_CONSTANTS
414
static char *acornscsi_interrupttype[] = {
415
  "rst",  "suc",  "p/a",  "3",
416
  "term", "5",    "6",    "7",
417
  "serv", "9",    "a",    "b",
418
  "c",    "d",    "e",    "f"
419
};
420
 
421
static signed char acornscsi_map[] = {
422
  0,  1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
423
 -1,  2, -1, -1,  -1, -1,  3, -1,   4,  5,  6,  7,   8,  9, 10, 11,
424
 12, 13, 14, -1,  -1, -1, -1, -1,   4,  5,  6,  7,   8,  9, 10, 11,
425
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
426
 15, 16, 17, 18,  19, -1, -1, 20,   4,  5,  6,  7,   8,  9, 10, 11,
427
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
428
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
429
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
430
 21, 22, -1, -1,  -1, 23, -1, -1,   4,  5,  6,  7,   8,  9, 10, 11,
431
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
432
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
433
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
434
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
435
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
436
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
437
 -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1
438
};
439
 
440
static char *acornscsi_interruptcode[] = {
441
    /* 0 */
442
    "reset - normal mode",      /* 00 */
443
    "reset - advanced mode",    /* 01 */
444
 
445
    /* 2 */
446
    "sel",                      /* 11 */
447
    "sel+xfer",                 /* 16 */
448
    "data-out",                 /* 18 */
449
    "data-in",                  /* 19 */
450
    "cmd",                      /* 1A */
451
    "stat",                     /* 1B */
452
    "??-out",                   /* 1C */
453
    "??-in",                    /* 1D */
454
    "msg-out",                  /* 1E */
455
    "msg-in",                   /* 1F */
456
 
457
    /* 12 */
458
    "/ACK asserted",            /* 20 */
459
    "save-data-ptr",            /* 21 */
460
    "{re}sel",                  /* 22 */
461
 
462
    /* 15 */
463
    "inv cmd",                  /* 40 */
464
    "unexpected disconnect",    /* 41 */
465
    "sel timeout",              /* 42 */
466
    "P err",                    /* 43 */
467
    "P err+ATN",                /* 44 */
468
    "bad status byte",          /* 47 */
469
 
470
    /* 21 */
471
    "resel, no id",             /* 80 */
472
    "resel",                    /* 81 */
473
    "discon",                   /* 85 */
474
};
475
 
476
static
477
void print_scsi_status(unsigned int ssr)
478
{
479
    if (acornscsi_map[ssr] != -1)
480
        printk("%s:%s",
481
                acornscsi_interrupttype[(ssr >> 4)],
482
                acornscsi_interruptcode[acornscsi_map[ssr]]);
483
    else
484
        printk("%X:%X", ssr >> 4, ssr & 0x0f);
485
}
486
#endif
487
 
488
static
489
void print_sbic_status(int asr, int ssr, int cmdphase)
490
{
491
#ifdef CONFIG_ACORNSCSI_CONSTANTS
492
    printk("sbic: %c%c%c%c%c%c ",
493
            asr & ASR_INT ? 'I' : 'i',
494
            asr & ASR_LCI ? 'L' : 'l',
495
            asr & ASR_BSY ? 'B' : 'b',
496
            asr & ASR_CIP ? 'C' : 'c',
497
            asr & ASR_PE  ? 'P' : 'p',
498
            asr & ASR_DBR ? 'D' : 'd');
499
    printk("scsi: ");
500
    print_scsi_status(ssr);
501
    printk(" ph %02X\n", cmdphase);
502
#else
503
    printk("sbic: %02X scsi: %X:%X ph: %02X\n",
504
            asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);
505
#endif
506
}
507
 
508
static void
509
acornscsi_dumplogline(AS_Host *host, int target, int line)
510
{
511
        unsigned long prev;
512
        signed int ptr;
513
 
514
        ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT;
515
        if (ptr < 0)
516
                ptr += STATUS_BUFFER_SIZE;
517
 
518
        printk("%c: %3s:", target == 8 ? 'H' : '0' + target,
519
                line == 0 ? "ph" : line == 1 ? "ssr" : "int");
520
 
521
        prev = host->status[target][ptr].when;
522
 
523
        for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
524
                unsigned long time_diff;
525
 
526
                if (!host->status[target][ptr].when)
527
                        continue;
528
 
529
                switch (line) {
530
                case 0:
531
                        printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ',
532
                                         host->status[target][ptr].ph);
533
                        break;
534
 
535
                case 1:
536
                        printk(" %02X", host->status[target][ptr].ssr);
537
                        break;
538
 
539
                case 2:
540
                        time_diff = host->status[target][ptr].when - prev;
541
                        prev = host->status[target][ptr].when;
542
                        if (time_diff == 0)
543
                                printk("==^");
544
                        else if (time_diff >= 100)
545
                                printk("   ");
546
                        else
547
                                printk(" %02ld", time_diff);
548
                        break;
549
                }
550
        }
551
 
552
        printk("\n");
553
}
554
 
555
static void
556
acornscsi_dumplog(AS_Host *host, int target)
557
{
558
    do {
559
        acornscsi_dumplogline(host, target, 0);
560
        acornscsi_dumplogline(host, target, 1);
561
        acornscsi_dumplogline(host, target, 2);
562
 
563
        if (target == 8)
564
            break;
565
 
566
        target = 8;
567
    } while (1);
568
}
569
 
570
static
571
char acornscsi_target(AS_Host *host)
572
{
573
        if (host->SCpnt)
574
                return '0' + host->SCpnt->target;
575
        return 'H';
576
}
577
 
578
/*
579
 * Prototype: cmdtype_t acornscsi_cmdtype(int command)
580
 * Purpose  : differentiate READ from WRITE from other commands
581
 * Params   : command - command to interpret
582
 * Returns  : CMD_READ  - command reads data,
583
 *            CMD_WRITE - command writes data,
584
 *            CMD_MISC  - everything else
585
 */
586
static inline
587
cmdtype_t acornscsi_cmdtype(int command)
588
{
589
    switch (command) {
590
    case WRITE_6:  case WRITE_10:  case WRITE_12:
591
        return CMD_WRITE;
592
    case READ_6:   case READ_10:   case READ_12:
593
        return CMD_READ;
594
    default:
595
        return CMD_MISC;
596
    }
597
}
598
 
599
/*
600
 * Prototype: int acornscsi_datadirection(int command)
601
 * Purpose  : differentiate between commands that have a DATA IN phase
602
 *            and a DATA OUT phase
603
 * Params   : command - command to interpret
604
 * Returns  : DATADIR_OUT - data out phase expected
605
 *            DATADIR_IN  - data in phase expected
606
 */
607
static
608
datadir_t acornscsi_datadirection(int command)
609
{
610
    switch (command) {
611
    case CHANGE_DEFINITION:     case COMPARE:           case COPY:
612
    case COPY_VERIFY:           case LOG_SELECT:        case MODE_SELECT:
613
    case MODE_SELECT_10:        case SEND_DIAGNOSTIC:   case WRITE_BUFFER:
614
    case FORMAT_UNIT:           case REASSIGN_BLOCKS:   case RESERVE:
615
    case SEARCH_EQUAL:          case SEARCH_HIGH:       case SEARCH_LOW:
616
    case WRITE_6:               case WRITE_10:          case WRITE_VERIFY:
617
    case UPDATE_BLOCK:          case WRITE_LONG:        case WRITE_SAME:
618
    case SEARCH_HIGH_12:        case SEARCH_EQUAL_12:   case SEARCH_LOW_12:
619
    case WRITE_12:              case WRITE_VERIFY_12:   case SET_WINDOW:
620
    case MEDIUM_SCAN:           case SEND_VOLUME_TAG:   case 0xea:
621
        return DATADIR_OUT;
622
    default:
623
        return DATADIR_IN;
624
    }
625
}
626
 
627
/*
628
 * Purpose  : provide values for synchronous transfers with 33C93.
629
 * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
630
 *      Modified by Russell King for 8MHz WD33C93A
631
 */
632
static struct sync_xfer_tbl {
633
    unsigned int period_ns;
634
    unsigned char reg_value;
635
} sync_xfer_table[] = {
636
    {   1, 0x20 },    { 249, 0x20 },    { 374, 0x30 },
637
    { 499, 0x40 },    { 624, 0x50 },    { 749, 0x60 },
638
    { 874, 0x70 },    { 999, 0x00 },    {   0,     0 }
639
};
640
 
641
/*
642
 * Prototype: int acornscsi_getperiod(unsigned char syncxfer)
643
 * Purpose  : period for the synchronous transfer setting
644
 * Params   : syncxfer SYNCXFER register value
645
 * Returns  : period in ns.
646
 */
647
static
648
int acornscsi_getperiod(unsigned char syncxfer)
649
{
650
    int i;
651
 
652
    syncxfer &= 0xf0;
653
    if (syncxfer == 0x10)
654
        syncxfer = 0;
655
 
656
    for (i = 1; sync_xfer_table[i].period_ns; i++)
657
        if (syncxfer == sync_xfer_table[i].reg_value)
658
            return sync_xfer_table[i].period_ns;
659
    return 0;
660
}
661
 
662
/*
663
 * Prototype: int round_period(unsigned int period)
664
 * Purpose  : return index into above table for a required REQ period
665
 * Params   : period - time (ns) for REQ
666
 * Returns  : table index
667
 * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
668
 */
669
static inline
670
int round_period(unsigned int period)
671
{
672
    int i;
673
 
674
    for (i = 1; sync_xfer_table[i].period_ns; i++) {
675
        if ((period <= sync_xfer_table[i].period_ns) &&
676
            (period > sync_xfer_table[i - 1].period_ns))
677
            return i;
678
    }
679
    return 7;
680
}
681
 
682
/*
683
 * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
684
 * Purpose  : calculate value for 33c93s SYNC register
685
 * Params   : period - time (ns) for REQ
686
 *            offset - offset in bytes between REQ/ACK
687
 * Returns  : value for SYNC register
688
 * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
689
 */
690
static
691
unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
692
{
693
    return sync_xfer_table[round_period(period)].reg_value |
694
                ((offset < SDTR_SIZE) ? offset : SDTR_SIZE);
695
}
696
 
697
/* ====================================================================================
698
 * Command functions
699
 */
700
/*
701
 * Function: acornscsi_kick(AS_Host *host)
702
 * Purpose : kick next command to interface
703
 * Params  : host - host to send command to
704
 * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING
705
 * Notes   : interrupts are always disabled!
706
 */
707
static
708
intr_ret_t acornscsi_kick(AS_Host *host)
709
{
710
    int from_queue = 0;
711
    Scsi_Cmnd *SCpnt;
712
 
713
    /* first check to see if a command is waiting to be executed */
714
    SCpnt = host->origSCpnt;
715
    host->origSCpnt = NULL;
716
 
717
    /* retrieve next command */
718
    if (!SCpnt) {
719
        SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns);
720
        if (!SCpnt)
721
            return INTR_IDLE;
722
 
723
        from_queue = 1;
724
    }
725
 
726
    if (host->scsi.disconnectable && host->SCpnt) {
727
        queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
728
        host->scsi.disconnectable = 0;
729
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
730
        DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n",
731
                host->host->host_no, acornscsi_target(host)));
732
#endif
733
        host->SCpnt = NULL;
734
    }
735
 
736
    /*
737
     * If we have an interrupt pending, then we may have been reselected.
738
     * In this case, we don't want to write to the registers
739
     */
740
    if (!(sbic_arm_read(host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
741
        sbic_arm_write(host->scsi.io_port, DESTID, SCpnt->target);
742
        sbic_arm_write(host->scsi.io_port, CMND, CMND_SELWITHATN);
743
    }
744
 
745
    /*
746
     * claim host busy - all of these must happen atomically wrt
747
     * our interrupt routine.  Failure means command loss.
748
     */
749
    host->scsi.phase = PHASE_CONNECTING;
750
    host->SCpnt = SCpnt;
751
    host->scsi.SCp = SCpnt->SCp;
752
    host->dma.xfer_setup = 0;
753
    host->dma.xfer_required = 0;
754
    host->dma.xfer_done = 0;
755
 
756
#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT))
757
    DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n",
758
            host->host->host_no, '0' + SCpnt->target,
759
            SCpnt->cmnd[0]));
760
#endif
761
 
762
    if (from_queue) {
763
#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
764
        /*
765
         * tagged queueing - allocate a new tag to this command
766
         */
767
        if (SCpnt->device->tagged_queue) {
768
            SCpnt->device->current_tag += 1;
769
            if (SCpnt->device->current_tag == 0)
770
                SCpnt->device->current_tag = 1;
771
            SCpnt->tag = SCpnt->device->current_tag;
772
        } else
773
#endif
774
            set_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns);
775
 
776
        host->stats.removes += 1;
777
 
778
        switch (acornscsi_cmdtype(SCpnt->cmnd[0])) {
779
        case CMD_WRITE:
780
            host->stats.writes += 1;
781
            break;
782
        case CMD_READ:
783
            host->stats.reads += 1;
784
            break;
785
        case CMD_MISC:
786
            host->stats.miscs += 1;
787
            break;
788
        }
789
    }
790
 
791
    return INTR_PROCESSING;
792
}
793
 
794
/*
795
 * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
796
 * Purpose : complete processing for command
797
 * Params  : host   - interface that completed
798
 *           result - driver byte of result
799
 */
800
static
801
void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
802
{
803
    Scsi_Cmnd *SCpnt = *SCpntp;
804
 
805
    /* clean up */
806
    sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
807
 
808
    host->stats.fins += 1;
809
 
810
    if (SCpnt) {
811
        *SCpntp = NULL;
812
 
813
        acornscsi_dma_cleanup(host);
814
 
815
        SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status;
816
 
817
        /*
818
         * In theory, this should not happen.  In practice, it seems to.
819
         * Only trigger an error if the device attempts to report all happy
820
         * but with untransferred buffers...  If we don't do something, then
821
         * data loss will occur.  Should we check SCpnt->underflow here?
822
         * It doesn't appear to be set to something meaningful by the higher
823
         * levels all the time.
824
         */
825
        if (result == DID_OK) {
826
                int xfer_warn = 0;
827
 
828
                if (SCpnt->underflow == 0) {
829
                        if (host->scsi.SCp.ptr &&
830
                            acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC)
831
                                xfer_warn = 1;
832
                } else {
833
                        if (host->scsi.SCp.scsi_xferred < SCpnt->underflow ||
834
                            host->scsi.SCp.scsi_xferred != host->dma.transferred)
835
                                xfer_warn = 1;
836
                }
837
 
838
                /* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6)
839
                 *  Targets which break data transfers into multiple
840
                 *  connections shall end each successful connection
841
                 *  (except possibly the last) with a SAVE DATA
842
                 *  POINTER - DISCONNECT message sequence.
843
                 *
844
                 * This makes it difficult to ensure that a transfer has
845
                 * completed.  If we reach the end of a transfer during
846
                 * the command, then we can only have finished the transfer.
847
                 * therefore, if we seem to have some data remaining, this
848
                 * is not a problem.
849
                 */
850
                if (host->dma.xfer_done)
851
                        xfer_warn = 0;
852
 
853
                if (xfer_warn) {
854
                    switch (status_byte(SCpnt->result)) {
855
                    case CHECK_CONDITION:
856
                    case COMMAND_TERMINATED:
857
                    case BUSY:
858
                    case QUEUE_FULL:
859
                    case RESERVATION_CONFLICT:
860
                        break;
861
 
862
                    default:
863
                        printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
864
                                host->host->host_no, SCpnt->result);
865
                        print_command(SCpnt->cmnd);
866
                        acornscsi_dumpdma(host, "done");
867
                        acornscsi_dumplog(host, SCpnt->target);
868
                        SCpnt->result &= 0xffff;
869
                        SCpnt->result |= DID_ERROR << 16;
870
                    }
871
                }
872
        }
873
 
874
        if (!SCpnt->scsi_done)
875
            panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no);
876
 
877
        clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns);
878
 
879
        SCpnt->scsi_done(SCpnt);
880
    } else
881
        printk("scsi%d: null command in acornscsi_done", host->host->host_no);
882
 
883
    host->scsi.phase = PHASE_IDLE;
884
}
885
 
886
/* ====================================================================================
887
 * DMA routines
888
 */
889
/*
890
 * Purpose  : update SCSI Data Pointer
891
 * Notes    : this will only be one SG entry or less
892
 */
893
static
894
void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length)
895
{
896
    SCp->ptr += length;
897
    SCp->this_residual -= length;
898
 
899
    if (!SCp->this_residual) {
900
        if (SCp->buffers_residual) {
901
            SCp->buffer++;
902
            SCp->buffers_residual--;
903
            SCp->ptr = (char *)SCp->buffer->address;
904
            SCp->this_residual = SCp->buffer->length;
905
        } else {
906
            SCp->ptr = NULL;
907
            host->dma.xfer_done = 1;
908
        }
909
    }
910
}
911
 
912
/*
913
 * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr,
914
 *                              unsigned int start_addr, unsigned int length)
915
 * Purpose  : read data from DMA RAM
916
 * Params   : host - host to transfer from
917
 *            ptr  - DRAM address
918
 *            start_addr - host mem address
919
 *            length - number of bytes to transfer
920
 * Notes    : this will only be one SG entry or less
921
 */
922
static
923
void acornscsi_data_read(AS_Host *host, char *ptr,
924
                                 unsigned int start_addr, unsigned int length)
925
{
926
    extern void __acornscsi_in(int port, char *buf, int len);
927
    unsigned int page, offset, len = length;
928
 
929
    page = (start_addr >> 12);
930
    offset = start_addr & ((1 << 12) - 1);
931
 
932
    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
933
 
934
    while (len > 0) {
935
        unsigned int this_len;
936
 
937
        if (len + offset > (1 << 12))
938
            this_len = (1 << 12) - offset;
939
        else
940
            this_len = len;
941
 
942
        __acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len);
943
 
944
        offset += this_len;
945
        ptr += this_len;
946
        len -= this_len;
947
 
948
        if (offset == (1 << 12)) {
949
            offset = 0;
950
            page ++;
951
            outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
952
        }
953
    }
954
    outb(host->card.page_reg, host->card.io_page);
955
}
956
 
957
/*
958
 * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr,
959
 *                              unsigned int start_addr, unsigned int length)
960
 * Purpose  : write data to DMA RAM
961
 * Params   : host - host to transfer from
962
 *            ptr  - DRAM address
963
 *            start_addr - host mem address
964
 *            length - number of bytes to transfer
965
 * Notes    : this will only be one SG entry or less
966
 */
967
static
968
void acornscsi_data_write(AS_Host *host, char *ptr,
969
                                 unsigned int start_addr, unsigned int length)
970
{
971
    extern void __acornscsi_out(int port, char *buf, int len);
972
    unsigned int page, offset, len = length;
973
 
974
    page = (start_addr >> 12);
975
    offset = start_addr & ((1 << 12) - 1);
976
 
977
    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
978
 
979
    while (len > 0) {
980
        unsigned int this_len;
981
 
982
        if (len + offset > (1 << 12))
983
            this_len = (1 << 12) - offset;
984
        else
985
            this_len = len;
986
 
987
        __acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len);
988
 
989
        offset += this_len;
990
        ptr += this_len;
991
        len -= this_len;
992
 
993
        if (offset == (1 << 12)) {
994
            offset = 0;
995
            page ++;
996
            outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
997
        }
998
    }
999
    outb(host->card.page_reg, host->card.io_page);
1000
}
1001
 
1002
/* =========================================================================================
1003
 * On-board DMA routines
1004
 */
1005
#ifdef USE_DMAC
1006
/*
1007
 * Prototype: void acornscsi_dmastop(AS_Host *host)
1008
 * Purpose  : stop all DMA
1009
 * Params   : host - host on which to stop DMA
1010
 * Notes    : This is called when leaving DATA IN/OUT phase,
1011
 *            or when interface is RESET
1012
 */
1013
static inline
1014
void acornscsi_dma_stop(AS_Host *host)
1015
{
1016
    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
1017
    dmac_clearintr(host->dma.io_intr_clear);
1018
 
1019
#if (DEBUG & DEBUG_DMA)
1020
    DBG(host->SCpnt, acornscsi_dumpdma(host, "stop"));
1021
#endif
1022
}
1023
 
1024
/*
1025
 * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
1026
 * Purpose : setup DMA controller for data transfer
1027
 * Params  : host - host to setup
1028
 *           direction - data transfer direction
1029
 * Notes   : This is called when entering DATA I/O phase, not
1030
 *           while we're in a DATA I/O phase
1031
 */
1032
static
1033
void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
1034
{
1035
    unsigned int address, length, mode;
1036
 
1037
    host->dma.direction = direction;
1038
 
1039
    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
1040
 
1041
    if (direction == DMA_OUT) {
1042
#if (DEBUG & DEBUG_NO_WRITE)
1043
        if (NO_WRITE & (1 << host->SCpnt->target)) {
1044
            printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",
1045
                    host->host->host_no, acornscsi_target(host));
1046
            return;
1047
        }
1048
#endif
1049
        mode = DMAC_WRITE;
1050
    } else
1051
        mode = DMAC_READ;
1052
 
1053
    /*
1054
     * Allocate some buffer space, limited to half the buffer size
1055
     */
1056
    length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
1057
    if (length) {
1058
        host->dma.start_addr = address = host->dma.free_addr;
1059
        host->dma.free_addr = (host->dma.free_addr + length) &
1060
                                (DMAC_BUFFER_SIZE - 1);
1061
 
1062
        /*
1063
         * Transfer data to DMA memory
1064
         */
1065
        if (direction == DMA_OUT)
1066
            acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
1067
                                length);
1068
 
1069
        length -= 1;
1070
        dmac_write(host->dma.io_port, TXCNTLO, length);
1071
        dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
1072
        dmac_write(host->dma.io_port, TXADRLO, address);
1073
        dmac_write(host->dma.io_port, TXADRMD, address >> 8);
1074
        dmac_write(host->dma.io_port, TXADRHI, 0);
1075
        dmac_write(host->dma.io_port, MODECON, mode);
1076
        dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
1077
 
1078
#if (DEBUG & DEBUG_DMA)
1079
        DBG(host->SCpnt, acornscsi_dumpdma(host, "strt"));
1080
#endif
1081
        host->dma.xfer_setup = 1;
1082
    }
1083
}
1084
 
1085
/*
1086
 * Function: void acornscsi_dma_cleanup(AS_Host *host)
1087
 * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct
1088
 * Params  : host - host to finish
1089
 * Notes   : This is called when a command is:
1090
 *              terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT
1091
 *         : This must not return until all transfers are completed.
1092
 */
1093
static
1094
void acornscsi_dma_cleanup(AS_Host *host)
1095
{
1096
    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
1097
    dmac_clearintr(host->dma.io_intr_clear);
1098
 
1099
    /*
1100
     * Check for a pending transfer
1101
     */
1102
    if (host->dma.xfer_required) {
1103
        host->dma.xfer_required = 0;
1104
        if (host->dma.direction == DMA_IN)
1105
            acornscsi_data_read(host, host->dma.xfer_ptr,
1106
                                 host->dma.xfer_start, host->dma.xfer_length);
1107
    }
1108
 
1109
    /*
1110
     * Has a transfer been setup?
1111
     */
1112
    if (host->dma.xfer_setup) {
1113
        unsigned int transferred;
1114
 
1115
        host->dma.xfer_setup = 0;
1116
 
1117
#if (DEBUG & DEBUG_DMA)
1118
        DBG(host->SCpnt, acornscsi_dumpdma(host, "cupi"));
1119
#endif
1120
 
1121
        /*
1122
         * Calculate number of bytes transferred from DMA.
1123
         */
1124
        transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
1125
        host->dma.transferred += transferred;
1126
 
1127
        if (host->dma.direction == DMA_IN)
1128
            acornscsi_data_read(host, host->scsi.SCp.ptr,
1129
                                 host->dma.start_addr, transferred);
1130
 
1131
        /*
1132
         * Update SCSI pointers
1133
         */
1134
        acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
1135
#if (DEBUG & DEBUG_DMA)
1136
        DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo"));
1137
#endif
1138
    }
1139
}
1140
 
1141
/*
1142
 * Function: void acornscsi_dmacintr(AS_Host *host)
1143
 * Purpose : handle interrupts from DMAC device
1144
 * Params  : host - host to process
1145
 * Notes   : If reading, we schedule the read to main memory &
1146
 *           allow the transfer to continue.
1147
 *         : If writing, we fill the onboard DMA memory from main
1148
 *           memory.
1149
 *         : Called whenever DMAC finished it's current transfer.
1150
 */
1151
static
1152
void acornscsi_dma_intr(AS_Host *host)
1153
{
1154
    unsigned int address, length, transferred;
1155
 
1156
#if (DEBUG & DEBUG_DMA)
1157
    DBG(host->SCpnt, acornscsi_dumpdma(host, "inti"));
1158
#endif
1159
 
1160
    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
1161
    dmac_clearintr(host->dma.io_intr_clear);
1162
 
1163
    /*
1164
     * Calculate amount transferred via DMA
1165
     */
1166
    transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
1167
    host->dma.transferred += transferred;
1168
 
1169
    /*
1170
     * Schedule DMA transfer off board
1171
     */
1172
    if (host->dma.direction == DMA_IN) {
1173
        host->dma.xfer_start = host->dma.start_addr;
1174
        host->dma.xfer_length = transferred;
1175
        host->dma.xfer_ptr = host->scsi.SCp.ptr;
1176
        host->dma.xfer_required = 1;
1177
    }
1178
 
1179
    acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
1180
 
1181
    /*
1182
     * Allocate some buffer space, limited to half the on-board RAM size
1183
     */
1184
    length = min(host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
1185
    if (length) {
1186
        host->dma.start_addr = address = host->dma.free_addr;
1187
        host->dma.free_addr = (host->dma.free_addr + length) &
1188
                                (DMAC_BUFFER_SIZE - 1);
1189
 
1190
        /*
1191
         * Transfer data to DMA memory
1192
         */
1193
        if (host->dma.direction == DMA_OUT)
1194
            acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
1195
                                length);
1196
 
1197
        length -= 1;
1198
        dmac_write(host->dma.io_port, TXCNTLO, length);
1199
        dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
1200
        dmac_write(host->dma.io_port, TXADRLO, address);
1201
        dmac_write(host->dma.io_port, TXADRMD, address >> 8);
1202
        dmac_write(host->dma.io_port, TXADRHI, 0);
1203
        dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
1204
 
1205
#if (DEBUG & DEBUG_DMA)
1206
        DBG(host->SCpnt, acornscsi_dumpdma(host, "into"));
1207
#endif
1208
    } else {
1209
        host->dma.xfer_setup = 0;
1210
#if 0
1211
        /*
1212
         * If the interface still wants more, then this is an error.
1213
         * We give it another byte, but we also attempt to raise an
1214
         * attention condition.  We continue giving one byte until
1215
         * the device recognises the attention.
1216
         */
1217
        if (dmac_read(host->dma.io_port, STATUS) & STATUS_RQ0) {
1218
            acornscsi_abortcmd(host, host->SCpnt->tag);
1219
 
1220
            dmac_write(host->dma.io_port, TXCNTLO, 0);
1221
            dmac_write(host->dma.io_port, TXCNTHI, 0);
1222
            dmac_write(host->dma.io_port, TXADRLO, 0);
1223
            dmac_write(host->dma.io_port, TXADRMD, 0);
1224
            dmac_write(host->dma.io_port, TXADRHI, 0);
1225
            dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
1226
        }
1227
#endif
1228
    }
1229
}
1230
 
1231
/*
1232
 * Function: void acornscsi_dma_xfer(AS_Host *host)
1233
 * Purpose : transfer data between AcornSCSI and memory
1234
 * Params  : host - host to process
1235
 */
1236
static
1237
void acornscsi_dma_xfer(AS_Host *host)
1238
{
1239
    host->dma.xfer_required = 0;
1240
 
1241
    if (host->dma.direction == DMA_IN)
1242
        acornscsi_data_read(host, host->dma.xfer_ptr,
1243
                                host->dma.xfer_start, host->dma.xfer_length);
1244
}
1245
 
1246
/*
1247
 * Function: void acornscsi_dma_adjust(AS_Host *host)
1248
 * Purpose : adjust DMA pointers & count for bytes transfered to
1249
 *           SBIC but not SCSI bus.
1250
 * Params  : host - host to adjust DMA count for
1251
 */
1252
static
1253
void acornscsi_dma_adjust(AS_Host *host)
1254
{
1255
    if (host->dma.xfer_setup) {
1256
        signed long transferred;
1257
#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
1258
        DBG(host->SCpnt, acornscsi_dumpdma(host, "adji"));
1259
#endif
1260
        /*
1261
         * Calculate correct DMA address - DMA is ahead of SCSI bus while
1262
         * writing.
1263
         *  host->scsi.SCp.scsi_xferred is the number of bytes
1264
         *  actually transferred to/from the SCSI bus.
1265
         *  host->dma.transferred is the number of bytes transferred
1266
         *  over DMA since host->dma.start_addr was last set.
1267
         *
1268
         * real_dma_addr = host->dma.start_addr + host->scsi.SCp.scsi_xferred
1269
         *                 - host->dma.transferred
1270
         */
1271
        transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred;
1272
        if (transferred < 0)
1273
            printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",
1274
                    host->host->host_no, acornscsi_target(host), transferred);
1275
        else if (transferred == 0)
1276
            host->dma.xfer_setup = 0;
1277
        else {
1278
            transferred += host->dma.start_addr;
1279
            dmac_write(host->dma.io_port, TXADRLO, transferred);
1280
            dmac_write(host->dma.io_port, TXADRMD, transferred >> 8);
1281
            dmac_write(host->dma.io_port, TXADRHI, transferred >> 16);
1282
#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
1283
            DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo"));
1284
#endif
1285
        }
1286
    }
1287
}
1288
#endif
1289
 
1290
/* =========================================================================================
1291
 * Data I/O
1292
 */
1293
static int
1294
acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout)
1295
{
1296
        unsigned int asr, timeout = max_timeout;
1297
        int my_ptr = *ptr;
1298
 
1299
        while (my_ptr < len) {
1300
                asr = sbic_arm_read(host->scsi.io_port, ASR);
1301
 
1302
                if (asr & ASR_DBR) {
1303
                        timeout = max_timeout;
1304
 
1305
                        sbic_arm_write(host->scsi.io_port, DATA, bytes[my_ptr++]);
1306
                } else if (asr & ASR_INT)
1307
                        break;
1308
                else if (--timeout == 0)
1309
                        break;
1310
                udelay(1);
1311
        }
1312
 
1313
        *ptr = my_ptr;
1314
 
1315
        if (timeout == 0)
1316
                return -1;
1317
 
1318
        return 0;
1319
}
1320
/*
1321
 * Function: void acornscsi_sendcommand(AS_Host *host)
1322
 * Purpose : send a command to a target
1323
 * Params  : host - host which is connected to target
1324
 */
1325
static void
1326
acornscsi_sendcommand(AS_Host *host)
1327
{
1328
    Scsi_Cmnd *SCpnt = host->SCpnt;
1329
 
1330
    sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
1331
    sbic_arm_writenext(host->scsi.io_port, 0);
1332
    sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command);
1333
 
1334
    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
1335
 
1336
    if (acornscsi_write_pio(host, SCpnt->cmnd,
1337
        (int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000))
1338
        printk("scsi%d: timeout while sending command\n", host->host->host_no);
1339
 
1340
    host->scsi.phase = PHASE_COMMAND;
1341
}
1342
 
1343
static
1344
void acornscsi_sendmessage(AS_Host *host)
1345
{
1346
    unsigned int message_length = msgqueue_msglength(&host->scsi.msgs);
1347
    unsigned int msgnr;
1348
    struct message *msg;
1349
 
1350
#if (DEBUG & DEBUG_MESSAGES)
1351
    printk("scsi%d.%c: sending message ",
1352
            host->host->host_no, acornscsi_target(host));
1353
#endif
1354
 
1355
    switch (message_length) {
1356
    case 0:
1357
        acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
1358
 
1359
        acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1");
1360
 
1361
        sbic_arm_write(host->scsi.io_port, DATA, NOP);
1362
 
1363
        host->scsi.last_message = NOP;
1364
#if (DEBUG & DEBUG_MESSAGES)
1365
        printk("NOP");
1366
#endif
1367
        break;
1368
 
1369
    case 1:
1370
        acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
1371
        msg = msgqueue_getmsg(&host->scsi.msgs, 0);
1372
 
1373
        acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2");
1374
 
1375
        sbic_arm_write(host->scsi.io_port, DATA, msg->msg[0]);
1376
 
1377
        host->scsi.last_message = msg->msg[0];
1378
#if (DEBUG & DEBUG_MESSAGES)
1379
        print_msg(msg->msg);
1380
#endif
1381
        break;
1382
 
1383
    default:
1384
        /*
1385
         * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14)
1386
         * 'When a target sends this (MESSAGE_REJECT) message, it
1387
         *  shall change to MESSAGE IN phase and send this message
1388
         *  prior to requesting additional message bytes from the
1389
         *  initiator.  This provides an interlock so that the
1390
         *  initiator can determine which message byte is rejected.
1391
         */
1392
        sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
1393
        sbic_arm_writenext(host->scsi.io_port, 0);
1394
        sbic_arm_writenext(host->scsi.io_port, message_length);
1395
        acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
1396
 
1397
        msgnr = 0;
1398
        while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) {
1399
            unsigned int i;
1400
#if (DEBUG & DEBUG_MESSAGES)
1401
            print_msg(msg);
1402
#endif
1403
            i = 0;
1404
            if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000))
1405
                printk("scsi%d: timeout while sending message\n", host->host->host_no);
1406
 
1407
 
1408
            host->scsi.last_message = msg->msg[0];
1409
            if (msg->msg[0] == EXTENDED_MESSAGE)
1410
                host->scsi.last_message |= msg->msg[2] << 8;
1411
 
1412
            if (i != msg->length)
1413
                break;
1414
        }
1415
        break;
1416
    }
1417
#if (DEBUG & DEBUG_MESSAGES)
1418
    printk("\n");
1419
#endif
1420
}
1421
 
1422
/*
1423
 * Function: void acornscsi_readstatusbyte(AS_Host *host)
1424
 * Purpose : Read status byte from connected target
1425
 * Params  : host - host connected to target
1426
 */
1427
static
1428
void acornscsi_readstatusbyte(AS_Host *host)
1429
{
1430
    acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT);
1431
 
1432
    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte");
1433
 
1434
    host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, DATA);
1435
}
1436
 
1437
/*
1438
 * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host)
1439
 * Purpose : Read one message byte from connected target
1440
 * Params  : host - host connected to target
1441
 */
1442
static
1443
unsigned char acornscsi_readmessagebyte(AS_Host *host)
1444
{
1445
    unsigned char message;
1446
 
1447
    acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
1448
 
1449
    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte");
1450
 
1451
    message = sbic_arm_read(host->scsi.io_port, DATA);
1452
 
1453
    /* wait for MSGIN-XFER-PAUSED */
1454
    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte");
1455
 
1456
    sbic_arm_read(host->scsi.io_port, SSR);
1457
 
1458
    return message;
1459
}
1460
 
1461
/*
1462
 * Function: void acornscsi_message(AS_Host *host)
1463
 * Purpose : Read complete message from connected target & action message
1464
 * Params  : host - host connected to target
1465
 */
1466
static
1467
void acornscsi_message(AS_Host *host)
1468
{
1469
    unsigned char message[16];
1470
    unsigned int msgidx = 0, msglen = 1;
1471
 
1472
    do {
1473
        message[msgidx] = acornscsi_readmessagebyte(host);
1474
 
1475
        switch (msgidx) {
1476
        case 0:
1477
            if (message[0] == EXTENDED_MESSAGE ||
1478
                (message[0] >= 0x20 && message[0] <= 0x2f))
1479
                msglen = 2;
1480
            break;
1481
 
1482
        case 1:
1483
            if (message[0] == EXTENDED_MESSAGE)
1484
                msglen += message[msgidx];
1485
            break;
1486
        }
1487
        msgidx += 1;
1488
        if (msgidx < msglen) {
1489
            acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
1490
 
1491
            /* wait for next msg-in */
1492
            acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack");
1493
            sbic_arm_read(host->scsi.io_port, SSR);
1494
        }
1495
    } while (msgidx < msglen);
1496
 
1497
#if (DEBUG & DEBUG_MESSAGES)
1498
    printk("scsi%d.%c: message in: ",
1499
            host->host->host_no, acornscsi_target(host));
1500
    print_msg(message);
1501
    printk("\n");
1502
#endif
1503
 
1504
    if (host->scsi.phase == PHASE_RECONNECTED) {
1505
        /*
1506
         * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)
1507
         * 'Whenever a target reconnects to an initiator to continue
1508
         *  a tagged I/O process, the SIMPLE QUEUE TAG message shall
1509
         *  be sent immediately following the IDENTIFY message...'
1510
         */
1511
        if (message[0] == SIMPLE_QUEUE_TAG)
1512
            host->scsi.reconnected.tag = message[1];
1513
        if (acornscsi_reconnect_finish(host))
1514
            host->scsi.phase = PHASE_MSGIN;
1515
    }
1516
 
1517
    host->device[0].sync_xfer = message[0];
1518
 
1519
    switch (message[0]) {
1520
    case ABORT:
1521
    case ABORT_TAG:
1522
    case COMMAND_COMPLETE:
1523
        if (host->scsi.phase != PHASE_STATUSIN) {
1524
            printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n",
1525
                    host->host->host_no, acornscsi_target(host));
1526
            acornscsi_dumplog(host, host->SCpnt->target);
1527
        }
1528
        host->scsi.phase = PHASE_DONE;
1529
        host->scsi.SCp.Message = message[0];
1530
        break;
1531
 
1532
    case SAVE_POINTERS:
1533
        /*
1534
         * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20)
1535
         * 'The SAVE DATA POINTER message is sent from a target to
1536
         *  direct the initiator to copy the active data pointer to
1537
         *  the saved data pointer for the current I/O process.
1538
         */
1539
        acornscsi_dma_cleanup(host);
1540
        host->SCpnt->SCp = host->scsi.SCp;
1541
        host->SCpnt->SCp.sent_command = 0;
1542
        host->scsi.phase = PHASE_MSGIN;
1543
        break;
1544
 
1545
    case RESTORE_POINTERS:
1546
        /*
1547
         * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19)
1548
         * 'The RESTORE POINTERS message is sent from a target to
1549
         *  direct the initiator to copy the most recently saved
1550
         *  command, data, and status pointers for the I/O process
1551
         *  to the corresponding active pointers.  The command and
1552
         *  status pointers shall be restored to the beginning of
1553
         *  the present command and status areas.'
1554
         */
1555
        acornscsi_dma_cleanup(host);
1556
        host->scsi.SCp = host->SCpnt->SCp;
1557
        host->scsi.phase = PHASE_MSGIN;
1558
        break;
1559
 
1560
    case DISCONNECT:
1561
        /*
1562
         * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2)
1563
         * 'On those occasions when an error or exception condition occurs
1564
         *  and the target elects to repeat the information transfer, the
1565
         *  target may repeat the transfer either issuing a RESTORE POINTERS
1566
         *  message or by disconnecting without issuing a SAVE POINTERS
1567
         *  message.  When reconnection is completed, the most recent
1568
         *  saved pointer values are restored.'
1569
         */
1570
        acornscsi_dma_cleanup(host);
1571
        host->scsi.phase = PHASE_DISCONNECT;
1572
        break;
1573
 
1574
    case MESSAGE_REJECT:
1575
#if 0 /* this isn't needed any more */
1576
        /*
1577
         * If we were negociating sync transfer, we don't yet know if
1578
         * this REJECT is for the sync transfer or for the tagged queue/wide
1579
         * transfer.  Re-initiate sync transfer negociation now, and if
1580
         * we got a REJECT in response to SDTR, then it'll be set to DONE.
1581
         */
1582
        if (host->device[host->SCpnt->target].sync_state == SYNC_SENT_REQUEST)
1583
            host->device[host->SCpnt->target].sync_state = SYNC_NEGOCIATE;
1584
#endif
1585
 
1586
        /*
1587
         * If we have any messages waiting to go out, then assert ATN now
1588
         */
1589
        if (msgqueue_msglength(&host->scsi.msgs))
1590
            acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
1591
 
1592
        switch (host->scsi.last_message) {
1593
#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
1594
        case HEAD_OF_QUEUE_TAG:
1595
        case ORDERED_QUEUE_TAG:
1596
        case SIMPLE_QUEUE_TAG:
1597
            /*
1598
             * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)
1599
             *  If a target does not implement tagged queuing and a queue tag
1600
             *  message is received, it shall respond with a MESSAGE REJECT
1601
             *  message and accept the I/O process as if it were untagged.
1602
             */
1603
            printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",
1604
                    host->host->host_no, acornscsi_target(host));
1605
            host->SCpnt->device->tagged_queue = 0;
1606
            set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns);
1607
            break;
1608
#endif
1609
        case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8):
1610
            /*
1611
             * Target can't handle synchronous transfers
1612
             */
1613
            printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",
1614
                    host->host->host_no, acornscsi_target(host));
1615
            host->device[host->SCpnt->target].sync_xfer = SYNCHTRANSFER_2DBA;
1616
            host->device[host->SCpnt->target].sync_state = SYNC_ASYNCHRONOUS;
1617
            sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
1618
            break;
1619
 
1620
        default:
1621
            break;
1622
        }
1623
        break;
1624
 
1625
    case QUEUE_FULL:
1626
        /* TODO: target queue is full */
1627
        break;
1628
 
1629
    case SIMPLE_QUEUE_TAG:
1630
        /* tag queue reconnect... message[1] = queue tag.  Print something to indicate something happened! */
1631
        printk("scsi%d.%c: reconnect queue tag %02X\n",
1632
                host->host->host_no, acornscsi_target(host),
1633
                message[1]);
1634
        break;
1635
 
1636
    case EXTENDED_MESSAGE:
1637
        switch (message[2]) {
1638
#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
1639
        case EXTENDED_SDTR:
1640
            if (host->device[host->SCpnt->target].sync_state == SYNC_SENT_REQUEST) {
1641
                /*
1642
                 * We requested synchronous transfers.  This isn't quite right...
1643
                 * We can only say if this succeeded if we proceed on to execute the
1644
                 * command from this message.  If we get a MESSAGE PARITY ERROR,
1645
                 * and the target retries fail, then we fallback to asynchronous mode
1646
                 */
1647
                host->device[host->SCpnt->target].sync_state = SYNC_COMPLETED;
1648
                printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",
1649
                        host->host->host_no, acornscsi_target(host),
1650
                        message[4], message[3] * 4);
1651
                host->device[host->SCpnt->target].sync_xfer =
1652
                        calc_sync_xfer(message[3] * 4, message[4]);
1653
            } else {
1654
                unsigned char period, length;
1655
                /*
1656
                 * Target requested synchronous transfers.  The agreement is only
1657
                 * to be in operation AFTER the target leaves message out phase.
1658
                 */
1659
                acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
1660
                period = max(message[3], sdtr_period / 4);
1661
                length = min(message[4], sdtr_size);
1662
                msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,
1663
                                 EXTENDED_SDTR, period, length);
1664
                host->device[host->SCpnt->target].sync_xfer =
1665
                        calc_sync_xfer(period * 4, length);
1666
            }
1667
            sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
1668
            break;
1669
#else
1670
            /* We do not accept synchronous transfers.  Respond with a
1671
             * MESSAGE_REJECT.
1672
             */
1673
#endif
1674
 
1675
        case EXTENDED_WDTR:
1676
            /* The WD33C93A is only 8-bit.  We respond with a MESSAGE_REJECT
1677
             * to a wide data transfer request.
1678
             */
1679
        default:
1680
            acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
1681
            msgqueue_flush(&host->scsi.msgs);
1682
            msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
1683
            break;
1684
        }
1685
        break;
1686
 
1687
#ifdef CONFIG_SCSI_ACORNSCSI_LINK
1688
    case LINKED_CMD_COMPLETE:
1689
    case LINKED_FLG_CMD_COMPLETE:
1690
        /*
1691
         * We don't support linked commands yet
1692
         */
1693
        if (0) {
1694
#if (DEBUG & DEBUG_LINK)
1695
            printk("scsi%d.%c: lun %d tag %d linked command complete\n",
1696
                    host->host->host_no, acornscsi_target(host), host->SCpnt->tag);
1697
#endif
1698
            /*
1699
             * A linked command should only terminate with one of these messages
1700
             * if there are more linked commands available.
1701
             */
1702
            if (!host->SCpnt->next_link) {
1703
                printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n",
1704
                        instance->host_no, acornscsi_target(host), host->SCpnt->tag);
1705
                acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
1706
                msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
1707
            } else {
1708
                Scsi_Cmnd *SCpnt = host->SCpnt;
1709
 
1710
                acornscsi_dma_cleanup(host);
1711
 
1712
                host->SCpnt = host->SCpnt->next_link;
1713
                host->SCpnt->tag = SCpnt->tag;
1714
                SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status;
1715
                SCpnt->done(SCpnt);
1716
 
1717
                /* initialise host->SCpnt->SCp */
1718
            }
1719
            break;
1720
        }
1721
#endif
1722
 
1723
    default: /* reject message */
1724
        printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",
1725
                host->host->host_no, acornscsi_target(host),
1726
                message[0]);
1727
        acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
1728
        msgqueue_flush(&host->scsi.msgs);
1729
        msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
1730
        host->scsi.phase = PHASE_MSGIN;
1731
        break;
1732
    }
1733
    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
1734
}
1735
 
1736
/*
1737
 * Function: int acornscsi_buildmessages(AS_Host *host)
1738
 * Purpose : build the connection messages for a host
1739
 * Params  : host - host to add messages to
1740
 */
1741
static
1742
void acornscsi_buildmessages(AS_Host *host)
1743
{
1744
#if 0
1745
    /* does the device need resetting? */
1746
    if (cmd_reset) {
1747
        msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET);
1748
        return;
1749
    }
1750
#endif
1751
 
1752
    msgqueue_addmsg(&host->scsi.msgs, 1,
1753
                     IDENTIFY(host->device[host->SCpnt->target].disconnect_ok,
1754
                             host->SCpnt->lun));
1755
 
1756
#if 0
1757
    /* does the device need the current command aborted */
1758
    if (cmd_aborted) {
1759
        acornscsi_abortcmd(host->SCpnt->tag);
1760
        return;
1761
    }
1762
#endif
1763
 
1764
#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
1765
    if (host->SCpnt->tag) {
1766
        unsigned int tag_type;
1767
 
1768
        if (host->SCpnt->cmnd[0] == REQUEST_SENSE ||
1769
            host->SCpnt->cmnd[0] == TEST_UNIT_READY ||
1770
            host->SCpnt->cmnd[0] == INQUIRY)
1771
            tag_type = HEAD_OF_QUEUE_TAG;
1772
        else
1773
            tag_type = SIMPLE_QUEUE_TAG;
1774
        msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag);
1775
    }
1776
#endif
1777
 
1778
#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
1779
    if (host->device[host->SCpnt->target].sync_state == SYNC_NEGOCIATE) {
1780
        host->device[host->SCpnt->target].sync_state = SYNC_SENT_REQUEST;
1781
        msgqueue_addmsg(&host->scsi.msgs, 5,
1782
                         EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
1783
                         sdtr_period / 4, sdtr_size);
1784
    }
1785
#endif
1786
}
1787
 
1788
/*
1789
 * Function: int acornscsi_starttransfer(AS_Host *host)
1790
 * Purpose : transfer data to/from connected target
1791
 * Params  : host - host to which target is connected
1792
 * Returns : 0 if failure
1793
 */
1794
static
1795
int acornscsi_starttransfer(AS_Host *host)
1796
{
1797
    int residual;
1798
 
1799
    if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) {
1800
        printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",
1801
                host->host->host_no, acornscsi_target(host));
1802
        return 0;
1803
    }
1804
 
1805
    residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred;
1806
 
1807
    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer);
1808
    sbic_arm_writenext(host->scsi.io_port, residual >> 16);
1809
    sbic_arm_writenext(host->scsi.io_port, residual >> 8);
1810
    sbic_arm_writenext(host->scsi.io_port, residual);
1811
    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
1812
    return 1;
1813
}
1814
 
1815
/* =========================================================================================
1816
 * Connection & Disconnection
1817
 */
1818
/*
1819
 * Function : acornscsi_reconnect(AS_Host *host)
1820
 * Purpose  : reconnect a previously disconnected command
1821
 * Params   : host - host specific data
1822
 * Remarks  : SCSI spec says:
1823
 *              'The set of active pointers is restored from the set
1824
 *               of saved pointers upon reconnection of the I/O process'
1825
 */
1826
static
1827
int acornscsi_reconnect(AS_Host *host)
1828
{
1829
    unsigned int target, lun, ok = 0;
1830
 
1831
    target = sbic_arm_read(host->scsi.io_port, SOURCEID);
1832
 
1833
    if (!(target & 8))
1834
        printk(KERN_ERR "scsi%d: invalid source id after reselection "
1835
                "- device fault?\n",
1836
                host->host->host_no);
1837
 
1838
    target &= 7;
1839
 
1840
    if (host->SCpnt && !host->scsi.disconnectable) {
1841
        printk(KERN_ERR "scsi%d.%d: reconnected while command in "
1842
                "progress to target %d?\n",
1843
                host->host->host_no, target, host->SCpnt->target);
1844
        host->SCpnt = NULL;
1845
    }
1846
 
1847
    lun = sbic_arm_read(host->scsi.io_port, DATA) & 7;
1848
 
1849
    host->scsi.reconnected.target = target;
1850
    host->scsi.reconnected.lun = lun;
1851
    host->scsi.reconnected.tag = 0;
1852
 
1853
    if (host->scsi.disconnectable && host->SCpnt &&
1854
        host->SCpnt->target == target && host->SCpnt->lun == lun)
1855
        ok = 1;
1856
 
1857
    if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun))
1858
        ok = 1;
1859
 
1860
    ADD_STATUS(target, 0x81, host->scsi.phase, 0);
1861
 
1862
    if (ok) {
1863
        host->scsi.phase = PHASE_RECONNECTED;
1864
    } else {
1865
        /* this doesn't seem to work */
1866
        printk(KERN_ERR "scsi%d.%c: reselected with no command "
1867
                "to reconnect with\n",
1868
                host->host->host_no, '0' + target);
1869
        acornscsi_dumplog(host, target);
1870
        acornscsi_abortcmd(host, 0);
1871
        if (host->SCpnt) {
1872
            queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
1873
            host->SCpnt = NULL;
1874
        }
1875
    }
1876
    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
1877
    return !ok;
1878
}
1879
 
1880
/*
1881
 * Function: int acornscsi_reconect_finish(AS_Host *host)
1882
 * Purpose : finish reconnecting a command
1883
 * Params  : host - host to complete
1884
 * Returns : 0 if failed
1885
 */
1886
static
1887
int acornscsi_reconnect_finish(AS_Host *host)
1888
{
1889
    if (host->scsi.disconnectable && host->SCpnt) {
1890
        host->scsi.disconnectable = 0;
1891
        if (host->SCpnt->target == host->scsi.reconnected.target &&
1892
            host->SCpnt->lun    == host->scsi.reconnected.lun &&
1893
            host->SCpnt->tag    == host->scsi.reconnected.tag) {
1894
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
1895
            DBG(host->SCpnt, printk("scsi%d.%c: reconnected",
1896
                    host->host->host_no, acornscsi_target(host)));
1897
#endif
1898
        } else {
1899
            queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
1900
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
1901
            DBG(host->SCpnt, printk("scsi%d.%c: had to move command "
1902
                    "to disconnected queue\n",
1903
                    host->host->host_no, acornscsi_target(host)));
1904
#endif
1905
            host->SCpnt = NULL;
1906
        }
1907
    }
1908
    if (!host->SCpnt) {
1909
        host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected,
1910
                                host->scsi.reconnected.target,
1911
                                host->scsi.reconnected.lun,
1912
                                host->scsi.reconnected.tag);
1913
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
1914
        DBG(host->SCpnt, printk("scsi%d.%c: had to get command",
1915
                host->host->host_no, acornscsi_target(host)));
1916
#endif
1917
    }
1918
 
1919
    if (!host->SCpnt)
1920
        acornscsi_abortcmd(host, host->scsi.reconnected.tag);
1921
    else {
1922
        /*
1923
         * Restore data pointer from SAVED pointers.
1924
         */
1925
        host->scsi.SCp = host->SCpnt->SCp;
1926
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
1927
        printk(", data pointers: [%p, %X]",
1928
                host->scsi.SCp.ptr, host->scsi.SCp.this_residual);
1929
#endif
1930
    }
1931
#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
1932
    printk("\n");
1933
#endif
1934
 
1935
    host->dma.transferred = host->scsi.SCp.scsi_xferred;
1936
 
1937
    return host->SCpnt != NULL;
1938
}
1939
 
1940
/*
1941
 * Function: void acornscsi_disconnect_unexpected(AS_Host *host)
1942
 * Purpose : handle an unexpected disconnect
1943
 * Params  : host - host on which disconnect occurred
1944
 */
1945
static
1946
void acornscsi_disconnect_unexpected(AS_Host *host)
1947
{
1948
    printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n",
1949
            host->host->host_no, acornscsi_target(host));
1950
#if (DEBUG & DEBUG_ABORT)
1951
    acornscsi_dumplog(host, 8);
1952
#endif
1953
 
1954
    acornscsi_done(host, &host->SCpnt, DID_ERROR);
1955
}
1956
 
1957
/*
1958
 * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag)
1959
 * Purpose : abort a currently executing command
1960
 * Params  : host - host with connected command to abort
1961
 *           tag  - tag to abort
1962
 */
1963
static
1964
void acornscsi_abortcmd(AS_Host *host, unsigned char tag)
1965
{
1966
    host->scsi.phase = PHASE_ABORTED;
1967
    sbic_arm_write(host->scsi.io_port, CMND, CMND_ASSERTATN);
1968
 
1969
    msgqueue_flush(&host->scsi.msgs);
1970
#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
1971
    if (tag)
1972
        msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag);
1973
    else
1974
#endif
1975
        msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
1976
}
1977
 
1978
/* ==========================================================================================
1979
 * Interrupt routines.
1980
 */
1981
/*
1982
 * Function: int acornscsi_sbicintr(AS_Host *host)
1983
 * Purpose : handle interrupts from SCSI device
1984
 * Params  : host - host to process
1985
 * Returns : INTR_PROCESS if expecting another SBIC interrupt
1986
 *           INTR_IDLE if no interrupt
1987
 *           INTR_NEXT_COMMAND if we have finished processing the command
1988
 */
1989
static
1990
intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
1991
{
1992
    unsigned int asr, ssr;
1993
 
1994
    asr = sbic_arm_read(host->scsi.io_port, ASR);
1995
    if (!(asr & ASR_INT))
1996
        return INTR_IDLE;
1997
 
1998
    ssr = sbic_arm_read(host->scsi.io_port, SSR);
1999
 
2000
#if (DEBUG & DEBUG_PHASES)
2001
    print_sbic_status(asr, ssr, host->scsi.phase);
2002
#endif
2003
 
2004
    ADD_STATUS(8, ssr, host->scsi.phase, in_irq);
2005
 
2006
    if (host->SCpnt && !host->scsi.disconnectable)
2007
        ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq);
2008
 
2009
    switch (ssr) {
2010
    case 0x00:                          /* reset state - not advanced                   */
2011
        printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",
2012
                host->host->host_no);
2013
        /* setup sbic - WD33C93A */
2014
        sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
2015
        sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
2016
        return INTR_IDLE;
2017
 
2018
    case 0x01:                          /* reset state - advanced                       */
2019
        sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
2020
        sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
2021
        sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
2022
        sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
2023
        msgqueue_flush(&host->scsi.msgs);
2024
        return INTR_IDLE;
2025
 
2026
    case 0x41:                          /* unexpected disconnect aborted command        */
2027
        acornscsi_disconnect_unexpected(host);
2028
        return INTR_NEXT_COMMAND;
2029
    }
2030
 
2031
    switch (host->scsi.phase) {
2032
    case PHASE_CONNECTING:              /* STATE: command removed from issue queue      */
2033
        switch (ssr) {
2034
        case 0x11:                      /* -> PHASE_CONNECTED                           */
2035
            /* BUS FREE -> SELECTION */
2036
            host->scsi.phase = PHASE_CONNECTED;
2037
            msgqueue_flush(&host->scsi.msgs);
2038
            host->dma.transferred = host->scsi.SCp.scsi_xferred;
2039
            /* 33C93 gives next interrupt indicating bus phase */
2040
            asr = sbic_arm_read(host->scsi.io_port, ASR);
2041
            if (!(asr & ASR_INT))
2042
                break;
2043
            ssr = sbic_arm_read(host->scsi.io_port, SSR);
2044
            ADD_STATUS(8, ssr, host->scsi.phase, 1);
2045
            ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, 1);
2046
            goto connected;
2047
 
2048
        case 0x42:                      /* select timed out                             */
2049
                                        /* -> PHASE_IDLE                                */
2050
            acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT);
2051
            return INTR_NEXT_COMMAND;
2052
 
2053
        case 0x81:                      /* -> PHASE_RECONNECTED or PHASE_ABORTED        */
2054
            /* BUS FREE -> RESELECTION */
2055
            host->origSCpnt = host->SCpnt;
2056
            host->SCpnt = NULL;
2057
            msgqueue_flush(&host->scsi.msgs);
2058
            acornscsi_reconnect(host);
2059
            break;
2060
 
2061
        default:
2062
            printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",
2063
                    host->host->host_no, acornscsi_target(host), ssr);
2064
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2065
            acornscsi_abortcmd(host, host->SCpnt->tag);
2066
        }
2067
        return INTR_PROCESSING;
2068
 
2069
    connected:
2070
    case PHASE_CONNECTED:               /* STATE: device selected ok                    */
2071
        switch (ssr) {
2072
#ifdef NONSTANDARD
2073
        case 0x8a:                      /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED        */
2074
            /* SELECTION -> COMMAND */
2075
            acornscsi_sendcommand(host);
2076
            break;
2077
 
2078
        case 0x8b:                      /* -> PHASE_STATUS                              */
2079
            /* SELECTION -> STATUS */
2080
            acornscsi_readstatusbyte(host);
2081
            host->scsi.phase = PHASE_STATUSIN;
2082
            break;
2083
#endif
2084
 
2085
        case 0x8e:                      /* -> PHASE_MSGOUT                              */
2086
            /* SELECTION ->MESSAGE OUT */
2087
            host->scsi.phase = PHASE_MSGOUT;
2088
            acornscsi_buildmessages(host);
2089
            acornscsi_sendmessage(host);
2090
            break;
2091
 
2092
        /* these should not happen */
2093
        case 0x85:                      /* target disconnected                          */
2094
            acornscsi_done(host, &host->SCpnt, DID_ERROR);
2095
            break;
2096
 
2097
        default:
2098
            printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",
2099
                    host->host->host_no, acornscsi_target(host), ssr);
2100
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2101
            acornscsi_abortcmd(host, host->SCpnt->tag);
2102
        }
2103
        return INTR_PROCESSING;
2104
 
2105
    case PHASE_MSGOUT:                  /* STATE: connected & sent IDENTIFY message     */
2106
        /*
2107
         * SCSI standard says that MESSAGE OUT phases can be followed by a
2108
         * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase
2109
         */
2110
        switch (ssr) {
2111
        case 0x8a:                      /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED        */
2112
        case 0x1a:                      /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED        */
2113
            /* MESSAGE OUT -> COMMAND */
2114
            acornscsi_sendcommand(host);
2115
            break;
2116
 
2117
        case 0x8b:                      /* -> PHASE_STATUS                              */
2118
        case 0x1b:                      /* -> PHASE_STATUS                              */
2119
            /* MESSAGE OUT -> STATUS */
2120
            acornscsi_readstatusbyte(host);
2121
            host->scsi.phase = PHASE_STATUSIN;
2122
            break;
2123
 
2124
        case 0x8e:                      /* -> PHASE_MSGOUT                              */
2125
            /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */
2126
            acornscsi_sendmessage(host);
2127
            break;
2128
 
2129
        case 0x4f:                      /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
2130
        case 0x1f:                      /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
2131
            /* MESSAGE OUT -> MESSAGE IN */
2132
            acornscsi_message(host);
2133
            break;
2134
 
2135
        default:
2136
            printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",
2137
                    host->host->host_no, acornscsi_target(host), ssr);
2138
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2139
/*DEBUG*/   printk(KERN_ERR "last message = %X\n", host->device[0].sync_xfer);
2140
        }
2141
        return INTR_PROCESSING;
2142
 
2143
    case PHASE_COMMAND:                 /* STATE: connected & command sent              */
2144
        switch (ssr) {
2145
        case 0x88:                      /* -> PHASE_DATAOUT                             */
2146
        case 0x18:                      /* -> PHASE_DATAOUT                             */
2147
            /* COMMAND -> DATA OUT */
2148
            if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
2149
                acornscsi_abortcmd(host, host->SCpnt->tag);
2150
            acornscsi_dma_setup(host, DMA_OUT);
2151
            if (!acornscsi_starttransfer(host))
2152
                acornscsi_abortcmd(host, host->SCpnt->tag);
2153
            host->scsi.phase = PHASE_DATAOUT;
2154
            return INTR_IDLE;
2155
 
2156
        case 0x89:                      /* -> PHASE_DATAIN                              */
2157
        case 0x19:                      /* -> PHASE_DATAIN                              */
2158
            /* COMMAND -> DATA IN */
2159
            if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
2160
                acornscsi_abortcmd(host, host->SCpnt->tag);
2161
            acornscsi_dma_setup(host, DMA_IN);
2162
            if (!acornscsi_starttransfer(host))
2163
                acornscsi_abortcmd(host, host->SCpnt->tag);
2164
            host->scsi.phase = PHASE_DATAIN;
2165
            return INTR_IDLE;
2166
 
2167
        case 0x8b:                      /* -> PHASE_STATUS                              */
2168
        case 0x1b:                      /* -> PHASE_STATUS                              */
2169
            /* COMMAND -> STATUS */
2170
            acornscsi_readstatusbyte(host);
2171
            host->scsi.phase = PHASE_STATUSIN;
2172
            break;
2173
 
2174
        case 0x8e:                      /* -> PHASE_MSGOUT                              */
2175
        case 0x1e:                      /* -> PHASE_MSGOUT                              */
2176
            /* COMMAND -> MESSAGE OUT */
2177
            acornscsi_sendmessage(host);
2178
            break;
2179
 
2180
        case 0x8f:                      /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
2181
        case 0x1f:                      /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
2182
            /* COMMAND -> MESSAGE IN */
2183
            acornscsi_message(host);
2184
            break;
2185
 
2186
        default:
2187
            printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",
2188
                    host->host->host_no, acornscsi_target(host), ssr);
2189
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2190
        }
2191
        return INTR_PROCESSING;
2192
 
2193
    case PHASE_DISCONNECT:              /* STATE: connected, received DISCONNECT msg    */
2194
        if (ssr == 0x85) {              /* -> PHASE_IDLE                                */
2195
            host->scsi.disconnectable = 1;
2196
            host->scsi.reconnected.tag = 0;
2197
            host->scsi.phase = PHASE_IDLE;
2198
            host->stats.disconnects += 1;
2199
        } else {
2200
            printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",
2201
                    host->host->host_no, acornscsi_target(host), ssr);
2202
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2203
        }
2204
        return INTR_NEXT_COMMAND;
2205
 
2206
    case PHASE_IDLE:                    /* STATE: disconnected                          */
2207
        if (ssr == 0x81)                /* -> PHASE_RECONNECTED or PHASE_ABORTED        */
2208
            acornscsi_reconnect(host);
2209
        else {
2210
            printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",
2211
                    host->host->host_no, acornscsi_target(host), ssr);
2212
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2213
        }
2214
        return INTR_PROCESSING;
2215
 
2216
    case PHASE_RECONNECTED:             /* STATE: device reconnected to initiator       */
2217
        /*
2218
         * Command reconnected - if MESGIN, get message - it may be
2219
         * the tag.  If not, get command out of disconnected queue
2220
         */
2221
        /*
2222
         * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY,
2223
         * reconnect I_T_L command
2224
         */
2225
        if (ssr != 0x8f && !acornscsi_reconnect_finish(host))
2226
            return INTR_IDLE;
2227
        ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq);
2228
        switch (ssr) {
2229
        case 0x88:                      /* data out phase                               */
2230
                                        /* -> PHASE_DATAOUT                             */
2231
            /* MESSAGE IN -> DATA OUT */
2232
            acornscsi_dma_setup(host, DMA_OUT);
2233
            if (!acornscsi_starttransfer(host))
2234
                acornscsi_abortcmd(host, host->SCpnt->tag);
2235
            host->scsi.phase = PHASE_DATAOUT;
2236
            return INTR_IDLE;
2237
 
2238
        case 0x89:                      /* data in phase                                */
2239
                                        /* -> PHASE_DATAIN                              */
2240
            /* MESSAGE IN -> DATA IN */
2241
            acornscsi_dma_setup(host, DMA_IN);
2242
            if (!acornscsi_starttransfer(host))
2243
                acornscsi_abortcmd(host, host->SCpnt->tag);
2244
            host->scsi.phase = PHASE_DATAIN;
2245
            return INTR_IDLE;
2246
 
2247
        case 0x8a:                      /* command out                                  */
2248
            /* MESSAGE IN -> COMMAND */
2249
            acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED        */
2250
            break;
2251
 
2252
        case 0x8b:                      /* status in                                    */
2253
                                        /* -> PHASE_STATUSIN                            */
2254
            /* MESSAGE IN -> STATUS */
2255
            acornscsi_readstatusbyte(host);
2256
            host->scsi.phase = PHASE_STATUSIN;
2257
            break;
2258
 
2259
        case 0x8e:                      /* message out                                  */
2260
                                        /* -> PHASE_MSGOUT                              */
2261
            /* MESSAGE IN -> MESSAGE OUT */
2262
            acornscsi_sendmessage(host);
2263
            break;
2264
 
2265
        case 0x8f:                      /* message in                                   */
2266
            acornscsi_message(host);    /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
2267
            break;
2268
 
2269
        default:
2270
            printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n",
2271
                    host->host->host_no, acornscsi_target(host), ssr);
2272
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2273
        }
2274
        return INTR_PROCESSING;
2275
 
2276
    case PHASE_DATAIN:                  /* STATE: transferred data in                   */
2277
        /*
2278
         * This is simple - if we disconnect then the DMA address & count is
2279
         * correct.
2280
         */
2281
        switch (ssr) {
2282
        case 0x19:                      /* -> PHASE_DATAIN                              */
2283
        case 0x89:                      /* -> PHASE_DATAIN                              */
2284
            acornscsi_abortcmd(host, host->SCpnt->tag);
2285
            return INTR_IDLE;
2286
 
2287
        case 0x1b:                      /* -> PHASE_STATUSIN                            */
2288
        case 0x4b:                      /* -> PHASE_STATUSIN                            */
2289
        case 0x8b:                      /* -> PHASE_STATUSIN                            */
2290
            /* DATA IN -> STATUS */
2291
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
2292
                                          acornscsi_sbic_xfcount(host);
2293
            acornscsi_dma_stop(host);
2294
            acornscsi_readstatusbyte(host);
2295
            host->scsi.phase = PHASE_STATUSIN;
2296
            break;
2297
 
2298
        case 0x1e:                      /* -> PHASE_MSGOUT                              */
2299
        case 0x4e:                      /* -> PHASE_MSGOUT                              */
2300
        case 0x8e:                      /* -> PHASE_MSGOUT                              */
2301
            /* DATA IN -> MESSAGE OUT */
2302
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
2303
                                          acornscsi_sbic_xfcount(host);
2304
            acornscsi_dma_stop(host);
2305
            acornscsi_sendmessage(host);
2306
            break;
2307
 
2308
        case 0x1f:                      /* message in                                   */
2309
        case 0x4f:                      /* message in                                   */
2310
        case 0x8f:                      /* message in                                   */
2311
            /* DATA IN -> MESSAGE IN */
2312
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
2313
                                          acornscsi_sbic_xfcount(host);
2314
            acornscsi_dma_stop(host);
2315
            acornscsi_message(host);    /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
2316
            break;
2317
 
2318
        default:
2319
            printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n",
2320
                    host->host->host_no, acornscsi_target(host), ssr);
2321
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2322
        }
2323
        return INTR_PROCESSING;
2324
 
2325
    case PHASE_DATAOUT:                 /* STATE: transferred data out                  */
2326
        /*
2327
         * This is more complicated - if we disconnect, the DMA could be 12
2328
         * bytes ahead of us.  We need to correct this.
2329
         */
2330
        switch (ssr) {
2331
        case 0x18:                      /* -> PHASE_DATAOUT                             */
2332
        case 0x88:                      /* -> PHASE_DATAOUT                             */
2333
            acornscsi_abortcmd(host, host->SCpnt->tag);
2334
            return INTR_IDLE;
2335
 
2336
        case 0x1b:                      /* -> PHASE_STATUSIN                            */
2337
        case 0x4b:                      /* -> PHASE_STATUSIN                            */
2338
        case 0x8b:                      /* -> PHASE_STATUSIN                            */
2339
            /* DATA OUT -> STATUS */
2340
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
2341
                                          acornscsi_sbic_xfcount(host);
2342
            acornscsi_dma_stop(host);
2343
            acornscsi_dma_adjust(host);
2344
            acornscsi_readstatusbyte(host);
2345
            host->scsi.phase = PHASE_STATUSIN;
2346
            break;
2347
 
2348
        case 0x1e:                      /* -> PHASE_MSGOUT                              */
2349
        case 0x4e:                      /* -> PHASE_MSGOUT                              */
2350
        case 0x8e:                      /* -> PHASE_MSGOUT                              */
2351
            /* DATA OUT -> MESSAGE OUT */
2352
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
2353
                                          acornscsi_sbic_xfcount(host);
2354
            acornscsi_dma_stop(host);
2355
            acornscsi_dma_adjust(host);
2356
            acornscsi_sendmessage(host);
2357
            break;
2358
 
2359
        case 0x1f:                      /* message in                                   */
2360
        case 0x4f:                      /* message in                                   */
2361
        case 0x8f:                      /* message in                                   */
2362
            /* DATA OUT -> MESSAGE IN */
2363
            host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
2364
                                          acornscsi_sbic_xfcount(host);
2365
            acornscsi_dma_stop(host);
2366
            acornscsi_dma_adjust(host);
2367
            acornscsi_message(host);    /* -> PHASE_MSGIN, PHASE_DISCONNECT             */
2368
            break;
2369
 
2370
        default:
2371
            printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n",
2372
                    host->host->host_no, acornscsi_target(host), ssr);
2373
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2374
        }
2375
        return INTR_PROCESSING;
2376
 
2377
    case PHASE_STATUSIN:                /* STATE: status in complete                    */
2378
        switch (ssr) {
2379
        case 0x1f:                      /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
2380
        case 0x8f:                      /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
2381
            /* STATUS -> MESSAGE IN */
2382
            acornscsi_message(host);
2383
            break;
2384
 
2385
        case 0x1e:                      /* -> PHASE_MSGOUT                              */
2386
        case 0x8e:                      /* -> PHASE_MSGOUT                              */
2387
            /* STATUS -> MESSAGE OUT */
2388
            acornscsi_sendmessage(host);
2389
            break;
2390
 
2391
        default:
2392
            printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n",
2393
                    host->host->host_no, acornscsi_target(host), ssr);
2394
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2395
        }
2396
        return INTR_PROCESSING;
2397
 
2398
    case PHASE_MSGIN:                   /* STATE: message in                            */
2399
        switch (ssr) {
2400
        case 0x1e:                      /* -> PHASE_MSGOUT                              */
2401
        case 0x4e:                      /* -> PHASE_MSGOUT                              */
2402
        case 0x8e:                      /* -> PHASE_MSGOUT                              */
2403
            /* MESSAGE IN -> MESSAGE OUT */
2404
            acornscsi_sendmessage(host);
2405
            break;
2406
 
2407
        case 0x1f:                      /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
2408
        case 0x2f:
2409
        case 0x4f:
2410
        case 0x8f:
2411
            acornscsi_message(host);
2412
            break;
2413
 
2414
        case 0x85: /* Strange disconnection with some drives */
2415
/*DEBUG*/   printk(KERN_ERR "Strange message in disconnection, last message = %X\n", host->device[0].sync_xfer);
2416
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2417
            acornscsi_done(host, &host->SCpnt, DID_ERROR);
2418
            break;
2419
 
2420
        default:
2421
            printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n",
2422
                    host->host->host_no, acornscsi_target(host), ssr);
2423
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2424
        }
2425
        return INTR_PROCESSING;
2426
 
2427
    case PHASE_DONE:                    /* STATE: received status & message             */
2428
        switch (ssr) {
2429
        case 0x85:                      /* -> PHASE_IDLE                                */
2430
            acornscsi_done(host, &host->SCpnt, DID_OK);
2431
            return INTR_NEXT_COMMAND;
2432
 
2433
        case 0x1e:
2434
        case 0x8e:
2435
            acornscsi_sendmessage(host);
2436
            break;
2437
 
2438
        default:
2439
            printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n",
2440
                    host->host->host_no, acornscsi_target(host), ssr);
2441
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2442
        }
2443
        return INTR_PROCESSING;
2444
 
2445
    case PHASE_ABORTED:
2446
        switch (ssr) {
2447
        case 0x85:
2448
            if (host->SCpnt)
2449
                acornscsi_done(host, &host->SCpnt, DID_ABORT);
2450
            else {
2451
                clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun,
2452
                          host->busyluns);
2453
                host->scsi.phase = PHASE_IDLE;
2454
            }
2455
            return INTR_NEXT_COMMAND;
2456
 
2457
        case 0x1e:
2458
        case 0x2e:
2459
        case 0x4e:
2460
        case 0x8e:
2461
            acornscsi_sendmessage(host);
2462
            break;
2463
 
2464
        default:
2465
            printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n",
2466
                    host->host->host_no, acornscsi_target(host), ssr);
2467
            acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2468
        }
2469
        return INTR_PROCESSING;
2470
 
2471
    default:
2472
        printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n",
2473
                host->host->host_no, acornscsi_target(host), ssr);
2474
        acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->target : 8);
2475
    }
2476
    return INTR_PROCESSING;
2477
}
2478
 
2479
/*
2480
 * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
2481
 * Purpose  : handle interrupts from Acorn SCSI card
2482
 * Params   : irq    - interrupt number
2483
 *            dev_id - device specific data (AS_Host structure)
2484
 *            regs   - processor registers when interrupt occurred
2485
 */
2486
static
2487
void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
2488
{
2489
    AS_Host *host = (AS_Host *)dev_id;
2490
    intr_ret_t ret;
2491
    int iostatus;
2492
    int in_irq = 0;
2493
 
2494
    if (host->scsi.interrupt)
2495
        printk("scsi%d: interrupt re-entered\n", host->host->host_no);
2496
    host->scsi.interrupt = 1;
2497
 
2498
    do {
2499
        ret = INTR_IDLE;
2500
 
2501
        iostatus = inb(host->card.io_intr);
2502
 
2503
        if (iostatus & 2) {
2504
            acornscsi_dma_intr(host);
2505
            iostatus = inb(host->card.io_intr);
2506
        }
2507
 
2508
        if (iostatus & 8)
2509
            ret = acornscsi_sbicintr(host, in_irq);
2510
 
2511
        /*
2512
         * If we have a transfer pending, start it.
2513
         * Only start it if the interface has already started transferring
2514
         * it's data
2515
         */
2516
        if (host->dma.xfer_required)
2517
            acornscsi_dma_xfer(host);
2518
 
2519
        if (ret == INTR_NEXT_COMMAND)
2520
            ret = acornscsi_kick(host);
2521
 
2522
        in_irq = 1;
2523
    } while (ret != INTR_IDLE);
2524
 
2525
    host->scsi.interrupt = 0;
2526
}
2527
 
2528
/*=============================================================================================
2529
 * Interfaces between interrupt handler and rest of scsi code
2530
 */
2531
 
2532
/*
2533
 * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
2534
 * Purpose  : queues a SCSI command
2535
 * Params   : cmd  - SCSI command
2536
 *            done - function called on completion, with pointer to command descriptor
2537
 * Returns  : 0, or < 0 on error.
2538
 */
2539
int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
2540
{
2541
    AS_Host *host = (AS_Host *)SCpnt->host->hostdata;
2542
 
2543
    if (!done) {
2544
        /* there should be some way of rejecting errors like this without panicing... */
2545
        panic("scsi%d: queuecommand called with NULL done function [cmd=%p]",
2546
                SCpnt->host->host_no, SCpnt);
2547
        return -EINVAL;
2548
    }
2549
 
2550
#if (DEBUG & DEBUG_NO_WRITE)
2551
    if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) {
2552
        printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",
2553
            SCpnt->host->host_no, '0' + SCpnt->target);
2554
        SCpnt->result = DID_NO_CONNECT << 16;
2555
        done(SCpnt);
2556
        return 0;
2557
    }
2558
#endif
2559
 
2560
    SCpnt->scsi_done = done;
2561
    SCpnt->host_scribble = NULL;
2562
    SCpnt->result = 0;
2563
    SCpnt->tag = 0;
2564
    SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]);
2565
    SCpnt->SCp.sent_command = 0;
2566
    SCpnt->SCp.scsi_xferred = 0;
2567
    SCpnt->SCp.Status = 0;
2568
    SCpnt->SCp.Message = 0;
2569
 
2570
    if (SCpnt->use_sg) {
2571
        SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
2572
        SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
2573
        SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address;
2574
        SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
2575
    } else {
2576
        SCpnt->SCp.buffer = NULL;
2577
        SCpnt->SCp.buffers_residual = 0;
2578
        SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
2579
        SCpnt->SCp.this_residual = SCpnt->request_bufflen;
2580
    }
2581
 
2582
    host->stats.queues += 1;
2583
 
2584
    {
2585
        unsigned long flags;
2586
 
2587
        if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) {
2588
            SCpnt->result = DID_ERROR << 16;
2589
            done(SCpnt);
2590
            return 0;
2591
        }
2592
        save_flags_cli(flags);
2593
        if (host->scsi.phase == PHASE_IDLE)
2594
            acornscsi_kick(host);
2595
        restore_flags(flags);
2596
    }
2597
    return 0;
2598
}
2599
 
2600
/*
2601
 * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
2602
 * Purpose  : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
2603
 * Params   : SCpntp1 - pointer to command to return
2604
 *            SCpntp2 - pointer to command to check
2605
 *            result  - result to pass back to mid-level done function
2606
 * Returns  : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
2607
 */
2608
static inline
2609
void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
2610
{
2611
    Scsi_Cmnd *SCpnt = *SCpntp1;
2612
 
2613
    if (SCpnt) {
2614
        *SCpntp1 = NULL;
2615
 
2616
        SCpnt->result = result;
2617
        SCpnt->scsi_done(SCpnt);
2618
    }
2619
 
2620
    if (SCpnt == *SCpntp2)
2621
        *SCpntp2 = NULL;
2622
}
2623
 
2624
enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
2625
 
2626
/*
2627
 * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
2628
 * Purpose  : abort a command on this host
2629
 * Params   : SCpnt - command to abort
2630
 * Returns  : our abort status
2631
 */
2632
static enum res_abort
2633
acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
2634
{
2635
        enum res_abort res = res_not_running;
2636
 
2637
        if (queue_removecmd(&host->queues.issue, SCpnt)) {
2638
                /*
2639
                 * The command was on the issue queue, and has not been
2640
                 * issued yet.  We can remove the command from the queue,
2641
                 * and acknowledge the abort.  Neither the devices nor the
2642
                 * interface know about the command.
2643
                 */
2644
//#if (DEBUG & DEBUG_ABORT)
2645
                printk("on issue queue ");
2646
//#endif
2647
                res = res_success;
2648
        } else if (queue_removecmd(&host->queues.disconnected, SCpnt)) {
2649
                /*
2650
                 * The command was on the disconnected queue.  Simply
2651
                 * acknowledge the abort condition, and when the target
2652
                 * reconnects, we will give it an ABORT message.  The
2653
                 * target should then disconnect, and we will clear
2654
                 * the busylun bit.
2655
                 */
2656
//#if (DEBUG & DEBUG_ABORT)
2657
                printk("on disconnected queue ");
2658
//#endif
2659
                res = res_success;
2660
        } else if (host->SCpnt == SCpnt) {
2661
                unsigned long flags;
2662
 
2663
//#if (DEBUG & DEBUG_ABORT)
2664
                printk("executing ");
2665
//#endif
2666
 
2667
                save_flags(flags);
2668
                cli();
2669
                switch (host->scsi.phase) {
2670
                /*
2671
                 * If the interface is idle, and the command is 'disconnectable',
2672
                 * then it is the same as on the disconnected queue.  We simply
2673
                 * remove all traces of the command.  When the target reconnects,
2674
                 * we will give it an ABORT message since the command could not
2675
                 * be found.  When the target finally disconnects, we will clear
2676
                 * the busylun bit.
2677
                 */
2678
                case PHASE_IDLE:
2679
                        if (host->scsi.disconnectable) {
2680
                                host->scsi.disconnectable = 0;
2681
                                host->SCpnt = NULL;
2682
                                res = res_success;
2683
                        }
2684
                        break;
2685
 
2686
                /*
2687
                 * If the command has connected and done nothing further,
2688
                 * simply force a disconnect.  We also need to clear the
2689
                 * busylun bit.
2690
                 */
2691
                case PHASE_CONNECTED:
2692
                sbic_arm_write(host->scsi.io_port, CMND, CMND_DISCONNECT);
2693
                host->SCpnt = NULL;
2694
                res = res_success_clear;
2695
                break;
2696
 
2697
                default:
2698
                        acornscsi_abortcmd(host, host->SCpnt->tag);
2699
                        res = res_snooze;
2700
                }
2701
                restore_flags(flags);
2702
        } else if (host->origSCpnt == SCpnt) {
2703
                /*
2704
                 * The command will be executed next, but a command
2705
                 * is currently using the interface.  This is similar to
2706
                 * being on the issue queue, except the busylun bit has
2707
                 * been set.
2708
                 */
2709
                host->origSCpnt = NULL;
2710
//#if (DEBUG & DEBUG_ABORT)
2711
                printk("waiting for execution ");
2712
//#endif
2713
                res = res_success_clear;
2714
        } else
2715
                printk("unknown ");
2716
 
2717
        return res;
2718
}
2719
 
2720
/*
2721
 * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
2722
 * Purpose  : abort a command on this host
2723
 * Params   : SCpnt - command to abort
2724
 * Returns  : one of SCSI_ABORT_ macros
2725
 */
2726
int acornscsi_abort(Scsi_Cmnd *SCpnt)
2727
{
2728
        AS_Host *host = (AS_Host *) SCpnt->host->hostdata;
2729
        int result;
2730
 
2731
        host->stats.aborts += 1;
2732
 
2733
#if (DEBUG & DEBUG_ABORT)
2734
        {
2735
                int asr, ssr;
2736
                asr = sbic_arm_read(host->scsi.io_port, ASR);
2737
                ssr = sbic_arm_read(host->scsi.io_port, SSR);
2738
 
2739
                printk(KERN_WARNING "acornscsi_abort: ");
2740
                print_sbic_status(asr, ssr, host->scsi.phase);
2741
                acornscsi_dumplog(host, SCpnt->target);
2742
        }
2743
#endif
2744
 
2745
        printk("scsi%d: ", host->host->host_no);
2746
 
2747
        switch (acornscsi_do_abort(host, SCpnt)) {
2748
        /*
2749
         * We managed to find the command and cleared it out.
2750
         * We do not expect the command to be executing on the
2751
         * target, but we have set the busylun bit.
2752
         */
2753
        case res_success_clear:
2754
                clear_bit(SCpnt->target * 8 + SCpnt->lun, host->busyluns);
2755
//#if (DEBUG & DEBUG_ABORT)
2756
                printk("clear ");
2757
//#endif
2758
 
2759
        /*
2760
         * We found the command, and cleared it out.  Either
2761
         * the command is still known to be executing on the
2762
         * target, or the busylun bit is not set.
2763
         */
2764
        case res_success:
2765
                SCpnt->result = DID_ABORT << 16;
2766
                SCpnt->scsi_done(SCpnt);
2767
                result = SCSI_ABORT_SUCCESS;
2768
//#if (DEBUG & DEBUG_ABORT)
2769
                printk("success\n");
2770
//#endif
2771
                break;
2772
 
2773
        /*
2774
         * We did find the command, but unfortunately we couldn't
2775
         * unhook it from ourselves.  Wait some more, and if it
2776
         * still doesn't complete, reset the interface.
2777
         */
2778
        case res_snooze:
2779
                result = SCSI_ABORT_SNOOZE;
2780
//#if (DEBUG & DEBUG_ABORT)
2781
                printk("snooze\n");
2782
//#endif
2783
                break;
2784
 
2785
        /*
2786
         * The command could not be found (either because it completed,
2787
         * or it got dropped.
2788
         */
2789
        default:
2790
        case res_not_running:
2791
                acornscsi_dumplog(host, SCpnt->target);
2792
#if (DEBUG & DEBUG_ABORT)
2793
                result = SCSI_ABORT_SNOOZE;
2794
#else
2795
                result = SCSI_ABORT_NOT_RUNNING;
2796
#endif
2797
//#if (DEBUG & DEBUG_ABORT)
2798
                printk("not running\n");
2799
//#endif
2800
                break;
2801
        }
2802
 
2803
        return result;
2804
}
2805
 
2806
/*
2807
 * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
2808
 * Purpose  : reset a command on this host/reset this host
2809
 * Params   : SCpnt  - command causing reset
2810
 *            result - what type of reset to perform
2811
 * Returns  : one of SCSI_RESET_ macros
2812
 */
2813
int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
2814
{
2815
    AS_Host *host = (AS_Host *)SCpnt->host->hostdata;
2816
    Scsi_Cmnd *SCptr;
2817
 
2818
    host->stats.resets += 1;
2819
 
2820
#if (DEBUG & DEBUG_RESET)
2821
    {
2822
        int asr, ssr;
2823
 
2824
        asr = sbic_arm_read(host->scsi.io_port, ASR);
2825
        ssr = sbic_arm_read(host->scsi.io_port, SSR);
2826
 
2827
        printk(KERN_WARNING "acornscsi_reset: ");
2828
        print_sbic_status(asr, ssr, host->scsi.phase);
2829
        acornscsi_dumplog(host, SCpnt->target);
2830
    }
2831
#endif
2832
 
2833
    acornscsi_dma_stop(host);
2834
 
2835
    SCptr = host->SCpnt;
2836
 
2837
    /*
2838
     * do hard reset.  This resets all devices on this host, and so we
2839
     * must set the reset status on all commands.
2840
     */
2841
    acornscsi_resetcard(host);
2842
 
2843
    /*
2844
     * report reset on commands current connected/disconnected
2845
     */
2846
    acornscsi_reportstatus(&host->SCpnt, &SCptr, DID_NO_CONNECT/*RESET*/);
2847
 
2848
    while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL)
2849
        acornscsi_reportstatus(&SCptr, &SCpnt, DID_NO_CONNECT/*RESET*/);
2850
 
2851
    if (SCpnt) {
2852
        SCpnt->result = DID_NO_CONNECT/*RESET*/ << 16;
2853
        SCpnt->scsi_done(SCpnt);
2854
    }
2855
 
2856
    return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS;
2857
}
2858
 
2859
/*==============================================================================================
2860
 * initialisation & miscellaneous support
2861
 */
2862
static struct expansion_card *ecs[MAX_ECARDS];
2863
 
2864
/*
2865
 * Prototype: void acornscsi_init(AS_Host *host)
2866
 * Purpose  : initialise the AS_Host structure for one interface & setup hardware
2867
 * Params   : host - host to setup
2868
 */
2869
static
2870
void acornscsi_init(AS_Host *host)
2871
{
2872
    memset(&host->stats, 0, sizeof (host->stats));
2873
    queue_initialise(&host->queues.issue);
2874
    queue_initialise(&host->queues.disconnected);
2875
    msgqueue_initialise(&host->scsi.msgs);
2876
 
2877
    acornscsi_resetcard(host);
2878
}
2879
 
2880
int acornscsi_detect(Scsi_Host_Template * tpnt)
2881
{
2882
    static const card_ids acornscsi_cids[] = { ACORNSCSI_LIST, { 0xffff, 0xffff } };
2883
    int i, count = 0;
2884
    struct Scsi_Host *instance;
2885
    AS_Host *host;
2886
 
2887
    tpnt->proc_dir = &proc_scsi_acornscsi;
2888
 
2889
    for (i = 0; i < MAX_ECARDS; i++)
2890
        ecs[i] = NULL;
2891
 
2892
    ecard_startfind();
2893
 
2894
    while(1) {
2895
        ecs[count] = ecard_find(0, acornscsi_cids);
2896
        if (!ecs[count])
2897
            break;
2898
 
2899
        if (ecs[count]->irq == 0xff) {
2900
            printk("scsi: WD33C93 does not have IRQ enabled - ignoring\n");
2901
            continue;
2902
        }
2903
 
2904
        ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */
2905
 
2906
        instance = scsi_register(tpnt, sizeof(AS_Host));
2907
        host = (AS_Host *)instance->hostdata;
2908
 
2909
        instance->io_port = ecard_address(ecs[count], ECARD_MEMC, 0);
2910
        instance->irq = ecs[count]->irq;
2911
 
2912
        host->host              = instance;
2913
        host->scsi.io_port      = ioaddr(instance->io_port + 0x800);
2914
        host->scsi.irq          = instance->irq;
2915
        host->card.io_intr      = POD_SPACE(instance->io_port) + 0x800;
2916
        host->card.io_page      = POD_SPACE(instance->io_port) + 0xc00;
2917
        host->card.io_ram       = ioaddr(instance->io_port);
2918
        host->dma.io_port       = instance->io_port + 0xc00;
2919
        host->dma.io_intr_clear = POD_SPACE(instance->io_port) + 0x800;
2920
 
2921
        ecs[count]->irqaddr     = (char *)ioaddr(host->card.io_intr);
2922
        ecs[count]->irqmask     = 0x0a;
2923
 
2924
        request_region(instance->io_port + 0x800,  2, "acornscsi(sbic)");
2925
        request_region(host->card.io_intr,  1, "acornscsi(intr)");
2926
        request_region(host->card.io_page,  1, "acornscsi(page)");
2927
#ifdef USE_DMAC
2928
        request_region(host->dma.io_port, 256, "acornscsi(dmac)");
2929
#endif
2930
        request_region(instance->io_port, 2048, "acornscsi(ram)");
2931
 
2932
        if (request_irq(host->scsi.irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", host)) {
2933
            printk(KERN_CRIT "scsi%d: IRQ%d not free, interrupts disabled\n",
2934
                instance->host_no, host->scsi.irq);
2935
            host->scsi.irq = NO_IRQ;
2936
        }
2937
 
2938
        acornscsi_init(host);
2939
 
2940
        ++count;
2941
    }
2942
    return count;
2943
}
2944
 
2945
/*
2946
 * Function: int acornscsi_release(struct Scsi_Host *host)
2947
 * Purpose : release all resources used by this adapter
2948
 * Params  : host - driver structure to release
2949
 * Returns : nothing of any consequence
2950
 */
2951
int acornscsi_release(struct Scsi_Host *instance)
2952
{
2953
    AS_Host *host = (AS_Host *)instance->hostdata;
2954
    int i;
2955
 
2956
    /*
2957
     * Put card into RESET state
2958
     */
2959
    outb(0x80, host->card.io_page);
2960
 
2961
    if (host->scsi.irq != NO_IRQ)
2962
        free_irq(host->scsi.irq, host);
2963
 
2964
    release_region(instance->io_port + 0x800, 2);
2965
    release_region(host->card.io_intr, 1);
2966
    release_region(host->card.io_page, 1);
2967
    release_region(host->dma.io_port, 256);
2968
    release_region(instance->io_port, 2048);
2969
 
2970
    for (i = 0; i < MAX_ECARDS; i++)
2971
        if (ecs[i] && instance->io_port == ecard_address(ecs[i], ECARD_MEMC, 0))
2972
            ecard_release(ecs[i]);
2973
 
2974
    msgqueue_free(&host->scsi.msgs);
2975
    queue_free(&host->queues.disconnected);
2976
    queue_free(&host->queues.issue);
2977
 
2978
    return 0;
2979
}
2980
 
2981
/*
2982
 * Function: char *acornscsi_info(struct Scsi_Host *host)
2983
 * Purpose : return a string describing this interface
2984
 * Params  : host - host to give information on
2985
 * Returns : a constant string
2986
 */
2987
const
2988
char *acornscsi_info(struct Scsi_Host *host)
2989
{
2990
    static char string[100], *p;
2991
 
2992
    p = string;
2993
 
2994
    p += sprintf(string, "%s at port %X irq %d v%d.%d.%d"
2995
#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
2996
    " SYNC"
2997
#endif
2998
#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
2999
    " TAG"
3000
#endif
3001
#ifdef CONFIG_SCSI_ACORNSCSI_LINK
3002
    " LINK"
3003
#endif
3004
#if (DEBUG & DEBUG_NO_WRITE)
3005
    " NOWRITE ("NO_WRITE_STR")"
3006
#endif
3007
                , host->hostt->name, host->io_port, host->irq,
3008
                VER_MAJOR, VER_MINOR, VER_PATCH);
3009
    return string;
3010
}
3011
 
3012
int acornscsi_proc_info(char *buffer, char **start, off_t offset,
3013
                        int length, int host_no, int inout)
3014
{
3015
    int pos, begin = 0, devidx;
3016
    struct Scsi_Host *instance = scsi_hostlist;
3017
    Scsi_Device *scd = scsi_devices;
3018
    AS_Host *host;
3019
    char *p = buffer;
3020
 
3021
    for (instance = scsi_hostlist;
3022
            instance && instance->host_no != host_no;
3023
                instance = instance->next);
3024
 
3025
    if (inout == 1 || !instance)
3026
        return -EINVAL;
3027
 
3028
    host  = (AS_Host *)instance->hostdata;
3029
 
3030
    p += sprintf(p, "AcornSCSI driver v%d.%d.%d"
3031
#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
3032
    " SYNC"
3033
#endif
3034
#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
3035
    " TAG"
3036
#endif
3037
#ifdef CONFIG_SCSI_ACORNSCSI_LINK
3038
    " LINK"
3039
#endif
3040
#if (DEBUG & DEBUG_NO_WRITE)
3041
    " NOWRITE ("NO_WRITE_STR")"
3042
#endif
3043
                "\n\n", VER_MAJOR, VER_MINOR, VER_PATCH);
3044
 
3045
    p += sprintf(p,     "SBIC: WD33C93A  Address: %08X  IRQ : %d\n",
3046
                        host->scsi.io_port, host->scsi.irq);
3047
#ifdef USE_DMAC
3048
    p += sprintf(p,     "DMAC: uPC71071  Address: %08X  IRQ : %d\n\n",
3049
                        host->dma.io_port, host->scsi.irq);
3050
#endif
3051
 
3052
    p += sprintf(p,     "Statistics:\n"
3053
                        "Queued commands: %-10u    Issued commands: %-10u\n"
3054
                        "Done commands  : %-10u    Reads          : %-10u\n"
3055
                        "Writes         : %-10u    Others         : %-10u\n"
3056
                        "Disconnects    : %-10u    Aborts         : %-10u\n"
3057
                        "Resets         : %-10u\n\nLast phases:",
3058
                        host->stats.queues,             host->stats.removes,
3059
                        host->stats.fins,               host->stats.reads,
3060
                        host->stats.writes,             host->stats.miscs,
3061
                        host->stats.disconnects,        host->stats.aborts,
3062
                        host->stats.resets);
3063
 
3064
    for (devidx = 0; devidx < 9; devidx ++) {
3065
        unsigned int statptr, prev;
3066
 
3067
        p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
3068
        statptr = host->status_ptr[devidx] - 10;
3069
 
3070
        if ((signed int)statptr < 0)
3071
            statptr += STATUS_BUFFER_SIZE;
3072
 
3073
        prev = host->status[devidx][statptr].when;
3074
 
3075
        for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
3076
            if (host->status[devidx][statptr].when) {
3077
                p += sprintf(p, "%c%02X:%02X+%2ld",
3078
                        host->status[devidx][statptr].irq ? '-' : ' ',
3079
                        host->status[devidx][statptr].ph,
3080
                        host->status[devidx][statptr].ssr,
3081
                        (host->status[devidx][statptr].when - prev) < 100 ?
3082
                                (host->status[devidx][statptr].when - prev) : 99);
3083
                prev = host->status[devidx][statptr].when;
3084
            }
3085
        }
3086
    }
3087
 
3088
    devidx = 1;
3089
    p += sprintf(p, "\nAttached devices:");
3090
    while (scd) {
3091
        if (scd->host == instance) {
3092
            int len;
3093
            if (devidx) {
3094
                p += sprintf(p, "\n");
3095
                devidx = 0;
3096
            }
3097
 
3098
            proc_print_scsidevice(scd, p, &len, 0);
3099
            p += len;
3100
 
3101
            p += sprintf(p, "Extensions: ");
3102
 
3103
            if (scd->tagged_supported)
3104
                p += sprintf(p, "TAG %sabled [%d] ",
3105
                        scd->tagged_queue ? "en" : "dis", scd->current_tag);
3106
            p += sprintf(p, "\nTransfers: ");
3107
            if (host->device[scd->id].sync_xfer & 15)
3108
                p += sprintf(p, "sync, offset %d, %d ns\n",
3109
                              host->device[scd->id].sync_xfer & 15,
3110
                              acornscsi_getperiod(host->device[scd->id].sync_xfer));
3111
            else
3112
                p += sprintf(p, "async\n");
3113
 
3114
            pos = p - buffer;
3115
            if (pos + begin < offset) {
3116
                begin += pos;
3117
                p = buffer;
3118
            }
3119
            pos = p - buffer;
3120
            if (pos + begin > offset + length)
3121
                break;
3122
        }
3123
        scd = scd->next;
3124
    }
3125
 
3126
    if (devidx)
3127
        p += sprintf(p, " none\n");
3128
 
3129
    pos = p - buffer;
3130
 
3131
    *start = buffer + (offset - begin);
3132
    pos -= offset - begin;
3133
 
3134
    if (pos > length)
3135
        pos = length;
3136
 
3137
    return pos;
3138
}
3139
 
3140
#ifdef MODULE
3141
 
3142
Scsi_Host_Template driver_template = ACORNSCSI_3;
3143
 
3144
#include "scsi_module.c"
3145
#endif

powered by: WebSVN 2.1.0

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