Newer
Older
* NCR 5380 generic driver routines. These should make it *trivial*
* to implement 5380 SCSI drivers under Linux with a non-trantor
* architecture.
*
* Note that these routines also work with NR53c400 family chips.
*
* Copyright 1993, Drew Eckhardt
* For more information, please consult
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
*
* NCR 5380 Family
* SCSI Protocol Controller
* Databook
*
* NCR Microelectronics
* 1635 Aeroplaza Drive
* Colorado Springs, CO 80916
* 1+ (719) 578-3400
* 1+ (800) 334-5454
*/
/*
* ++roman: To port the 5380 driver to the Atari, I had to do some changes in
* this file, too:
*
* - Some of the debug statements were incorrect (undefined variables and the
* like). I fixed that.
*
* - In information_transfer(), I think a #ifdef was wrong. Looking at the
* possible DMA transfer size should also happen for REAL_DMA. I added this
* in the #if statement.
*
* - When using real DMA, information_transfer() should return in a DATAOUT
* phase after starting the DMA. It has nothing more to do.
*
* - The interrupt service routine should run main after end of DMA, too (not
* only after RESELECTION interrupts). Additionally, it should _not_ test
* for more interrupts after running main, since a DMA process may have
* been started and interrupts are turned on now. The new int could happen
* inside the execution of NCR5380_intr(), leading to recursive
* calls.
*
* - I've added a function merge_contiguous_buffers() that tries to
* merge scatter-gather buffers that are located at contiguous
* physical addresses and can be processed with the same DMA setup.
* Since most scatter-gather operations work on a page (4K) of
* 4 buffers (1K), in more than 90% of all cases three interrupts and
* DMA setup actions are saved.
*
* - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
* and USLEEP, because these were messing up readability and will never be
* needed for Atari SCSI.
* - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
* stuff), and 'main' is executed in a bottom half if awoken by an
* interrupt.
*
* - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
* constructs. In my eyes, this made the source rather unreadable, so I
* finally replaced that by the *_PRINTK() macros.
*
*/
/* Adapted for the sun3 by Sam Creasey. */
#include <scsi/scsi_transport_spi.h>
#define LIST(x, y) \
do { \
printk("LINE:%d Adding %p to %p\n", \
__LINE__, (void*)(x), (void*)(y)); \
if ((x) == (y)) \
udelay(5); \
} while (0)
#define REMOVE(w, x, y, z) \
do { \
printk("LINE:%d Removing: %p->%p %p->%p \n", \
__LINE__, (void*)(w), (void*)(x), \
(void*)(y), (void*)(z)); \
if ((x) == (y)) \
udelay(5); \
} while (0)
#else
#define LIST(x,y)
#define REMOVE(w,x,y,z)
#endif
/*
* Design
*
* This is a generic 5380 driver. To use it on a different platform,
* one simply writes appropriate system specific macros (ie, data
* transfer - some PC's will use the I/O bus, 68K's must use
* memory mapped) and drops this file in their 'C' wrapper.
*
* As far as command queueing, two queues are maintained for
* each 5380 in the system - commands that haven't been issued yet,
* and commands that are currently executing. This means that an
* unlimited number of commands may be queued, letting
* more commands propagate from the higher driver levels giving higher
* throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
* allowing multiple commands to propagate all the way to a SCSI-II device
* When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
* piece of hardware that requires you to sit in a loop polling for
* the REQ signal as long as you are connected. Some devices are
* brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
* while doing long seek operations. [...] These
* broken devices are the exception rather than the rule and I'd rather
* spend my time optimizing for the normal case.
*
* Architecture :
*
* At the heart of the design is a coroutine, NCR5380_main,
* which is started from a workqueue for each NCR5380 host in the
* system. It attempts to establish I_T_L or I_T_L_Q nexuses by
* removing the commands from the issue queue and calling
* NCR5380_select() if a nexus is not established.
*
* Once a nexus is established, the NCR5380_information_transfer()
* phase goes through the various phases as instructed by the target.
* if the target goes into MSG IN and sends a DISCONNECT message,
* the command structure is placed into the per instance disconnected
* queue, and NCR5380_main tries to find more work. If the target is
* idle for too long, the system will try to sleep.
*
* If a command has disconnected, eventually an interrupt will trigger,
* calling NCR5380_intr() which will in turn call NCR5380_reselect
* to reestablish a nexus. This will run main if necessary.
*
* On command termination, the done function will be called as
* SCSI pointers are maintained in the SCp field of SCSI command
* structures, being initialized after the command is connected
* in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
* Note that in violation of the standard, an implicit SAVE POINTERS operation
* is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
*/
/*
* Using this file :
* This file a skeleton Linux SCSI driver for the NCR 5380 series
* of chips. To use it, you write an architecture specific functions
* and macros and include this file in your driver.
*
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
* for commands that return with a CHECK CONDITION status.
* DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
* transceivers.
*
* REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
*
* SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
*
* These macros MUST be defined :
* NCR5380_read(register) - read from the specified register
*
* NCR5380_write(register, value) - write to the specific register
* NCR5380_implementation_fields - additional fields needed for this
* specific implementation of the NCR5380
*
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
* Note that the DMA setup functions should return the number of bytes
* that they were able to program the controller for.
*
* Also note that generic i386/PC versions of these macros are
* available as NCR5380_i386_dma_write_setup,
* NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
*
* NCR5380_dma_write_setup(instance, src, count) - initialize
* NCR5380_dma_read_setup(instance, dst, count) - initialize
* NCR5380_dma_residual(instance); - residual count
*
* PSEUDO functions :
* NCR5380_pwrite(instance, src, count)
* NCR5380_pread(instance, dst, count);
*
* The generic driver is initialized by calling NCR5380_init(instance),
* after setting the appropriate host specific fields and ID. If the
* driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
*/
/* Macros ease life... :-) */
#define SETUP_HOSTDATA(in) \
struct NCR5380_hostdata *hostdata = \
(struct NCR5380_hostdata *)(in)->hostdata
#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
#define NEXT(cmd) ((struct scsi_cmnd *)(cmd)->host_scribble)
#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next))
#define NEXTADDR(cmd) ((struct scsi_cmnd **)&(cmd)->host_scribble)
#define HOSTNO instance->host_no
#define H_NO(cmd) (cmd)->device->host->host_no
static int do_abort(struct Scsi_Host *);
static void do_reset(struct Scsi_Host *);
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#ifdef SUPPORT_TAGS
/*
* Functions for handling tagged queuing
* =====================================
*
* ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes:
*
* Using consecutive numbers for the tags is no good idea in my eyes. There
* could be wrong re-usings if the counter (8 bit!) wraps and some early
* command has been preempted for a long time. My solution: a bitfield for
* remembering used tags.
*
* There's also the problem that each target has a certain queue size, but we
* cannot know it in advance :-( We just see a QUEUE_FULL status being
* returned. So, in this case, the driver internal queue size assumption is
* reduced to the number of active tags if QUEUE_FULL is returned by the
* target. The command is returned to the mid-level, but with status changed
* to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
* correctly.
*
* We're also not allowed running tagged commands as long as an untagged
* command is active. And REQUEST SENSE commands after a contingent allegiance
* condition _must_ be untagged. To keep track whether an untagged command has
* been issued, the host->busy array is still employed, as it is without
* support for tagged queuing.
*
* One could suspect that there are possible race conditions between
* is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the
* case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(),
* which already guaranteed to be running at most once. It is also the only
* place where tags/LUNs are allocated. So no other allocation can slip
* between that pair, there could only happen a reselection, which can free a
* tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes
* important: the tag bit must be cleared before 'nr_allocated' is decreased.
*/
static void __init init_tags(struct NCR5380_hostdata *hostdata)
struct tag_alloc *ta;
if (!(hostdata->flags & FLAG_TAGGED_QUEUING))
return;
for (target = 0; target < 8; ++target) {
for (lun = 0; lun < 8; ++lun) {
ta = &hostdata->TagAlloc[target][lun];
bitmap_zero(ta->allocated, MAX_TAGS);
ta->nr_allocated = 0;
/* At the beginning, assume the maximum queue size we could
* support (MAX_TAGS). This value will be decreased if the target
* returns QUEUE_FULL status.
*/
ta->queue_size = MAX_TAGS;
}
}
}
/* Check if we can issue a command to this LUN: First see if the LUN is marked
* busy by an untagged command. If the command should use tagged queuing, also
* check that there is a free tag and the target's queue won't overflow. This
* function should be called with interrupts disabled to avoid race
* conditions.
static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
SETUP_HOSTDATA(cmd->device->host);
if (hostdata->busy[cmd->device->id] & (1 << lun))
return 1;
if (!should_be_tagged ||
!(hostdata->flags & FLAG_TAGGED_QUEUING) ||
!cmd->device->tagged_supported)
if (hostdata->TagAlloc[scmd_id(cmd)][lun].nr_allocated >=
hostdata->TagAlloc[scmd_id(cmd)][lun].queue_size) {
dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d: no free tags\n",
}
/* Allocate a tag for a command (there are no checks anymore, check_lun_busy()
* must be called before!), or reserve the LUN in 'busy' if the command is
* untagged.
*/
static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
SETUP_HOSTDATA(cmd->device->host);
/* If we or the target don't support tagged queuing, allocate the LUN for
* an untagged command.
*/
if (!should_be_tagged ||
!(hostdata->flags & FLAG_TAGGED_QUEUING) ||
!cmd->device->tagged_supported) {
dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d now allocated by untagged "
struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS);
set_bit(cmd->tag, ta->allocated);
ta->nr_allocated++;
dprintk(NDEBUG_TAGS, "scsi%d: using tag %d for target %d lun %d "
"(now %d tags in use)\n",
H_NO(cmd), cmd->tag, cmd->device->id,
}
/* Mark the tag of command 'cmd' as free, or in case of an untagged command,
* unlock the LUN.
*/
static void cmd_free_tag(struct scsi_cmnd *cmd)
SETUP_HOSTDATA(cmd->device->host);
if (cmd->tag == TAG_NONE) {
dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d untagged cmd finished\n",
} else if (cmd->tag >= MAX_TAGS) {
printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
H_NO(cmd), cmd->tag);
} else {
struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
clear_bit(cmd->tag, ta->allocated);
ta->nr_allocated--;
dprintk(NDEBUG_TAGS, "scsi%d: freed tag %d for target %d lun %d\n",
static void free_all_tags(struct NCR5380_hostdata *hostdata)
struct tag_alloc *ta;
if (!(hostdata->flags & FLAG_TAGGED_QUEUING))
return;
for (target = 0; target < 8; ++target) {
for (lun = 0; lun < 8; ++lun) {
ta = &hostdata->TagAlloc[target][lun];
bitmap_zero(ta->allocated, MAX_TAGS);
ta->nr_allocated = 0;
}
}
}
#endif /* SUPPORT_TAGS */
/*
* Function: void merge_contiguous_buffers( struct scsi_cmnd *cmd )
*
* Purpose: Try to merge several scatter-gather requests into one DMA
* transfer. This is possible if the scatter buffers lie on
* physical contiguous addresses.
*
* The command to work on. The first scatter buffer's data are
* assumed to be already transferred into ptr/this_residual.
static void merge_contiguous_buffers(struct scsi_cmnd *cmd)
unsigned long oldlen = cmd->SCp.this_residual;
int cnt = 1;
for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
cmd->SCp.buffers_residual &&
virt_to_phys(sg_virt(&cmd->SCp.buffer[1])) == endaddr;) {
dprintk(NDEBUG_MERGING, "VTOP(%p) == %08lx -> merging\n",
page_address(sg_page(&cmd->SCp.buffer[1])), endaddr);
++cmd->SCp.buffer;
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual += cmd->SCp.buffer->length;
endaddr += cmd->SCp.buffer->length;
}
if (oldlen != cmd->SCp.this_residual)
dprintk(NDEBUG_MERGING, "merged %d buffers from %p, new length %08x\n",
cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
#endif /* !defined(CONFIG_SUN3) */
/**
* initialize_SCp - init the scsi pointer field
* @cmd: command block to set up
* Set up the internal fields in the SCSI command.
static inline void initialize_SCp(struct scsi_cmnd *cmd)
/*
* Initialize the Scsi Pointer field so that all of the commands in the
* various queues are valid.
if (scsi_bufflen(cmd)) {
cmd->SCp.buffer = scsi_sglist(cmd);
cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
/* ++roman: Try to merge some scatter-buffers if they are at
* contiguous physical addresses.
*/
merge_contiguous_buffers(cmd);
} else {
cmd->SCp.buffer = NULL;
cmd->SCp.buffers_residual = 0;
cmd->SCp.ptr = NULL;
cmd->SCp.this_residual = 0;
* NCR5380_poll_politely - wait for chip register value
* @instance: controller to poll
* @reg: 5380 register to poll
* @bit: Bitmask to check
* @val: Value required to exit
* Polls the chip in a reasonably efficient manner waiting for an
* event to occur. After a short quick poll we begin to yield the CPU
* (if possible). In irq contexts the time-out is arbitrarily limited.
* Callers may hold locks as long as they are held in irq mode.
* Returns 0 if event occurred otherwise -ETIMEDOUT.
*/
static int NCR5380_poll_politely(struct Scsi_Host *instance,
int reg, int bit, int val, int wait)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned long deadline = jiffies + wait;
unsigned long n;
/* Busy-wait for up to 10 ms */
n = min(10000U, jiffies_to_usecs(wait));
n *= hostdata->accesses_per_ms;
n /= 1000;
do {
if ((NCR5380_read(reg) & bit) == val)
return 0;
cpu_relax();
} while (n--);
if (irqs_disabled() || in_interrupt())
return -ETIMEDOUT;
/* Repeatedly sleep for 1 ms until deadline */
while (time_is_after_jiffies(deadline)) {
schedule_timeout_uninterruptible(1);
if ((NCR5380_read(reg) & bit) == val)
return 0;
}
return -ETIMEDOUT;
}
#include <linux/delay.h>
#if NDEBUG
static struct {
unsigned char mask;
const char *name;
} signals[] = {
{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
{ SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
{ SR_SEL, "SEL" }, {0, NULL}
}, basrs[] = {
{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}
}, icrs[] = {
{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
{ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
{ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
{0, NULL}
}, mrs[] = {
{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
{MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
"MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
{MR_MONITOR_BSY, "MODE MONITOR BSY"},
{MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
{0, NULL}
};
/**
* NCR5380_print - print scsi bus signals
* @instance: adapter state to dump
* Print the SCSI bus signals for debugging purposes
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
static void NCR5380_print(struct Scsi_Host *instance)
{
unsigned char status, data, basr, mr, icr, i;
unsigned long flags;
local_irq_save(flags);
data = NCR5380_read(CURRENT_SCSI_DATA_REG);
status = NCR5380_read(STATUS_REG);
mr = NCR5380_read(MODE_REG);
icr = NCR5380_read(INITIATOR_COMMAND_REG);
basr = NCR5380_read(BUS_AND_STATUS_REG);
local_irq_restore(flags);
printk("STATUS_REG: %02x ", status);
for (i = 0; signals[i].mask; ++i)
if (status & signals[i].mask)
printk(",%s", signals[i].name);
printk("\nBASR: %02x ", basr);
for (i = 0; basrs[i].mask; ++i)
if (basr & basrs[i].mask)
printk(",%s", basrs[i].name);
printk("\nICR: %02x ", icr);
for (i = 0; icrs[i].mask; ++i)
if (icr & icrs[i].mask)
printk(",%s", icrs[i].name);
printk("\nMODE: %02x ", mr);
for (i = 0; mrs[i].mask; ++i)
if (mr & mrs[i].mask)
printk(",%s", mrs[i].name);
printk("\n");
unsigned char value;
const char *name;
{PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
{PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
{PHASE_UNKNOWN, "UNKNOWN"}
};
/**
* NCR5380_print_phase - show SCSI phase
* @instance: adapter to dump
* Print the current SCSI phase for debugging purposes
*/
static void NCR5380_print_phase(struct Scsi_Host *instance)
{
unsigned char status;
int i;
status = NCR5380_read(STATUS_REG);
if (!(status & SR_REQ))
printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
else {
for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
(phases[i].value != (status & PHASE_MASK)); ++i)
;
printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
}
/**
* NCR58380_info - report driver and host information
* @instance: relevant scsi host instance
* For use as the host template info() handler.
static const char *NCR5380_info(struct Scsi_Host *instance)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
return hostdata->info;
}
static void prepare_info(struct Scsi_Host *instance)
{
struct NCR5380_hostdata *hostdata = shost_priv(instance);
snprintf(hostdata->info, sizeof(hostdata->info),
"%s, io_port 0x%lx, n_io_port %d, "
"base 0x%lx, irq %d, "
"can_queue %d, cmd_per_lun %d, "
"sg_tablesize %d, this_id %d, "
Finn Thain
committed
"flags { %s%s}, "
"options { %s} ",
instance->hostt->name, instance->io_port, instance->n_io_port,
instance->base, instance->irq,
instance->can_queue, instance->cmd_per_lun,
instance->sg_tablesize, instance->this_id,
hostdata->flags & FLAG_TAGGED_QUEUING ? "TAGGED_QUEUING " : "",
Finn Thain
committed
hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "",
#ifdef DIFFERENTIAL
"DIFFERENTIAL "
#endif
/**
* NCR5380_print_status - dump controller info
* @instance: controller to dump
* Print commands in the various queues, called from NCR5380_abort
* to aid debugging.
static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd)
printk("scsi%d: destination target %d, lun %llu\n",
H_NO(cmd), cmd->device->id, cmd->device->lun);
printk(KERN_CONT " command = ");
command = cmd->cmnd;
printk(KERN_CONT "%2d (0x%02x)", command[0], command[0]);
for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
printk(KERN_CONT " %02x", command[i]);
printk("\n");
static void __maybe_unused NCR5380_print_status(struct Scsi_Host *instance)
NCR5380_dprint(NDEBUG_ANY, instance);
NCR5380_dprint_phase(NDEBUG_ANY, instance);
hostdata = (struct NCR5380_hostdata *)instance->hostdata;
local_irq_save(flags);
if (!hostdata->connected)
printk("scsi%d: no currently connected command\n", HOSTNO);
lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected);
for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
printk("scsi%d: disconnected_queue\n", HOSTNO);
for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
ptr = NEXT(ptr))
lprint_Scsi_Cmnd(ptr);
static void show_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
int i, s;
unsigned char *command;
seq_printf(m, "scsi%d: destination target %d, lun %llu\n",
H_NO(cmd), cmd->device->id, cmd->device->lun);
seq_printf(m, "%2d (0x%02x)", command[0], command[0]);
for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
seq_putc(m, '\n');
static int __maybe_unused NCR5380_show_info(struct seq_file *m,
struct Scsi_Host *instance)
unsigned long flags;
hostdata = (struct NCR5380_hostdata *)instance->hostdata;
local_irq_save(flags);
if (!hostdata->connected)
seq_printf(m, "scsi%d: no currently connected command\n", HOSTNO);
else
show_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
seq_printf(m, "scsi%d: issue_queue\n", HOSTNO);
for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
show_Scsi_Cmnd(ptr, m);
seq_printf(m, "scsi%d: disconnected_queue\n", HOSTNO);
for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
ptr = NEXT(ptr))
show_Scsi_Cmnd(ptr, m);
local_irq_restore(flags);
return 0;
}
/**
* NCR5380_init - initialise an NCR5380
* @instance: adapter to configure
* @flags: control flags
* Initializes *instance and corresponding 5380 chip,
* with flags OR'd into the initial flags value.
*
* Notes : I assume that the host, hostno, and id bits have been
* set correctly. I don't care about the irq and other fields.
static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
int i;
SETUP_HOSTDATA(instance);
hostdata->host = instance;
hostdata->id_mask = 1 << instance->this_id;
hostdata->id_higher_mask = 0;
for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
if (i > hostdata->id_mask)
hostdata->id_higher_mask |= i;
for (i = 0; i < 8; ++i)
hostdata->busy[i] = 0;
hostdata->connected = NULL;
hostdata->issue_queue = NULL;
hostdata->disconnected_queue = NULL;
INIT_WORK(&hostdata->main_task, NCR5380_main);
hostdata->work_q = alloc_workqueue("ncr5380_%d",
WQ_UNBOUND | WQ_MEM_RECLAIM,
1, instance->host_no);
if (!hostdata->work_q)
return -ENOMEM;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0);
/* Calibrate register polling loop */
i = 0;
deadline = jiffies + 1;
do {
cpu_relax();
} while (time_is_after_jiffies(deadline));
deadline += msecs_to_jiffies(256);
do {
NCR5380_read(STATUS_REG);
++i;
cpu_relax();
} while (time_is_after_jiffies(deadline));
hostdata->accesses_per_ms = i / 256;
/**
* NCR5380_maybe_reset_bus - Detect and correct bus wedge problems.
* @instance: adapter to check
*
* If the system crashed, it may have crashed with a connected target and
* the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the
* currently established nexus, which we know nothing about. Failing that
* do a bus reset.
*
* Note that a bus reset will cause the chip to assert IRQ.
*
* Returns 0 if successful, otherwise -ENXIO.
*/
static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
{
Finn Thain
committed
struct NCR5380_hostdata *hostdata = shost_priv(instance);
int pass;
for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
switch (pass) {
case 1:
case 3:
case 5:
shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n");
NCR5380_poll_politely(instance,
STATUS_REG, SR_BSY, 0, 5 * HZ);
break;
case 2:
shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
do_abort(instance);
break;
case 4:
shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
do_reset(instance);
Finn Thain
committed
/* Wait after a reset; the SCSI standard calls for
* 250ms, we wait 500ms to be on the safe side.
* But some Toshiba CD-ROMs need ten times that.
*/
if (hostdata->flags & FLAG_TOSHIBA_DELAY)
msleep(2500);
else
msleep(500);
break;
case 6:
shost_printk(KERN_ERR, instance, "bus locked solid\n");
return -ENXIO;
}
}
return 0;
}
/**
* NCR5380_exit - remove an NCR5380
* @instance: adapter to remove
*
* Assumes that no more work can be queued (e.g. by NCR5380_intr).
*/
static void NCR5380_exit(struct Scsi_Host *instance)
{
struct NCR5380_hostdata *hostdata = shost_priv(instance);
cancel_work_sync(&hostdata->main_task);
/**
* NCR5380_queue_command - queue a command
* @instance: the relevant SCSI adapter
* @cmd: SCSI command
* cmd is added to the per-instance issue queue, with minor
* twiddling done to the host specific fields of cmd. If the
* main coroutine is not running, it is restarted.
static int NCR5380_queue_command(struct Scsi_Host *instance,
struct scsi_cmnd *cmd)
struct NCR5380_hostdata *hostdata = shost_priv(instance);
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
H_NO(cmd));
cmd->result = (DID_ERROR << 16);
/*
* We use the host_scribble field as a pointer to the next command
* in a queue
*/
cmd->result = 0;
/*
* Insert the cmd into the issue queue. Note that REQUEST SENSE
* commands are added to the head of the queue since any command will
* clear the contingent allegiance condition that exists and the
* sense data is only guaranteed to be valid while the condition exists.
*/
/* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
* Otherwise a running NCR5380_main may steal the lock.
* Lock before actually inserting due to fairness reasons explained in
* atari_scsi.c. If we insert first, then it's impossible for this driver
* to release the lock.
* Stop timer for this command while waiting for the lock, or timeouts
* may happen (and they really do), and it's no good if the command doesn't
* appear in any of the queues.
* ++roman: Just disabling the NCR interrupt isn't sufficient here,
* because also a timer int can trigger an abort or reset, which would
* alter queues and touch the lock.
*/
if (!NCR5380_acquire_dma_irq(instance))
return SCSI_MLQUEUE_HOST_BUSY;
local_irq_save(flags);
/*
* Insert the cmd into the issue queue. Note that REQUEST SENSE
* commands are added to the head of the queue since any command will
* clear the contingent allegiance condition that exists and the
* sense data is only guaranteed to be valid while the condition exists.
*/
if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
LIST(cmd, hostdata->issue_queue);
SET_NEXT(cmd, hostdata->issue_queue);
hostdata->issue_queue = cmd;
} else {
for (tmp = (struct scsi_cmnd *)hostdata->issue_queue;
NEXT(tmp); tmp = NEXT(tmp))
;
LIST(cmd, tmp);
dprintk(NDEBUG_QUEUES, "scsi%d: command added to %s of queue\n", H_NO(cmd),
(cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
/* Kick off command processing */
queue_work(hostdata->work_q, &hostdata->main_task);
static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
{
struct NCR5380_hostdata *hostdata = shost_priv(instance);
/* Caller does the locking needed to set & test these data atomically */
if (!hostdata->disconnected_queue &&
!hostdata->issue_queue &&
!hostdata->connected &&
!hostdata->retain_dma_intr)
NCR5380_release_dma_irq(instance);
}
/**
* NCR5380_main - NCR state machines
* NCR5380_main is a coroutine that runs as long as more work can
* be done on the NCR5380 host adapters in a system. Both
* NCR5380_queue_command() and NCR5380_intr() will try to start it
* in case it is not running.
* Locks: called as its own thread with no locks held.
static void NCR5380_main(struct work_struct *work)
struct NCR5380_hostdata *hostdata =
container_of(work, struct NCR5380_hostdata, main_task);
struct Scsi_Host *instance = hostdata->host;