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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [acorn/] [scsi/] [acornscsi.c] - Blame information for rev 1779

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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