xref: /linux/drivers/scsi/NCR5380.c (revision 62717f537e1b325665711166c33cd2d06fd6a5cd)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * NCR 5380 generic driver routines.  These should make it *trivial*
31da177e4SLinus Torvalds  *      to implement 5380 SCSI drivers under Linux with a non-trantor
41da177e4SLinus Torvalds  *      architecture.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *      Note that these routines also work with NR53c400 family chips.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Copyright 1993, Drew Eckhardt
91da177e4SLinus Torvalds  *      Visionary Computing
101da177e4SLinus Torvalds  *      (Unix and Linux consulting and custom programming)
111da177e4SLinus Torvalds  *      drew@colorado.edu
121da177e4SLinus Torvalds  *      +1 (303) 666-5836
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  * For more information, please consult
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * NCR 5380 Family
171da177e4SLinus Torvalds  * SCSI Protocol Controller
181da177e4SLinus Torvalds  * Databook
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  * NCR Microelectronics
211da177e4SLinus Torvalds  * 1635 Aeroplaza Drive
221da177e4SLinus Torvalds  * Colorado Springs, CO 80916
231da177e4SLinus Torvalds  * 1+ (719) 578-3400
241da177e4SLinus Torvalds  * 1+ (800) 334-5454
251da177e4SLinus Torvalds  */
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds /*
281da177e4SLinus Torvalds  * Revision 1.10 1998/9/2	Alan Cox
29fa195afeSAlan Cox  *				(alan@lxorguk.ukuu.org.uk)
301da177e4SLinus Torvalds  * Fixed up the timer lockups reported so far. Things still suck. Looking
311da177e4SLinus Torvalds  * forward to 2.3 and per device request queues. Then it'll be possible to
321da177e4SLinus Torvalds  * SMP thread this beast and improve life no end.
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds  * Revision 1.9  1997/7/27	Ronald van Cuijlenborg
351da177e4SLinus Torvalds  *				(ronald.van.cuijlenborg@tip.nl or nutty@dds.nl)
361da177e4SLinus Torvalds  * (hopefully) fixed and enhanced USLEEP
371da177e4SLinus Torvalds  * added support for DTC3181E card (for Mustek scanner)
381da177e4SLinus Torvalds  *
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds  * Revision 1.8			Ingmar Baumgart
411da177e4SLinus Torvalds  *				(ingmar@gonzo.schwaben.de)
421da177e4SLinus Torvalds  * added support for NCR53C400a card
431da177e4SLinus Torvalds  *
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds  * Revision 1.7  1996/3/2       Ray Van Tassle (rayvt@comm.mot.com)
461da177e4SLinus Torvalds  * added proc_info
471da177e4SLinus Torvalds  * added support needed for DTC 3180/3280
481da177e4SLinus Torvalds  * fixed a couple of bugs
491da177e4SLinus Torvalds  *
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds  * Revision 1.5  1994/01/19  09:14:57  drew
521da177e4SLinus Torvalds  * Fixed udelay() hack that was being used on DATAOUT phases
531da177e4SLinus Torvalds  * instead of a proper wait for the final handshake.
541da177e4SLinus Torvalds  *
551da177e4SLinus Torvalds  * Revision 1.4  1994/01/19  06:44:25  drew
561da177e4SLinus Torvalds  * *** empty log message ***
571da177e4SLinus Torvalds  *
581da177e4SLinus Torvalds  * Revision 1.3  1994/01/19  05:24:40  drew
591da177e4SLinus Torvalds  * Added support for TCR LAST_BYTE_SENT bit.
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  * Revision 1.2  1994/01/15  06:14:11  drew
621da177e4SLinus Torvalds  * REAL DMA support, bug fixes.
631da177e4SLinus Torvalds  *
641da177e4SLinus Torvalds  * Revision 1.1  1994/01/15  06:00:54  drew
651da177e4SLinus Torvalds  * Initial revision
661da177e4SLinus Torvalds  *
671da177e4SLinus Torvalds  */
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds /*
701da177e4SLinus Torvalds  * Further development / testing that should be done :
711da177e4SLinus Torvalds  * 1.  Cleanup the NCR5380_transfer_dma function and DMA operation complete
721da177e4SLinus Torvalds  *     code so that everything does the same thing that's done at the
731da177e4SLinus Torvalds  *     end of a pseudo-DMA read operation.
741da177e4SLinus Torvalds  *
751da177e4SLinus Torvalds  * 2.  Fix REAL_DMA (interrupt driven, polled works fine) -
761da177e4SLinus Torvalds  *     basically, transfer size needs to be reduced by one
771da177e4SLinus Torvalds  *     and the last byte read as is done with PSEUDO_DMA.
781da177e4SLinus Torvalds  *
791da177e4SLinus Torvalds  * 4.  Test SCSI-II tagged queueing (I have no devices which support
801da177e4SLinus Torvalds  *      tagged queueing)
811da177e4SLinus Torvalds  */
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds #ifndef notyet
841da177e4SLinus Torvalds #undef REAL_DMA
851da177e4SLinus Torvalds #endif
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds #ifdef BOARD_REQUIRES_NO_DELAY
881da177e4SLinus Torvalds #define io_recovery_delay(x)
891da177e4SLinus Torvalds #else
901da177e4SLinus Torvalds #define io_recovery_delay(x)	udelay(x)
911da177e4SLinus Torvalds #endif
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds /*
941da177e4SLinus Torvalds  * Design
951da177e4SLinus Torvalds  *
961da177e4SLinus Torvalds  * This is a generic 5380 driver.  To use it on a different platform,
971da177e4SLinus Torvalds  * one simply writes appropriate system specific macros (ie, data
981da177e4SLinus Torvalds  * transfer - some PC's will use the I/O bus, 68K's must use
991da177e4SLinus Torvalds  * memory mapped) and drops this file in their 'C' wrapper.
1001da177e4SLinus Torvalds  *
1011da177e4SLinus Torvalds  * (Note from hch:  unfortunately it was not enough for the different
1021da177e4SLinus Torvalds  * m68k folks and instead of improving this driver they copied it
1031da177e4SLinus Torvalds  * and hacked it up for their needs.  As a consequence they lost
1041da177e4SLinus Torvalds  * most updates to this driver.  Maybe someone will fix all these
1051da177e4SLinus Torvalds  * drivers to use a common core one day..)
1061da177e4SLinus Torvalds  *
1071da177e4SLinus Torvalds  * As far as command queueing, two queues are maintained for
1081da177e4SLinus Torvalds  * each 5380 in the system - commands that haven't been issued yet,
1091da177e4SLinus Torvalds  * and commands that are currently executing.  This means that an
1101da177e4SLinus Torvalds  * unlimited number of commands may be queued, letting
1111da177e4SLinus Torvalds  * more commands propagate from the higher driver levels giving higher
1121da177e4SLinus Torvalds  * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported,
1131da177e4SLinus Torvalds  * allowing multiple commands to propagate all the way to a SCSI-II device
1141da177e4SLinus Torvalds  * while a command is already executing.
1151da177e4SLinus Torvalds  *
1161da177e4SLinus Torvalds  *
1171da177e4SLinus Torvalds  * Issues specific to the NCR5380 :
1181da177e4SLinus Torvalds  *
1191da177e4SLinus Torvalds  * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
1201da177e4SLinus Torvalds  * piece of hardware that requires you to sit in a loop polling for
1211da177e4SLinus Torvalds  * the REQ signal as long as you are connected.  Some devices are
1221da177e4SLinus Torvalds  * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
123686f3990SFinn Thain  * while doing long seek operations. [...] These
1241da177e4SLinus Torvalds  * broken devices are the exception rather than the rule and I'd rather
1251da177e4SLinus Torvalds  * spend my time optimizing for the normal case.
1261da177e4SLinus Torvalds  *
1271da177e4SLinus Torvalds  * Architecture :
1281da177e4SLinus Torvalds  *
1291da177e4SLinus Torvalds  * At the heart of the design is a coroutine, NCR5380_main,
1301da177e4SLinus Torvalds  * which is started from a workqueue for each NCR5380 host in the
1311da177e4SLinus Torvalds  * system.  It attempts to establish I_T_L or I_T_L_Q nexuses by
1321da177e4SLinus Torvalds  * removing the commands from the issue queue and calling
1331da177e4SLinus Torvalds  * NCR5380_select() if a nexus is not established.
1341da177e4SLinus Torvalds  *
1351da177e4SLinus Torvalds  * Once a nexus is established, the NCR5380_information_transfer()
1361da177e4SLinus Torvalds  * phase goes through the various phases as instructed by the target.
1371da177e4SLinus Torvalds  * if the target goes into MSG IN and sends a DISCONNECT message,
1381da177e4SLinus Torvalds  * the command structure is placed into the per instance disconnected
1391da177e4SLinus Torvalds  * queue, and NCR5380_main tries to find more work.  If the target is
1401da177e4SLinus Torvalds  * idle for too long, the system will try to sleep.
1411da177e4SLinus Torvalds  *
1421da177e4SLinus Torvalds  * If a command has disconnected, eventually an interrupt will trigger,
1431da177e4SLinus Torvalds  * calling NCR5380_intr()  which will in turn call NCR5380_reselect
1441da177e4SLinus Torvalds  * to reestablish a nexus.  This will run main if necessary.
1451da177e4SLinus Torvalds  *
1461da177e4SLinus Torvalds  * On command termination, the done function will be called as
1471da177e4SLinus Torvalds  * appropriate.
1481da177e4SLinus Torvalds  *
1491da177e4SLinus Torvalds  * SCSI pointers are maintained in the SCp field of SCSI command
1501da177e4SLinus Torvalds  * structures, being initialized after the command is connected
1511da177e4SLinus Torvalds  * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
1521da177e4SLinus Torvalds  * Note that in violation of the standard, an implicit SAVE POINTERS operation
1531da177e4SLinus Torvalds  * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
1541da177e4SLinus Torvalds  */
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds /*
1571da177e4SLinus Torvalds  * Using this file :
1581da177e4SLinus Torvalds  * This file a skeleton Linux SCSI driver for the NCR 5380 series
1591da177e4SLinus Torvalds  * of chips.  To use it, you write an architecture specific functions
1601da177e4SLinus Torvalds  * and macros and include this file in your driver.
1611da177e4SLinus Torvalds  *
1621da177e4SLinus Torvalds  * These macros control options :
1631da177e4SLinus Torvalds  * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be
1641da177e4SLinus Torvalds  *      defined.
1651da177e4SLinus Torvalds  *
1661da177e4SLinus Torvalds  * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
1671da177e4SLinus Torvalds  *      for commands that return with a CHECK CONDITION status.
1681da177e4SLinus Torvalds  *
1691da177e4SLinus Torvalds  * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
1701da177e4SLinus Torvalds  *      transceivers.
1711da177e4SLinus Torvalds  *
1721da177e4SLinus Torvalds  * DONT_USE_INTR - if defined, never use interrupts, even if we probe or
1731da177e4SLinus Torvalds  *      override-configure an IRQ.
1741da177e4SLinus Torvalds  *
1751da177e4SLinus Torvalds  * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
1761da177e4SLinus Torvalds  *
1771da177e4SLinus Torvalds  * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
1781da177e4SLinus Torvalds  *
1791da177e4SLinus Torvalds  * REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't
1801da177e4SLinus Torvalds  *      rely on phase mismatch and EOP interrupts to determine end
1811da177e4SLinus Torvalds  *      of phase.
1821da177e4SLinus Torvalds  *
1831da177e4SLinus Torvalds  * Defaults for these will be provided although the user may want to adjust
1841da177e4SLinus Torvalds  * these to allocate CPU resources to the SCSI driver or "real" code.
1851da177e4SLinus Torvalds  *
1861da177e4SLinus Torvalds  * These macros MUST be defined :
1871da177e4SLinus Torvalds  *
1881da177e4SLinus Torvalds  * NCR5380_read(register)  - read from the specified register
1891da177e4SLinus Torvalds  *
1901da177e4SLinus Torvalds  * NCR5380_write(register, value) - write to the specific register
1911da177e4SLinus Torvalds  *
1921da177e4SLinus Torvalds  * NCR5380_implementation_fields  - additional fields needed for this
1931da177e4SLinus Torvalds  *      specific implementation of the NCR5380
1941da177e4SLinus Torvalds  *
1951da177e4SLinus Torvalds  * Either real DMA *or* pseudo DMA may be implemented
1961da177e4SLinus Torvalds  * REAL functions :
1971da177e4SLinus Torvalds  * NCR5380_REAL_DMA should be defined if real DMA is to be used.
1981da177e4SLinus Torvalds  * Note that the DMA setup functions should return the number of bytes
1991da177e4SLinus Torvalds  *      that they were able to program the controller for.
2001da177e4SLinus Torvalds  *
2011da177e4SLinus Torvalds  * Also note that generic i386/PC versions of these macros are
2021da177e4SLinus Torvalds  *      available as NCR5380_i386_dma_write_setup,
2031da177e4SLinus Torvalds  *      NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
2041da177e4SLinus Torvalds  *
2051da177e4SLinus Torvalds  * NCR5380_dma_write_setup(instance, src, count) - initialize
2061da177e4SLinus Torvalds  * NCR5380_dma_read_setup(instance, dst, count) - initialize
2071da177e4SLinus Torvalds  * NCR5380_dma_residual(instance); - residual count
2081da177e4SLinus Torvalds  *
2091da177e4SLinus Torvalds  * PSEUDO functions :
2101da177e4SLinus Torvalds  * NCR5380_pwrite(instance, src, count)
2111da177e4SLinus Torvalds  * NCR5380_pread(instance, dst, count);
2121da177e4SLinus Torvalds  *
2131da177e4SLinus Torvalds  * The generic driver is initialized by calling NCR5380_init(instance),
2141da177e4SLinus Torvalds  * after setting the appropriate host specific fields and ID.  If the
2151da177e4SLinus Torvalds  * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
2161da177e4SLinus Torvalds  * possible) function may be used.
2171da177e4SLinus Torvalds  */
2181da177e4SLinus Torvalds 
21954d8fe44SFinn Thain static int do_abort(struct Scsi_Host *);
22054d8fe44SFinn Thain static void do_reset(struct Scsi_Host *);
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds /*
2231da177e4SLinus Torvalds  *	initialize_SCp		-	init the scsi pointer field
2241da177e4SLinus Torvalds  *	@cmd: command block to set up
2251da177e4SLinus Torvalds  *
2261da177e4SLinus Torvalds  *	Set up the internal fields in the SCSI command.
2271da177e4SLinus Torvalds  */
2281da177e4SLinus Torvalds 
229710ddd0dSFinn Thain static inline void initialize_SCp(struct scsi_cmnd *cmd)
2301da177e4SLinus Torvalds {
2311da177e4SLinus Torvalds 	/*
2321da177e4SLinus Torvalds 	 * Initialize the Scsi Pointer field so that all of the commands in the
2331da177e4SLinus Torvalds 	 * various queues are valid.
2341da177e4SLinus Torvalds 	 */
2351da177e4SLinus Torvalds 
2369e0fe44dSBoaz Harrosh 	if (scsi_bufflen(cmd)) {
2379e0fe44dSBoaz Harrosh 		cmd->SCp.buffer = scsi_sglist(cmd);
2389e0fe44dSBoaz Harrosh 		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
23945711f1aSJens Axboe 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
2401da177e4SLinus Torvalds 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
2411da177e4SLinus Torvalds 	} else {
2421da177e4SLinus Torvalds 		cmd->SCp.buffer = NULL;
2431da177e4SLinus Torvalds 		cmd->SCp.buffers_residual = 0;
2449e0fe44dSBoaz Harrosh 		cmd->SCp.ptr = NULL;
2459e0fe44dSBoaz Harrosh 		cmd->SCp.this_residual = 0;
2461da177e4SLinus Torvalds 	}
247f27db8ebSFinn Thain 
248f27db8ebSFinn Thain 	cmd->SCp.Status = 0;
249f27db8ebSFinn Thain 	cmd->SCp.Message = 0;
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds /**
253b32ade12SFinn Thain  * NCR5380_poll_politely2 - wait for two chip register values
2541da177e4SLinus Torvalds  * @instance: controller to poll
255b32ade12SFinn Thain  * @reg1: 5380 register to poll
256b32ade12SFinn Thain  * @bit1: Bitmask to check
257b32ade12SFinn Thain  * @val1: Expected value
258b32ade12SFinn Thain  * @reg2: Second 5380 register to poll
259b32ade12SFinn Thain  * @bit2: Second bitmask to check
260b32ade12SFinn Thain  * @val2: Second expected value
2612f854b82SFinn Thain  * @wait: Time-out in jiffies
2621da177e4SLinus Torvalds  *
2632f854b82SFinn Thain  * Polls the chip in a reasonably efficient manner waiting for an
2642f854b82SFinn Thain  * event to occur. After a short quick poll we begin to yield the CPU
2652f854b82SFinn Thain  * (if possible). In irq contexts the time-out is arbitrarily limited.
2662f854b82SFinn Thain  * Callers may hold locks as long as they are held in irq mode.
2671da177e4SLinus Torvalds  *
268b32ade12SFinn Thain  * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT.
2691da177e4SLinus Torvalds  */
2701da177e4SLinus Torvalds 
271b32ade12SFinn Thain static int NCR5380_poll_politely2(struct Scsi_Host *instance,
272b32ade12SFinn Thain                                   int reg1, int bit1, int val1,
273b32ade12SFinn Thain                                   int reg2, int bit2, int val2, int wait)
2741da177e4SLinus Torvalds {
2752f854b82SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
2762f854b82SFinn Thain 	unsigned long deadline = jiffies + wait;
2772f854b82SFinn Thain 	unsigned long n;
2781da177e4SLinus Torvalds 
2792f854b82SFinn Thain 	/* Busy-wait for up to 10 ms */
2802f854b82SFinn Thain 	n = min(10000U, jiffies_to_usecs(wait));
2812f854b82SFinn Thain 	n *= hostdata->accesses_per_ms;
282b32ade12SFinn Thain 	n /= 2000;
2832f854b82SFinn Thain 	do {
284b32ade12SFinn Thain 		if ((NCR5380_read(reg1) & bit1) == val1)
285b32ade12SFinn Thain 			return 0;
286b32ade12SFinn Thain 		if ((NCR5380_read(reg2) & bit2) == val2)
2871da177e4SLinus Torvalds 			return 0;
2881da177e4SLinus Torvalds 		cpu_relax();
2892f854b82SFinn Thain 	} while (n--);
2902f854b82SFinn Thain 
2912f854b82SFinn Thain 	if (irqs_disabled() || in_interrupt())
2922f854b82SFinn Thain 		return -ETIMEDOUT;
2932f854b82SFinn Thain 
2942f854b82SFinn Thain 	/* Repeatedly sleep for 1 ms until deadline */
2952f854b82SFinn Thain 	while (time_is_after_jiffies(deadline)) {
2962f854b82SFinn Thain 		schedule_timeout_uninterruptible(1);
297b32ade12SFinn Thain 		if ((NCR5380_read(reg1) & bit1) == val1)
298b32ade12SFinn Thain 			return 0;
299b32ade12SFinn Thain 		if ((NCR5380_read(reg2) & bit2) == val2)
3002f854b82SFinn Thain 			return 0;
3011da177e4SLinus Torvalds 	}
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	return -ETIMEDOUT;
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds 
306b32ade12SFinn Thain static inline int NCR5380_poll_politely(struct Scsi_Host *instance,
307b32ade12SFinn Thain                                         int reg, int bit, int val, int wait)
308b32ade12SFinn Thain {
309b32ade12SFinn Thain 	return NCR5380_poll_politely2(instance, reg, bit, val,
310b32ade12SFinn Thain 	                                        reg, bit, val, wait);
311b32ade12SFinn Thain }
312b32ade12SFinn Thain 
3131da177e4SLinus Torvalds static struct {
3141da177e4SLinus Torvalds 	unsigned char value;
3151da177e4SLinus Torvalds 	const char *name;
316702809ceSAndrew Morton } phases[] __maybe_unused = {
3171da177e4SLinus Torvalds 	{PHASE_DATAOUT, "DATAOUT"},
3181da177e4SLinus Torvalds 	{PHASE_DATAIN, "DATAIN"},
3191da177e4SLinus Torvalds 	{PHASE_CMDOUT, "CMDOUT"},
3201da177e4SLinus Torvalds 	{PHASE_STATIN, "STATIN"},
3211da177e4SLinus Torvalds 	{PHASE_MSGOUT, "MSGOUT"},
3221da177e4SLinus Torvalds 	{PHASE_MSGIN, "MSGIN"},
3231da177e4SLinus Torvalds 	{PHASE_UNKNOWN, "UNKNOWN"}
3241da177e4SLinus Torvalds };
3251da177e4SLinus Torvalds 
326185a7a1cSviro@ZenIV.linux.org.uk #if NDEBUG
3271da177e4SLinus Torvalds static struct {
3281da177e4SLinus Torvalds 	unsigned char mask;
3291da177e4SLinus Torvalds 	const char *name;
3301da177e4SLinus Torvalds } signals[] = {
3311da177e4SLinus Torvalds 	{SR_DBP, "PARITY"},
3321da177e4SLinus Torvalds 	{SR_RST, "RST"},
3331da177e4SLinus Torvalds 	{SR_BSY, "BSY"},
3341da177e4SLinus Torvalds 	{SR_REQ, "REQ"},
3351da177e4SLinus Torvalds 	{SR_MSG, "MSG"},
3361da177e4SLinus Torvalds 	{SR_CD, "CD"},
3371da177e4SLinus Torvalds 	{SR_IO, "IO"},
3381da177e4SLinus Torvalds 	{SR_SEL, "SEL"},
3391da177e4SLinus Torvalds 	{0, NULL}
3401da177e4SLinus Torvalds },
3411da177e4SLinus Torvalds basrs[] = {
3421da177e4SLinus Torvalds 	{BASR_ATN, "ATN"},
3431da177e4SLinus Torvalds 	{BASR_ACK, "ACK"},
3441da177e4SLinus Torvalds 	{0, NULL}
3451da177e4SLinus Torvalds },
3461da177e4SLinus Torvalds icrs[] = {
3471da177e4SLinus Torvalds 	{ICR_ASSERT_RST, "ASSERT RST"},
3481da177e4SLinus Torvalds 	{ICR_ASSERT_ACK, "ASSERT ACK"},
3491da177e4SLinus Torvalds 	{ICR_ASSERT_BSY, "ASSERT BSY"},
3501da177e4SLinus Torvalds 	{ICR_ASSERT_SEL, "ASSERT SEL"},
3511da177e4SLinus Torvalds 	{ICR_ASSERT_ATN, "ASSERT ATN"},
3521da177e4SLinus Torvalds 	{ICR_ASSERT_DATA, "ASSERT DATA"},
3531da177e4SLinus Torvalds 	{0, NULL}
3541da177e4SLinus Torvalds },
3551da177e4SLinus Torvalds mrs[] = {
3561da177e4SLinus Torvalds 	{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"},
3571da177e4SLinus Torvalds 	{MR_TARGET, "MODE TARGET"},
3581da177e4SLinus Torvalds 	{MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"},
3591da177e4SLinus Torvalds 	{MR_ENABLE_PAR_INTR, "MODE PARITY INTR"},
3601da177e4SLinus Torvalds 	{MR_MONITOR_BSY, "MODE MONITOR BSY"},
3611da177e4SLinus Torvalds 	{MR_DMA_MODE, "MODE DMA"},
3621da177e4SLinus Torvalds 	{MR_ARBITRATE, "MODE ARBITRATION"},
3631da177e4SLinus Torvalds 	{0, NULL}
3641da177e4SLinus Torvalds };
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds /**
3671da177e4SLinus Torvalds  *	NCR5380_print	-	print scsi bus signals
3681da177e4SLinus Torvalds  *	@instance:	adapter state to dump
3691da177e4SLinus Torvalds  *
3701da177e4SLinus Torvalds  *	Print the SCSI bus signals for debugging purposes
3711da177e4SLinus Torvalds  *
3721da177e4SLinus Torvalds  *	Locks: caller holds hostdata lock (not essential)
3731da177e4SLinus Torvalds  */
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds static void NCR5380_print(struct Scsi_Host *instance)
3761da177e4SLinus Torvalds {
3771da177e4SLinus Torvalds 	unsigned char status, data, basr, mr, icr, i;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	data = NCR5380_read(CURRENT_SCSI_DATA_REG);
3801da177e4SLinus Torvalds 	status = NCR5380_read(STATUS_REG);
3811da177e4SLinus Torvalds 	mr = NCR5380_read(MODE_REG);
3821da177e4SLinus Torvalds 	icr = NCR5380_read(INITIATOR_COMMAND_REG);
3831da177e4SLinus Torvalds 	basr = NCR5380_read(BUS_AND_STATUS_REG);
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	printk("STATUS_REG: %02x ", status);
3861da177e4SLinus Torvalds 	for (i = 0; signals[i].mask; ++i)
3871da177e4SLinus Torvalds 		if (status & signals[i].mask)
3881da177e4SLinus Torvalds 			printk(",%s", signals[i].name);
3891da177e4SLinus Torvalds 	printk("\nBASR: %02x ", basr);
3901da177e4SLinus Torvalds 	for (i = 0; basrs[i].mask; ++i)
3911da177e4SLinus Torvalds 		if (basr & basrs[i].mask)
3921da177e4SLinus Torvalds 			printk(",%s", basrs[i].name);
3931da177e4SLinus Torvalds 	printk("\nICR: %02x ", icr);
3941da177e4SLinus Torvalds 	for (i = 0; icrs[i].mask; ++i)
3951da177e4SLinus Torvalds 		if (icr & icrs[i].mask)
3961da177e4SLinus Torvalds 			printk(",%s", icrs[i].name);
3971da177e4SLinus Torvalds 	printk("\nMODE: %02x ", mr);
3981da177e4SLinus Torvalds 	for (i = 0; mrs[i].mask; ++i)
3991da177e4SLinus Torvalds 		if (mr & mrs[i].mask)
4001da177e4SLinus Torvalds 			printk(",%s", mrs[i].name);
4011da177e4SLinus Torvalds 	printk("\n");
4021da177e4SLinus Torvalds }
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds /*
4061da177e4SLinus Torvalds  *	NCR5380_print_phase	-	show SCSI phase
4071da177e4SLinus Torvalds  *	@instance: adapter to dump
4081da177e4SLinus Torvalds  *
4091da177e4SLinus Torvalds  * 	Print the current SCSI phase for debugging purposes
4101da177e4SLinus Torvalds  *
4111da177e4SLinus Torvalds  *	Locks: none
4121da177e4SLinus Torvalds  */
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds static void NCR5380_print_phase(struct Scsi_Host *instance)
4151da177e4SLinus Torvalds {
4161da177e4SLinus Torvalds 	unsigned char status;
4171da177e4SLinus Torvalds 	int i;
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	status = NCR5380_read(STATUS_REG);
4201da177e4SLinus Torvalds 	if (!(status & SR_REQ))
4211da177e4SLinus Torvalds 		printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no);
4221da177e4SLinus Torvalds 	else {
4231da177e4SLinus Torvalds 		for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
4241da177e4SLinus Torvalds 		printk("scsi%d : phase %s\n", instance->host_no, phases[i].name);
4251da177e4SLinus Torvalds 	}
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds #endif
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 
430d5f7e65dSFinn Thain static int probe_irq __initdata;
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds /**
4331da177e4SLinus Torvalds  *	probe_intr	-	helper for IRQ autoprobe
4341da177e4SLinus Torvalds  *	@irq: interrupt number
4351da177e4SLinus Torvalds  *	@dev_id: unused
4361da177e4SLinus Torvalds  *	@regs: unused
4371da177e4SLinus Torvalds  *
4381da177e4SLinus Torvalds  *	Set a flag to indicate the IRQ in question was received. This is
4391da177e4SLinus Torvalds  *	used by the IRQ probe code.
4401da177e4SLinus Torvalds  */
4411da177e4SLinus Torvalds 
4427d12e780SDavid Howells static irqreturn_t __init probe_intr(int irq, void *dev_id)
4431da177e4SLinus Torvalds {
4441da177e4SLinus Torvalds 	probe_irq = irq;
4451da177e4SLinus Torvalds 	return IRQ_HANDLED;
4461da177e4SLinus Torvalds }
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds /**
4491da177e4SLinus Torvalds  *	NCR5380_probe_irq	-	find the IRQ of an NCR5380
4501da177e4SLinus Torvalds  *	@instance: NCR5380 controller
4511da177e4SLinus Torvalds  *	@possible: bitmask of ISA IRQ lines
4521da177e4SLinus Torvalds  *
4531da177e4SLinus Torvalds  *	Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ
4541da177e4SLinus Torvalds  *	and then looking to see what interrupt actually turned up.
4551da177e4SLinus Torvalds  *
4561da177e4SLinus Torvalds  *	Locks: none, irqs must be enabled on entry
4571da177e4SLinus Torvalds  */
4581da177e4SLinus Torvalds 
459702809ceSAndrew Morton static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
460702809ceSAndrew Morton 						int possible)
4611da177e4SLinus Torvalds {
462e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
4631da177e4SLinus Torvalds 	unsigned long timeout;
4641da177e4SLinus Torvalds 	int trying_irqs, i, mask;
4651da177e4SLinus Torvalds 
46622f5f10dSFinn Thain 	for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1)
4674909cc2bSMichael Opdenacker 		if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
4681da177e4SLinus Torvalds 			trying_irqs |= mask;
4691da177e4SLinus Torvalds 
4704e5a800cSNicholas Mc Guire 	timeout = jiffies + msecs_to_jiffies(250);
47122f5f10dSFinn Thain 	probe_irq = NO_IRQ;
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds 	/*
4741da177e4SLinus Torvalds 	 * A interrupt is triggered whenever BSY = false, SEL = true
4751da177e4SLinus Torvalds 	 * and a bit set in the SELECT_ENABLE_REG is asserted on the
4761da177e4SLinus Torvalds 	 * SCSI bus.
4771da177e4SLinus Torvalds 	 *
4781da177e4SLinus Torvalds 	 * Note that the bus is only driven when the phase control signals
4791da177e4SLinus Torvalds 	 * (I/O, C/D, and MSG) match those in the TCR, so we must reset that
4801da177e4SLinus Torvalds 	 * to zero.
4811da177e4SLinus Torvalds 	 */
4821da177e4SLinus Torvalds 
4831da177e4SLinus Torvalds 	NCR5380_write(TARGET_COMMAND_REG, 0);
4841da177e4SLinus Torvalds 	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
4851da177e4SLinus Torvalds 	NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
4861da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL);
4871da177e4SLinus Torvalds 
48822f5f10dSFinn Thain 	while (probe_irq == NO_IRQ && time_before(jiffies, timeout))
489a9a3047dSNishanth Aravamudan 		schedule_timeout_uninterruptible(1);
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds 	NCR5380_write(SELECT_ENABLE_REG, 0);
4921da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
4931da177e4SLinus Torvalds 
49422f5f10dSFinn Thain 	for (i = 1, mask = 2; i < 16; ++i, mask <<= 1)
4951da177e4SLinus Torvalds 		if (trying_irqs & mask)
4961da177e4SLinus Torvalds 			free_irq(i, NULL);
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 	return probe_irq;
4991da177e4SLinus Torvalds }
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds /**
5028c32513bSFinn Thain  *	NCR58380_info - report driver and host information
5038c32513bSFinn Thain  *	@instance: relevant scsi host instance
5041da177e4SLinus Torvalds  *
5058c32513bSFinn Thain  *	For use as the host template info() handler.
5061da177e4SLinus Torvalds  *
5071da177e4SLinus Torvalds  *	Locks: none
5081da177e4SLinus Torvalds  */
5091da177e4SLinus Torvalds 
5108c32513bSFinn Thain static const char *NCR5380_info(struct Scsi_Host *instance)
5111da177e4SLinus Torvalds {
5128c32513bSFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
5138c32513bSFinn Thain 
5148c32513bSFinn Thain 	return hostdata->info;
5158c32513bSFinn Thain }
5168c32513bSFinn Thain 
5178c32513bSFinn Thain static void prepare_info(struct Scsi_Host *instance)
5188c32513bSFinn Thain {
5198c32513bSFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
5208c32513bSFinn Thain 
5218c32513bSFinn Thain 	snprintf(hostdata->info, sizeof(hostdata->info),
5228c32513bSFinn Thain 	         "%s, io_port 0x%lx, n_io_port %d, "
5238c32513bSFinn Thain 	         "base 0x%lx, irq %d, "
5248c32513bSFinn Thain 	         "can_queue %d, cmd_per_lun %d, "
5258c32513bSFinn Thain 	         "sg_tablesize %d, this_id %d, "
526be3f4121SFinn Thain 	         "flags { %s%s%s}, "
5278c32513bSFinn Thain 	         "options { %s} ",
5288c32513bSFinn Thain 	         instance->hostt->name, instance->io_port, instance->n_io_port,
5298c32513bSFinn Thain 	         instance->base, instance->irq,
5308c32513bSFinn Thain 	         instance->can_queue, instance->cmd_per_lun,
5318c32513bSFinn Thain 	         instance->sg_tablesize, instance->this_id,
53255181be8SFinn Thain 	         hostdata->flags & FLAG_NO_DMA_FIXUP  ? "NO_DMA_FIXUP "  : "",
5338c32513bSFinn Thain 	         hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "",
5349c3f0e2bSFinn Thain 	         hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY "  : "",
5351da177e4SLinus Torvalds #ifdef AUTOPROBE_IRQ
5361da177e4SLinus Torvalds 	         "AUTOPROBE_IRQ "
5371da177e4SLinus Torvalds #endif
5381da177e4SLinus Torvalds #ifdef DIFFERENTIAL
5391da177e4SLinus Torvalds 	         "DIFFERENTIAL "
5401da177e4SLinus Torvalds #endif
5411da177e4SLinus Torvalds #ifdef REAL_DMA
5428c32513bSFinn Thain 	         "REAL_DMA "
5431da177e4SLinus Torvalds #endif
5441da177e4SLinus Torvalds #ifdef REAL_DMA_POLL
5458c32513bSFinn Thain 	         "REAL_DMA_POLL "
5461da177e4SLinus Torvalds #endif
5471da177e4SLinus Torvalds #ifdef PARITY
5481da177e4SLinus Torvalds 	         "PARITY "
5491da177e4SLinus Torvalds #endif
5501da177e4SLinus Torvalds #ifdef PSEUDO_DMA
5518c32513bSFinn Thain 	         "PSEUDO_DMA "
5521da177e4SLinus Torvalds #endif
5538c32513bSFinn Thain 	         "");
5541da177e4SLinus Torvalds }
5551da177e4SLinus Torvalds 
556a9c2dc43SFinn Thain #ifdef PSEUDO_DMA
5571da177e4SLinus Torvalds /******************************************/
5581da177e4SLinus Torvalds /*
5591da177e4SLinus Torvalds  * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
5601da177e4SLinus Torvalds  *
5611da177e4SLinus Torvalds  * *buffer: I/O buffer
5621da177e4SLinus Torvalds  * **start: if inout == FALSE pointer into buffer where user read should start
5631da177e4SLinus Torvalds  * offset: current offset
5641da177e4SLinus Torvalds  * length: length of buffer
5651da177e4SLinus Torvalds  * hostno: Scsi_Host host_no
5661da177e4SLinus Torvalds  * inout: TRUE - user is writing; FALSE - user is reading
5671da177e4SLinus Torvalds  *
5681da177e4SLinus Torvalds  * Return the number of bytes read from or written
5691da177e4SLinus Torvalds  */
5701da177e4SLinus Torvalds 
571dd7ab71bSAl Viro static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
572dd7ab71bSAl Viro 	char *buffer, int length)
5731da177e4SLinus Torvalds {
574a9c2dc43SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
575a9c2dc43SFinn Thain 
576a9c2dc43SFinn Thain 	hostdata->spin_max_r = 0;
577a9c2dc43SFinn Thain 	hostdata->spin_max_w = 0;
578a9c2dc43SFinn Thain 	return 0;
5791da177e4SLinus Torvalds }
580dd7ab71bSAl Viro 
581dd7ab71bSAl Viro static int __maybe_unused NCR5380_show_info(struct seq_file *m,
582dd7ab71bSAl Viro 	struct Scsi_Host *instance)
583dd7ab71bSAl Viro {
584e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
585dd7ab71bSAl Viro 
5860c3de38fSRasmus Villemoes 	seq_printf(m, "Highwater I/O busy spin counts: write %d, read %d\n",
587a9c2dc43SFinn Thain 	        hostdata->spin_max_w, hostdata->spin_max_r);
5881da177e4SLinus Torvalds 	return 0;
5891da177e4SLinus Torvalds }
590e5c3fddfSFinn Thain #endif
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds /**
5931da177e4SLinus Torvalds  *	NCR5380_init	-	initialise an NCR5380
5941da177e4SLinus Torvalds  *	@instance: adapter to configure
5951da177e4SLinus Torvalds  *	@flags: control flags
5961da177e4SLinus Torvalds  *
5971da177e4SLinus Torvalds  *	Initializes *instance and corresponding 5380 chip,
5981da177e4SLinus Torvalds  *      with flags OR'd into the initial flags value.
5991da177e4SLinus Torvalds  *
6001da177e4SLinus Torvalds  *	Notes : I assume that the host, hostno, and id bits have been
6011da177e4SLinus Torvalds  *      set correctly.  I don't care about the irq and other fields.
6021da177e4SLinus Torvalds  *
6031da177e4SLinus Torvalds  *	Returns 0 for success
6041da177e4SLinus Torvalds  *
6051da177e4SLinus Torvalds  *	Locks: interrupts must be enabled when we are called
6061da177e4SLinus Torvalds  */
6071da177e4SLinus Torvalds 
6086f039790SGreg Kroah-Hartman static int NCR5380_init(struct Scsi_Host *instance, int flags)
6091da177e4SLinus Torvalds {
610e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
611b6488f97SFinn Thain 	int i;
6122f854b82SFinn Thain 	unsigned long deadline;
6131da177e4SLinus Torvalds 
6141da177e4SLinus Torvalds 	if(in_interrupt())
6151da177e4SLinus Torvalds 		printk(KERN_ERR "NCR5380_init called with interrupts off!\n");
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds 	hostdata->id_mask = 1 << instance->this_id;
6181da177e4SLinus Torvalds 	for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
6191da177e4SLinus Torvalds 		if (i > hostdata->id_mask)
6201da177e4SLinus Torvalds 			hostdata->id_higher_mask |= i;
6211da177e4SLinus Torvalds 	for (i = 0; i < 8; ++i)
6221da177e4SLinus Torvalds 		hostdata->busy[i] = 0;
6231da177e4SLinus Torvalds #ifdef REAL_DMA
6241da177e4SLinus Torvalds 	hostdata->dmalen = 0;
6251da177e4SLinus Torvalds #endif
62611d2f63bSFinn Thain 	spin_lock_init(&hostdata->lock);
6271da177e4SLinus Torvalds 	hostdata->connected = NULL;
628f27db8ebSFinn Thain 	hostdata->sensing = NULL;
629f27db8ebSFinn Thain 	INIT_LIST_HEAD(&hostdata->autosense);
63032b26a10SFinn Thain 	INIT_LIST_HEAD(&hostdata->unissued);
63132b26a10SFinn Thain 	INIT_LIST_HEAD(&hostdata->disconnected);
63232b26a10SFinn Thain 
63355181be8SFinn Thain 	hostdata->flags = flags;
6341da177e4SLinus Torvalds 
6358d8601a7SFinn Thain 	INIT_WORK(&hostdata->main_task, NCR5380_main);
6360ad0eff9SFinn Thain 	hostdata->work_q = alloc_workqueue("ncr5380_%d",
6370ad0eff9SFinn Thain 	                        WQ_UNBOUND | WQ_MEM_RECLAIM,
6380ad0eff9SFinn Thain 	                        1, instance->host_no);
6390ad0eff9SFinn Thain 	if (!hostdata->work_q)
6400ad0eff9SFinn Thain 		return -ENOMEM;
6411da177e4SLinus Torvalds 
6421da177e4SLinus Torvalds 	hostdata->host = instance;
6431da177e4SLinus Torvalds 
6448c32513bSFinn Thain 	prepare_info(instance);
6458c32513bSFinn Thain 
6461da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
6471da177e4SLinus Torvalds 	NCR5380_write(MODE_REG, MR_BASE);
6481da177e4SLinus Torvalds 	NCR5380_write(TARGET_COMMAND_REG, 0);
6491da177e4SLinus Torvalds 	NCR5380_write(SELECT_ENABLE_REG, 0);
6502f854b82SFinn Thain 
6512f854b82SFinn Thain 	/* Calibrate register polling loop */
6522f854b82SFinn Thain 	i = 0;
6532f854b82SFinn Thain 	deadline = jiffies + 1;
6542f854b82SFinn Thain 	do {
6552f854b82SFinn Thain 		cpu_relax();
6562f854b82SFinn Thain 	} while (time_is_after_jiffies(deadline));
6572f854b82SFinn Thain 	deadline += msecs_to_jiffies(256);
6582f854b82SFinn Thain 	do {
6592f854b82SFinn Thain 		NCR5380_read(STATUS_REG);
6602f854b82SFinn Thain 		++i;
6612f854b82SFinn Thain 		cpu_relax();
6622f854b82SFinn Thain 	} while (time_is_after_jiffies(deadline));
6632f854b82SFinn Thain 	hostdata->accesses_per_ms = i / 256;
6642f854b82SFinn Thain 
665b6488f97SFinn Thain 	return 0;
666b6488f97SFinn Thain }
6671da177e4SLinus Torvalds 
668b6488f97SFinn Thain /**
669b6488f97SFinn Thain  * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems.
670b6488f97SFinn Thain  * @instance: adapter to check
6711da177e4SLinus Torvalds  *
672b6488f97SFinn Thain  * If the system crashed, it may have crashed with a connected target and
673b6488f97SFinn Thain  * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the
674b6488f97SFinn Thain  * currently established nexus, which we know nothing about. Failing that
675b6488f97SFinn Thain  * do a bus reset.
6761da177e4SLinus Torvalds  *
677b6488f97SFinn Thain  * Note that a bus reset will cause the chip to assert IRQ.
678b6488f97SFinn Thain  *
679b6488f97SFinn Thain  * Returns 0 if successful, otherwise -ENXIO.
6801da177e4SLinus Torvalds  */
6811da177e4SLinus Torvalds 
682b6488f97SFinn Thain static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance)
683b6488f97SFinn Thain {
6849c3f0e2bSFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
685b6488f97SFinn Thain 	int pass;
686b6488f97SFinn Thain 
6871da177e4SLinus Torvalds 	for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
6881da177e4SLinus Torvalds 		switch (pass) {
6891da177e4SLinus Torvalds 		case 1:
6901da177e4SLinus Torvalds 		case 3:
6911da177e4SLinus Torvalds 		case 5:
692636b1ec8SFinn Thain 			shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n");
693636b1ec8SFinn Thain 			NCR5380_poll_politely(instance,
694636b1ec8SFinn Thain 			                      STATUS_REG, SR_BSY, 0, 5 * HZ);
6951da177e4SLinus Torvalds 			break;
6961da177e4SLinus Torvalds 		case 2:
697636b1ec8SFinn Thain 			shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n");
6981da177e4SLinus Torvalds 			do_abort(instance);
6991da177e4SLinus Torvalds 			break;
7001da177e4SLinus Torvalds 		case 4:
701636b1ec8SFinn Thain 			shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n");
7021da177e4SLinus Torvalds 			do_reset(instance);
7039c3f0e2bSFinn Thain 			/* Wait after a reset; the SCSI standard calls for
7049c3f0e2bSFinn Thain 			 * 250ms, we wait 500ms to be on the safe side.
7059c3f0e2bSFinn Thain 			 * But some Toshiba CD-ROMs need ten times that.
7069c3f0e2bSFinn Thain 			 */
7079c3f0e2bSFinn Thain 			if (hostdata->flags & FLAG_TOSHIBA_DELAY)
7089c3f0e2bSFinn Thain 				msleep(2500);
7099c3f0e2bSFinn Thain 			else
7109c3f0e2bSFinn Thain 				msleep(500);
7111da177e4SLinus Torvalds 			break;
7121da177e4SLinus Torvalds 		case 6:
713636b1ec8SFinn Thain 			shost_printk(KERN_ERR, instance, "bus locked solid\n");
7141da177e4SLinus Torvalds 			return -ENXIO;
7151da177e4SLinus Torvalds 		}
7161da177e4SLinus Torvalds 	}
7171da177e4SLinus Torvalds 	return 0;
7181da177e4SLinus Torvalds }
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds /**
7211da177e4SLinus Torvalds  *	NCR5380_exit	-	remove an NCR5380
7221da177e4SLinus Torvalds  *	@instance: adapter to remove
7231da177e4SLinus Torvalds  */
7241da177e4SLinus Torvalds 
725a43cf0f3SRandy Dunlap static void NCR5380_exit(struct Scsi_Host *instance)
7261da177e4SLinus Torvalds {
727e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
7281da177e4SLinus Torvalds 
7298d8601a7SFinn Thain 	cancel_work_sync(&hostdata->main_task);
7300ad0eff9SFinn Thain 	destroy_workqueue(hostdata->work_q);
7311da177e4SLinus Torvalds }
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds /**
734677e0194SFinn Thain  * complete_cmd - finish processing a command and return it to the SCSI ML
735677e0194SFinn Thain  * @instance: the host instance
736677e0194SFinn Thain  * @cmd: command to complete
737677e0194SFinn Thain  */
738677e0194SFinn Thain 
739677e0194SFinn Thain static void complete_cmd(struct Scsi_Host *instance,
740677e0194SFinn Thain                          struct scsi_cmnd *cmd)
741677e0194SFinn Thain {
742677e0194SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
743677e0194SFinn Thain 
744677e0194SFinn Thain 	dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd);
745677e0194SFinn Thain 
746f27db8ebSFinn Thain 	if (hostdata->sensing == cmd) {
747f27db8ebSFinn Thain 		/* Autosense processing ends here */
748f27db8ebSFinn Thain 		if ((cmd->result & 0xff) != SAM_STAT_GOOD) {
749f27db8ebSFinn Thain 			scsi_eh_restore_cmnd(cmd, &hostdata->ses);
750f27db8ebSFinn Thain 			set_host_byte(cmd, DID_ERROR);
751f27db8ebSFinn Thain 		} else
752f27db8ebSFinn Thain 			scsi_eh_restore_cmnd(cmd, &hostdata->ses);
753f27db8ebSFinn Thain 		hostdata->sensing = NULL;
754f27db8ebSFinn Thain 	}
755f27db8ebSFinn Thain 
756677e0194SFinn Thain 	hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun);
757677e0194SFinn Thain 
758677e0194SFinn Thain 	cmd->scsi_done(cmd);
759677e0194SFinn Thain }
760677e0194SFinn Thain 
761677e0194SFinn Thain /**
7621da177e4SLinus Torvalds  * NCR5380_queue_command - queue a command
7631bb40589SFinn Thain  * @instance: the relevant SCSI adapter
7641da177e4SLinus Torvalds  * @cmd: SCSI command
7651da177e4SLinus Torvalds  *
7661bb40589SFinn Thain  * cmd is added to the per-instance issue queue, with minor
7671da177e4SLinus Torvalds  * twiddling done to the host specific fields of cmd.  If the
7681da177e4SLinus Torvalds  * main coroutine is not running, it is restarted.
7691da177e4SLinus Torvalds  */
7701da177e4SLinus Torvalds 
7711bb40589SFinn Thain static int NCR5380_queue_command(struct Scsi_Host *instance,
7721bb40589SFinn Thain                                  struct scsi_cmnd *cmd)
7731da177e4SLinus Torvalds {
7741bb40589SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
77532b26a10SFinn Thain 	struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
7761bb40589SFinn Thain 	unsigned long flags;
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_WRITE)
7791da177e4SLinus Torvalds 	switch (cmd->cmnd[0]) {
7801da177e4SLinus Torvalds 	case WRITE_6:
7811da177e4SLinus Torvalds 	case WRITE_10:
782dbb6b350SFinn Thain 		shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n");
7831da177e4SLinus Torvalds 		cmd->result = (DID_ERROR << 16);
7841bb40589SFinn Thain 		cmd->scsi_done(cmd);
7851da177e4SLinus Torvalds 		return 0;
7861da177e4SLinus Torvalds 	}
7871da177e4SLinus Torvalds #endif				/* (NDEBUG & NDEBUG_NO_WRITE) */
7881da177e4SLinus Torvalds 
7891da177e4SLinus Torvalds 	cmd->result = 0;
7901da177e4SLinus Torvalds 
79111d2f63bSFinn Thain 	spin_lock_irqsave(&hostdata->lock, flags);
7921bb40589SFinn Thain 
7931da177e4SLinus Torvalds 	/*
7941da177e4SLinus Torvalds 	 * Insert the cmd into the issue queue. Note that REQUEST SENSE
7951da177e4SLinus Torvalds 	 * commands are added to the head of the queue since any command will
7961da177e4SLinus Torvalds 	 * clear the contingent allegiance condition that exists and the
7971da177e4SLinus Torvalds 	 * sense data is only guaranteed to be valid while the condition exists.
7981da177e4SLinus Torvalds 	 */
7991da177e4SLinus Torvalds 
80032b26a10SFinn Thain 	if (cmd->cmnd[0] == REQUEST_SENSE)
80132b26a10SFinn Thain 		list_add(&ncmd->list, &hostdata->unissued);
80232b26a10SFinn Thain 	else
80332b26a10SFinn Thain 		list_add_tail(&ncmd->list, &hostdata->unissued);
80432b26a10SFinn Thain 
80511d2f63bSFinn Thain 	spin_unlock_irqrestore(&hostdata->lock, flags);
8061bb40589SFinn Thain 
807dbb6b350SFinn Thain 	dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n",
808dbb6b350SFinn Thain 	         cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
8091da177e4SLinus Torvalds 
8101da177e4SLinus Torvalds 	/* Kick off command processing */
8118d8601a7SFinn Thain 	queue_work(hostdata->work_q, &hostdata->main_task);
8121da177e4SLinus Torvalds 	return 0;
8131da177e4SLinus Torvalds }
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds /**
816f27db8ebSFinn Thain  * dequeue_next_cmd - dequeue a command for processing
817f27db8ebSFinn Thain  * @instance: the scsi host instance
818f27db8ebSFinn Thain  *
819f27db8ebSFinn Thain  * Priority is given to commands on the autosense queue. These commands
820f27db8ebSFinn Thain  * need autosense because of a CHECK CONDITION result.
821f27db8ebSFinn Thain  *
822f27db8ebSFinn Thain  * Returns a command pointer if a command is found for a target that is
823f27db8ebSFinn Thain  * not already busy. Otherwise returns NULL.
824f27db8ebSFinn Thain  */
825f27db8ebSFinn Thain 
826f27db8ebSFinn Thain static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance)
827f27db8ebSFinn Thain {
828f27db8ebSFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
829f27db8ebSFinn Thain 	struct NCR5380_cmd *ncmd;
830f27db8ebSFinn Thain 	struct scsi_cmnd *cmd;
831f27db8ebSFinn Thain 
832f27db8ebSFinn Thain 	if (list_empty(&hostdata->autosense)) {
833f27db8ebSFinn Thain 		list_for_each_entry(ncmd, &hostdata->unissued, list) {
834f27db8ebSFinn Thain 			cmd = NCR5380_to_scmd(ncmd);
835f27db8ebSFinn Thain 			dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n",
836f27db8ebSFinn Thain 			         cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun);
837f27db8ebSFinn Thain 
838f27db8ebSFinn Thain 			if (!(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))) {
839f27db8ebSFinn Thain 				list_del(&ncmd->list);
840f27db8ebSFinn Thain 				dsprintk(NDEBUG_QUEUES, instance,
841f27db8ebSFinn Thain 				         "dequeue: removed %p from issue queue\n", cmd);
842f27db8ebSFinn Thain 				return cmd;
843f27db8ebSFinn Thain 			}
844f27db8ebSFinn Thain 		}
845f27db8ebSFinn Thain 	} else {
846f27db8ebSFinn Thain 		/* Autosense processing begins here */
847f27db8ebSFinn Thain 		ncmd = list_first_entry(&hostdata->autosense,
848f27db8ebSFinn Thain 		                        struct NCR5380_cmd, list);
849f27db8ebSFinn Thain 		list_del(&ncmd->list);
850f27db8ebSFinn Thain 		cmd = NCR5380_to_scmd(ncmd);
851f27db8ebSFinn Thain 		dsprintk(NDEBUG_QUEUES, instance,
852f27db8ebSFinn Thain 		         "dequeue: removed %p from autosense queue\n", cmd);
853f27db8ebSFinn Thain 		scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
854f27db8ebSFinn Thain 		hostdata->sensing = cmd;
855f27db8ebSFinn Thain 		return cmd;
856f27db8ebSFinn Thain 	}
857f27db8ebSFinn Thain 	return NULL;
858f27db8ebSFinn Thain }
859f27db8ebSFinn Thain 
860f27db8ebSFinn Thain static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
861f27db8ebSFinn Thain {
862f27db8ebSFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
863f27db8ebSFinn Thain 	struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
864f27db8ebSFinn Thain 
865f27db8ebSFinn Thain 	if (hostdata->sensing) {
866f27db8ebSFinn Thain 		scsi_eh_restore_cmnd(cmd, &hostdata->ses);
867f27db8ebSFinn Thain 		list_add(&ncmd->list, &hostdata->autosense);
868f27db8ebSFinn Thain 		hostdata->sensing = NULL;
869f27db8ebSFinn Thain 	} else
870f27db8ebSFinn Thain 		list_add(&ncmd->list, &hostdata->unissued);
871f27db8ebSFinn Thain }
872f27db8ebSFinn Thain 
873f27db8ebSFinn Thain /**
8741da177e4SLinus Torvalds  *	NCR5380_main	-	NCR state machines
8751da177e4SLinus Torvalds  *
8761da177e4SLinus Torvalds  *	NCR5380_main is a coroutine that runs as long as more work can
8771da177e4SLinus Torvalds  *      be done on the NCR5380 host adapters in a system.  Both
8781da177e4SLinus Torvalds  *      NCR5380_queue_command() and NCR5380_intr() will try to start it
8791da177e4SLinus Torvalds  *      in case it is not running.
8801da177e4SLinus Torvalds  *
8811da177e4SLinus Torvalds  *	Locks: called as its own thread with no locks held. Takes the
8821da177e4SLinus Torvalds  *	host lock and called routines may take the isa dma lock.
8831da177e4SLinus Torvalds  */
8841da177e4SLinus Torvalds 
885c4028958SDavid Howells static void NCR5380_main(struct work_struct *work)
8861da177e4SLinus Torvalds {
887c4028958SDavid Howells 	struct NCR5380_hostdata *hostdata =
8888d8601a7SFinn Thain 		container_of(work, struct NCR5380_hostdata, main_task);
8891da177e4SLinus Torvalds 	struct Scsi_Host *instance = hostdata->host;
890f27db8ebSFinn Thain 	struct scsi_cmnd *cmd;
8911da177e4SLinus Torvalds 	int done;
8921da177e4SLinus Torvalds 
89311d2f63bSFinn Thain 	spin_lock_irq(&hostdata->lock);
8941da177e4SLinus Torvalds 	do {
8951da177e4SLinus Torvalds 		done = 1;
89611d2f63bSFinn Thain 
897f27db8ebSFinn Thain 		while (!hostdata->connected &&
898f27db8ebSFinn Thain 		       (cmd = dequeue_next_cmd(instance))) {
89932b26a10SFinn Thain 
900f27db8ebSFinn Thain 			dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd);
9011da177e4SLinus Torvalds 
9021da177e4SLinus Torvalds 			/*
9031da177e4SLinus Torvalds 			 * Attempt to establish an I_T_L nexus here.
9041da177e4SLinus Torvalds 			 * On success, instance->hostdata->connected is set.
9051da177e4SLinus Torvalds 			 * On failure, we must add the command back to the
9061da177e4SLinus Torvalds 			 * issue queue so we can keep trying.
9071da177e4SLinus Torvalds 			 */
9081da177e4SLinus Torvalds 			/*
9091da177e4SLinus Torvalds 			 * REQUEST SENSE commands are issued without tagged
9101da177e4SLinus Torvalds 			 * queueing, even on SCSI-II devices because the
9111da177e4SLinus Torvalds 			 * contingent allegiance condition exists for the
9121da177e4SLinus Torvalds 			 * entire unit.
9131da177e4SLinus Torvalds 			 */
91476f13b93SFinn Thain 
915707d62b3SFinn Thain 			cmd = NCR5380_select(instance, cmd);
916707d62b3SFinn Thain 			if (!cmd) {
917707d62b3SFinn Thain 				dsprintk(NDEBUG_MAIN, instance, "main: select complete\n");
9181da177e4SLinus Torvalds 			} else {
919f27db8ebSFinn Thain 				dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance,
920f27db8ebSFinn Thain 				         "main: select failed, returning %p to queue\n", cmd);
921f27db8ebSFinn Thain 				requeue_cmd(instance, cmd);
9221da177e4SLinus Torvalds 			}
923f27db8ebSFinn Thain 		}
9241da177e4SLinus Torvalds 		if (hostdata->connected
9251da177e4SLinus Torvalds #ifdef REAL_DMA
9261da177e4SLinus Torvalds 		    && !hostdata->dmalen
9271da177e4SLinus Torvalds #endif
9281da177e4SLinus Torvalds 		    ) {
92952a6a1cbSFinn Thain 			dprintk(NDEBUG_MAIN, "scsi%d : main() : performing information transfer\n", instance->host_no);
9301da177e4SLinus Torvalds 			NCR5380_information_transfer(instance);
93152a6a1cbSFinn Thain 			dprintk(NDEBUG_MAIN, "scsi%d : main() : done set false\n", instance->host_no);
9321da177e4SLinus Torvalds 			done = 0;
9331d3db59dSFinn Thain 		}
9341da177e4SLinus Torvalds 	} while (!done);
93511d2f63bSFinn Thain 	spin_unlock_irq(&hostdata->lock);
9361da177e4SLinus Torvalds }
9371da177e4SLinus Torvalds 
9381da177e4SLinus Torvalds #ifndef DONT_USE_INTR
9391da177e4SLinus Torvalds 
9401da177e4SLinus Torvalds /**
9411da177e4SLinus Torvalds  * NCR5380_intr - generic NCR5380 irq handler
9421da177e4SLinus Torvalds  * @irq: interrupt number
9431da177e4SLinus Torvalds  * @dev_id: device info
9441da177e4SLinus Torvalds  *
9451da177e4SLinus Torvalds  * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
9461da177e4SLinus Torvalds  * from the disconnected queue, and restarting NCR5380_main()
9471da177e4SLinus Torvalds  * as required.
9481da177e4SLinus Torvalds  *
949cd400825SFinn Thain  * The chip can assert IRQ in any of six different conditions. The IRQ flag
950cd400825SFinn Thain  * is then cleared by reading the Reset Parity/Interrupt Register (RPIR).
951cd400825SFinn Thain  * Three of these six conditions are latched in the Bus and Status Register:
952cd400825SFinn Thain  * - End of DMA (cleared by ending DMA Mode)
953cd400825SFinn Thain  * - Parity error (cleared by reading RPIR)
954cd400825SFinn Thain  * - Loss of BSY (cleared by reading RPIR)
955cd400825SFinn Thain  * Two conditions have flag bits that are not latched:
956cd400825SFinn Thain  * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode)
957cd400825SFinn Thain  * - Bus reset (non-maskable)
958cd400825SFinn Thain  * The remaining condition has no flag bit at all:
959cd400825SFinn Thain  * - Selection/reselection
960cd400825SFinn Thain  *
961cd400825SFinn Thain  * Hence, establishing the cause(s) of any interrupt is partly guesswork.
962cd400825SFinn Thain  * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor
963cd400825SFinn Thain  * claimed that "the design of the [DP8490] interrupt logic ensures
964cd400825SFinn Thain  * interrupts will not be lost (they can be on the DP5380)."
965cd400825SFinn Thain  * The L5380/53C80 datasheet from LOGIC Devices has more details.
966cd400825SFinn Thain  *
967cd400825SFinn Thain  * Checking for bus reset by reading RST is futile because of interrupt
968cd400825SFinn Thain  * latency, but a bus reset will reset chip logic. Checking for parity error
969cd400825SFinn Thain  * is unnecessary because that interrupt is never enabled. A Loss of BSY
970cd400825SFinn Thain  * condition will clear DMA Mode. We can tell when this occurs because the
971cd400825SFinn Thain  * the Busy Monitor interrupt is enabled together with DMA Mode.
9721da177e4SLinus Torvalds  */
9731da177e4SLinus Torvalds 
974cd400825SFinn Thain static irqreturn_t NCR5380_intr(int irq, void *dev_id)
9751da177e4SLinus Torvalds {
976baa9aac6SJeff Garzik 	struct Scsi_Host *instance = dev_id;
977cd400825SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
978cd400825SFinn Thain 	int handled = 0;
9791da177e4SLinus Torvalds 	unsigned char basr;
9801da177e4SLinus Torvalds 	unsigned long flags;
9811da177e4SLinus Torvalds 
98211d2f63bSFinn Thain 	spin_lock_irqsave(&hostdata->lock, flags);
983cd400825SFinn Thain 
9841da177e4SLinus Torvalds 	basr = NCR5380_read(BUS_AND_STATUS_REG);
9851da177e4SLinus Torvalds 	if (basr & BASR_IRQ) {
986cd400825SFinn Thain 		unsigned char mr = NCR5380_read(MODE_REG);
987cd400825SFinn Thain 		unsigned char sr = NCR5380_read(STATUS_REG);
988cd400825SFinn Thain 
989cd400825SFinn Thain 		dprintk(NDEBUG_INTR, "scsi%d: IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n",
990cd400825SFinn Thain 		        instance->host_no, irq, basr, sr, mr);
991cd400825SFinn Thain 
9921da177e4SLinus Torvalds #if defined(REAL_DMA)
993cd400825SFinn Thain 		if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) {
994cd400825SFinn Thain 			/* Probably End of DMA, Phase Mismatch or Loss of BSY.
995cd400825SFinn Thain 			 * We ack IRQ after clearing Mode Register. Workarounds
996cd400825SFinn Thain 			 * for End of DMA errata need to happen in DMA Mode.
9971da177e4SLinus Torvalds 			 */
9981da177e4SLinus Torvalds 
999cd400825SFinn Thain 			dprintk(NDEBUG_INTR, "scsi%d: interrupt in DMA mode\n", intance->host_no);
1000cd400825SFinn Thain 
100125985edcSLucas De Marchi 			int transferred;
10021da177e4SLinus Torvalds 
10031da177e4SLinus Torvalds 			if (!hostdata->connected)
1004cd400825SFinn Thain 				panic("scsi%d : DMA interrupt with no connected cmd\n",
1005cd400825SFinn Thain 				      instance->hostno);
10061da177e4SLinus Torvalds 
1007cd400825SFinn Thain 			transferred = hostdata->dmalen - NCR5380_dma_residual(instance);
10081da177e4SLinus Torvalds 			hostdata->connected->SCp.this_residual -= transferred;
10091da177e4SLinus Torvalds 			hostdata->connected->SCp.ptr += transferred;
10101da177e4SLinus Torvalds 			hostdata->dmalen = 0;
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds 			/* FIXME: we need to poll briefly then defer a workqueue task ! */
10131da177e4SLinus Torvalds 			NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2 * HZ);
10141da177e4SLinus Torvalds 
10151da177e4SLinus Torvalds 			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
1016cd400825SFinn Thain 			NCR5380_write(MODE_REG, MR_BASE);
1017cd400825SFinn Thain 			NCR5380_read(RESET_PARITY_INTERRUPT_REG);
1018cd400825SFinn Thain 		} else
1019cd400825SFinn Thain #endif /* REAL_DMA */
1020cd400825SFinn Thain 		if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) &&
1021cd400825SFinn Thain 		    (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) {
1022cd400825SFinn Thain 			/* Probably reselected */
1023cd400825SFinn Thain 			NCR5380_write(SELECT_ENABLE_REG, 0);
1024cd400825SFinn Thain 			NCR5380_read(RESET_PARITY_INTERRUPT_REG);
1025cd400825SFinn Thain 
1026cd400825SFinn Thain 			dprintk(NDEBUG_INTR, "scsi%d: interrupt with SEL and IO\n",
1027cd400825SFinn Thain 			        instance->host_no);
1028cd400825SFinn Thain 
1029cd400825SFinn Thain 			if (!hostdata->connected) {
1030cd400825SFinn Thain 				NCR5380_reselect(instance);
10318d8601a7SFinn Thain 				queue_work(hostdata->work_q, &hostdata->main_task);
1032cd400825SFinn Thain 			}
1033cd400825SFinn Thain 			if (!hostdata->connected)
1034cd400825SFinn Thain 				NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
1035cd400825SFinn Thain 		} else {
1036cd400825SFinn Thain 			/* Probably Bus Reset */
1037cd400825SFinn Thain 			NCR5380_read(RESET_PARITY_INTERRUPT_REG);
1038cd400825SFinn Thain 
1039cd400825SFinn Thain 			dprintk(NDEBUG_INTR, "scsi%d: unknown interrupt\n", instance->host_no);
1040cd400825SFinn Thain 		}
1041cd400825SFinn Thain 		handled = 1;
1042cd400825SFinn Thain 	} else {
1043cd400825SFinn Thain 		shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n");
1044cd400825SFinn Thain 	}
1045cd400825SFinn Thain 
104611d2f63bSFinn Thain 	spin_unlock_irqrestore(&hostdata->lock, flags);
1047cd400825SFinn Thain 
1048cd400825SFinn Thain 	return IRQ_RETVAL(handled);
10491da177e4SLinus Torvalds }
10501da177e4SLinus Torvalds 
10511da177e4SLinus Torvalds #endif
10521da177e4SLinus Torvalds 
10531da177e4SLinus Torvalds /*
1054710ddd0dSFinn Thain  * Function : int NCR5380_select(struct Scsi_Host *instance,
1055710ddd0dSFinn Thain  *                               struct scsi_cmnd *cmd)
10561da177e4SLinus Torvalds  *
10571da177e4SLinus Torvalds  * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
10581da177e4SLinus Torvalds  *      including ARBITRATION, SELECTION, and initial message out for
10591da177e4SLinus Torvalds  *      IDENTIFY and queue messages.
10601da177e4SLinus Torvalds  *
10611da177e4SLinus Torvalds  * Inputs : instance - instantiation of the 5380 driver on which this
106276f13b93SFinn Thain  *      target lives, cmd - SCSI command to execute.
10631da177e4SLinus Torvalds  *
1064707d62b3SFinn Thain  * Returns cmd if selection failed but should be retried,
1065707d62b3SFinn Thain  * NULL if selection failed and should not be retried, or
1066707d62b3SFinn Thain  * NULL if selection succeeded (hostdata->connected == cmd).
10671da177e4SLinus Torvalds  *
10681da177e4SLinus Torvalds  * Side effects :
10691da177e4SLinus Torvalds  *      If bus busy, arbitration failed, etc, NCR5380_select() will exit
10701da177e4SLinus Torvalds  *              with registers as they should have been on entry - ie
10711da177e4SLinus Torvalds  *              SELECT_ENABLE will be set appropriately, the NCR5380
10721da177e4SLinus Torvalds  *              will cease to drive any SCSI bus signals.
10731da177e4SLinus Torvalds  *
10741da177e4SLinus Torvalds  *      If successful : I_T_L or I_T_L_Q nexus will be established,
10751da177e4SLinus Torvalds  *              instance->connected will be set to cmd.
10761da177e4SLinus Torvalds  *              SELECT interrupt will be disabled.
10771da177e4SLinus Torvalds  *
10781da177e4SLinus Torvalds  *      If failed (no target) : cmd->scsi_done() will be called, and the
10791da177e4SLinus Torvalds  *              cmd->result host byte set to DID_BAD_TARGET.
10801da177e4SLinus Torvalds  *
10811da177e4SLinus Torvalds  *	Locks: caller holds hostdata lock in IRQ mode
10821da177e4SLinus Torvalds  */
10831da177e4SLinus Torvalds 
1084707d62b3SFinn Thain static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
1085707d62b3SFinn Thain                                         struct scsi_cmnd *cmd)
10861da177e4SLinus Torvalds {
1087e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
10881da177e4SLinus Torvalds 	unsigned char tmp[3], phase;
10891da177e4SLinus Torvalds 	unsigned char *data;
10901da177e4SLinus Torvalds 	int len;
10911da177e4SLinus Torvalds 	int err;
10921da177e4SLinus Torvalds 
10931da177e4SLinus Torvalds 	NCR5380_dprint(NDEBUG_ARBITRATION, instance);
109452a6a1cbSFinn Thain 	dprintk(NDEBUG_ARBITRATION, "scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id);
10951da177e4SLinus Torvalds 
10961da177e4SLinus Torvalds 	/*
1097707d62b3SFinn Thain 	 * Arbitration and selection phases are slow and involve dropping the
1098707d62b3SFinn Thain 	 * lock, so we have to watch out for EH. An exception handler may
1099707d62b3SFinn Thain 	 * change 'selecting' to NULL. This function will then return NULL
1100707d62b3SFinn Thain 	 * so that the caller will forget about 'cmd'. (During information
1101707d62b3SFinn Thain 	 * transfer phases, EH may change 'connected' to NULL.)
1102707d62b3SFinn Thain 	 */
1103707d62b3SFinn Thain 	hostdata->selecting = cmd;
1104707d62b3SFinn Thain 
1105707d62b3SFinn Thain 	/*
11061da177e4SLinus Torvalds 	 * Set the phase bits to 0, otherwise the NCR5380 won't drive the
11071da177e4SLinus Torvalds 	 * data bus during SELECTION.
11081da177e4SLinus Torvalds 	 */
11091da177e4SLinus Torvalds 
11101da177e4SLinus Torvalds 	NCR5380_write(TARGET_COMMAND_REG, 0);
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 	/*
11131da177e4SLinus Torvalds 	 * Start arbitration.
11141da177e4SLinus Torvalds 	 */
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds 	NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
11171da177e4SLinus Torvalds 	NCR5380_write(MODE_REG, MR_ARBITRATE);
11181da177e4SLinus Torvalds 
111955500d9bSFinn Thain 	/* The chip now waits for BUS FREE phase. Then after the 800 ns
112055500d9bSFinn Thain 	 * Bus Free Delay, arbitration will begin.
11211da177e4SLinus Torvalds 	 */
11221da177e4SLinus Torvalds 
112311d2f63bSFinn Thain 	spin_unlock_irq(&hostdata->lock);
1124b32ade12SFinn Thain 	err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0,
1125b32ade12SFinn Thain 	                INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS,
1126b32ade12SFinn Thain 	                                       ICR_ARBITRATION_PROGRESS, HZ);
112711d2f63bSFinn Thain 	spin_lock_irq(&hostdata->lock);
112855500d9bSFinn Thain 	if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) {
112955500d9bSFinn Thain 		/* Reselection interrupt */
1130707d62b3SFinn Thain 		goto out;
113155500d9bSFinn Thain 	}
1132b32ade12SFinn Thain 	if (err < 0) {
1133b32ade12SFinn Thain 		NCR5380_write(MODE_REG, MR_BASE);
1134b32ade12SFinn Thain 		shost_printk(KERN_ERR, instance,
1135b32ade12SFinn Thain 		             "select: arbitration timeout\n");
1136707d62b3SFinn Thain 		goto out;
113755500d9bSFinn Thain 	}
113811d2f63bSFinn Thain 	spin_unlock_irq(&hostdata->lock);
113955500d9bSFinn Thain 
114055500d9bSFinn Thain 	/* The SCSI-2 arbitration delay is 2.4 us */
11411da177e4SLinus Torvalds 	udelay(3);
11421da177e4SLinus Torvalds 
11431da177e4SLinus Torvalds 	/* Check for lost arbitration */
11441da177e4SLinus Torvalds 	if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
11451da177e4SLinus Torvalds 		NCR5380_write(MODE_REG, MR_BASE);
114652a6a1cbSFinn Thain 		dprintk(NDEBUG_ARBITRATION, "scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no);
114711d2f63bSFinn Thain 		spin_lock_irq(&hostdata->lock);
1148707d62b3SFinn Thain 		goto out;
11491da177e4SLinus Torvalds 	}
1150cf13b083SFinn Thain 
1151cf13b083SFinn Thain 	/* After/during arbitration, BSY should be asserted.
1152cf13b083SFinn Thain 	 * IBM DPES-31080 Version S31Q works now
1153cf13b083SFinn Thain 	 * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman)
1154cf13b083SFinn Thain 	 */
1155cf13b083SFinn Thain 	NCR5380_write(INITIATOR_COMMAND_REG,
1156cf13b083SFinn Thain 		      ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 	/*
11591da177e4SLinus Torvalds 	 * Again, bus clear + bus settle time is 1.2us, however, this is
11601da177e4SLinus Torvalds 	 * a minimum so we'll udelay ceil(1.2)
11611da177e4SLinus Torvalds 	 */
11621da177e4SLinus Torvalds 
11639c3f0e2bSFinn Thain 	if (hostdata->flags & FLAG_TOSHIBA_DELAY)
11649c3f0e2bSFinn Thain 		udelay(15);
11659c3f0e2bSFinn Thain 	else
11661da177e4SLinus Torvalds 		udelay(2);
11671da177e4SLinus Torvalds 
116811d2f63bSFinn Thain 	spin_lock_irq(&hostdata->lock);
116911d2f63bSFinn Thain 
117072064a78SFinn Thain 	/* NCR5380_reselect() clears MODE_REG after a reselection interrupt */
117172064a78SFinn Thain 	if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE))
1172707d62b3SFinn Thain 		goto out;
1173707d62b3SFinn Thain 
1174707d62b3SFinn Thain 	if (!hostdata->selecting) {
1175707d62b3SFinn Thain 		NCR5380_write(MODE_REG, MR_BASE);
1176707d62b3SFinn Thain 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
1177707d62b3SFinn Thain 		goto out;
1178707d62b3SFinn Thain 	}
117972064a78SFinn Thain 
118052a6a1cbSFinn Thain 	dprintk(NDEBUG_ARBITRATION, "scsi%d : won arbitration\n", instance->host_no);
11811da177e4SLinus Torvalds 
11821da177e4SLinus Torvalds 	/*
11831da177e4SLinus Torvalds 	 * Now that we have won arbitration, start Selection process, asserting
11841da177e4SLinus Torvalds 	 * the host and target ID's on the SCSI bus.
11851da177e4SLinus Torvalds 	 */
11861da177e4SLinus Torvalds 
1187422c0d61SJeff Garzik 	NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << scmd_id(cmd))));
11881da177e4SLinus Torvalds 
11891da177e4SLinus Torvalds 	/*
11901da177e4SLinus Torvalds 	 * Raise ATN while SEL is true before BSY goes false from arbitration,
11911da177e4SLinus Torvalds 	 * since this is the only way to guarantee that we'll get a MESSAGE OUT
11921da177e4SLinus Torvalds 	 * phase immediately after selection.
11931da177e4SLinus Torvalds 	 */
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
11961da177e4SLinus Torvalds 	NCR5380_write(MODE_REG, MR_BASE);
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 	/*
11991da177e4SLinus Torvalds 	 * Reselect interrupts must be turned off prior to the dropping of BSY,
12001da177e4SLinus Torvalds 	 * otherwise we will trigger an interrupt.
12011da177e4SLinus Torvalds 	 */
12021da177e4SLinus Torvalds 	NCR5380_write(SELECT_ENABLE_REG, 0);
12031da177e4SLinus Torvalds 
120411d2f63bSFinn Thain 	spin_unlock_irq(&hostdata->lock);
120511d2f63bSFinn Thain 
12061da177e4SLinus Torvalds 	/*
12071da177e4SLinus Torvalds 	 * The initiator shall then wait at least two deskew delays and release
12081da177e4SLinus Torvalds 	 * the BSY signal.
12091da177e4SLinus Torvalds 	 */
12101da177e4SLinus Torvalds 	udelay(1);		/* wingel -- wait two bus deskew delay >2*45ns */
12111da177e4SLinus Torvalds 
12121da177e4SLinus Torvalds 	/* Reset BSY */
12131da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
12141da177e4SLinus Torvalds 
12151da177e4SLinus Torvalds 	/*
12161da177e4SLinus Torvalds 	 * Something weird happens when we cease to drive BSY - looks
12171da177e4SLinus Torvalds 	 * like the board/chip is letting us do another read before the
12181da177e4SLinus Torvalds 	 * appropriate propagation delay has expired, and we're confusing
12191da177e4SLinus Torvalds 	 * a BSY signal from ourselves as the target's response to SELECTION.
12201da177e4SLinus Torvalds 	 *
12211da177e4SLinus Torvalds 	 * A small delay (the 'C++' frontend breaks the pipeline with an
12221da177e4SLinus Torvalds 	 * unnecessary jump, making it work on my 386-33/Trantor T128, the
12231da177e4SLinus Torvalds 	 * tighter 'C' code breaks and requires this) solves the problem -
12241da177e4SLinus Torvalds 	 * the 1 us delay is arbitrary, and only used because this delay will
12251da177e4SLinus Torvalds 	 * be the same on other platforms and since it works here, it should
12261da177e4SLinus Torvalds 	 * work there.
12271da177e4SLinus Torvalds 	 *
12281da177e4SLinus Torvalds 	 * wingel suggests that this could be due to failing to wait
12291da177e4SLinus Torvalds 	 * one deskew delay.
12301da177e4SLinus Torvalds 	 */
12311da177e4SLinus Torvalds 
12321da177e4SLinus Torvalds 	udelay(1);
12331da177e4SLinus Torvalds 
123452a6a1cbSFinn Thain 	dprintk(NDEBUG_SELECTION, "scsi%d : selecting target %d\n", instance->host_no, scmd_id(cmd));
12351da177e4SLinus Torvalds 
12361da177e4SLinus Torvalds 	/*
12371da177e4SLinus Torvalds 	 * The SCSI specification calls for a 250 ms timeout for the actual
12381da177e4SLinus Torvalds 	 * selection.
12391da177e4SLinus Torvalds 	 */
12401da177e4SLinus Torvalds 
1241ae753a33SFinn Thain 	err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY,
1242ae753a33SFinn Thain 	                            msecs_to_jiffies(250));
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 	if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
124511d2f63bSFinn Thain 		spin_lock_irq(&hostdata->lock);
12461da177e4SLinus Torvalds 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
12471da177e4SLinus Torvalds 		NCR5380_reselect(instance);
1248cd400825SFinn Thain 		if (!hostdata->connected)
12491da177e4SLinus Torvalds 			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
1250cd400825SFinn Thain 		printk("scsi%d : reselection after won arbitration?\n", instance->host_no);
1251707d62b3SFinn Thain 		goto out;
12521da177e4SLinus Torvalds 	}
1253ae753a33SFinn Thain 
1254ae753a33SFinn Thain 	if (err < 0) {
125511d2f63bSFinn Thain 		spin_lock_irq(&hostdata->lock);
1256ae753a33SFinn Thain 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
1257707d62b3SFinn Thain 		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
1258707d62b3SFinn Thain 		/* Can't touch cmd if it has been reclaimed by the scsi ML */
1259707d62b3SFinn Thain 		if (hostdata->selecting) {
1260ae753a33SFinn Thain 			cmd->result = DID_BAD_TARGET << 16;
1261677e0194SFinn Thain 			complete_cmd(instance, cmd);
1262707d62b3SFinn Thain 			dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n");
1263707d62b3SFinn Thain 			cmd = NULL;
1264707d62b3SFinn Thain 		}
1265707d62b3SFinn Thain 		goto out;
1266ae753a33SFinn Thain 	}
1267ae753a33SFinn Thain 
12681da177e4SLinus Torvalds 	/*
12691da177e4SLinus Torvalds 	 * No less than two deskew delays after the initiator detects the
12701da177e4SLinus Torvalds 	 * BSY signal is true, it shall release the SEL signal and may
12711da177e4SLinus Torvalds 	 * change the DATA BUS.                                     -wingel
12721da177e4SLinus Torvalds 	 */
12731da177e4SLinus Torvalds 
12741da177e4SLinus Torvalds 	udelay(1);
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
12771da177e4SLinus Torvalds 
12781da177e4SLinus Torvalds 	/*
12791da177e4SLinus Torvalds 	 * Since we followed the SCSI spec, and raised ATN while SEL
12801da177e4SLinus Torvalds 	 * was true but before BSY was false during selection, the information
12811da177e4SLinus Torvalds 	 * transfer phase should be a MESSAGE OUT phase so that we can send the
12821da177e4SLinus Torvalds 	 * IDENTIFY message.
12831da177e4SLinus Torvalds 	 *
12841da177e4SLinus Torvalds 	 * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
12851da177e4SLinus Torvalds 	 * message (2 bytes) with a tag ID that we increment with every command
12861da177e4SLinus Torvalds 	 * until it wraps back to 0.
12871da177e4SLinus Torvalds 	 *
12881da177e4SLinus Torvalds 	 * XXX - it turns out that there are some broken SCSI-II devices,
12891da177e4SLinus Torvalds 	 *       which claim to support tagged queuing but fail when more than
12901da177e4SLinus Torvalds 	 *       some number of commands are issued at once.
12911da177e4SLinus Torvalds 	 */
12921da177e4SLinus Torvalds 
12931da177e4SLinus Torvalds 	/* Wait for start of REQ/ACK handshake */
12941da177e4SLinus Torvalds 
12951da177e4SLinus Torvalds 	err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
129611d2f63bSFinn Thain 	spin_lock_irq(&hostdata->lock);
12971cc160e1SFinn Thain 	if (err < 0) {
129855500d9bSFinn Thain 		shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
129955500d9bSFinn Thain 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
13001da177e4SLinus Torvalds 		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
1301707d62b3SFinn Thain 		goto out;
1302707d62b3SFinn Thain 	}
1303707d62b3SFinn Thain 	if (!hostdata->selecting) {
1304707d62b3SFinn Thain 		do_abort(instance);
1305707d62b3SFinn Thain 		goto out;
13061da177e4SLinus Torvalds 	}
13071da177e4SLinus Torvalds 
130852a6a1cbSFinn Thain 	dprintk(NDEBUG_SELECTION, "scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id);
130922f5f10dSFinn Thain 	tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun);
13101da177e4SLinus Torvalds 
13111da177e4SLinus Torvalds 	len = 1;
13121da177e4SLinus Torvalds 	cmd->tag = 0;
13131da177e4SLinus Torvalds 
13141da177e4SLinus Torvalds 	/* Send message(s) */
13151da177e4SLinus Torvalds 	data = tmp;
13161da177e4SLinus Torvalds 	phase = PHASE_MSGOUT;
13171da177e4SLinus Torvalds 	NCR5380_transfer_pio(instance, &phase, &len, &data);
131852a6a1cbSFinn Thain 	dprintk(NDEBUG_SELECTION, "scsi%d : nexus established.\n", instance->host_no);
13191da177e4SLinus Torvalds 	/* XXX need to handle errors here */
132011d2f63bSFinn Thain 
13211da177e4SLinus Torvalds 	hostdata->connected = cmd;
13229cb78c16SHannes Reinecke 	hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF));
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 	initialize_SCp(cmd);
13251da177e4SLinus Torvalds 
1326707d62b3SFinn Thain 	cmd = NULL;
1327707d62b3SFinn Thain 
1328707d62b3SFinn Thain out:
1329707d62b3SFinn Thain 	if (!hostdata->selecting)
1330707d62b3SFinn Thain 		return NULL;
1331707d62b3SFinn Thain 	hostdata->selecting = NULL;
1332707d62b3SFinn Thain 	return cmd;
13331da177e4SLinus Torvalds }
13341da177e4SLinus Torvalds 
13351da177e4SLinus Torvalds /*
13361da177e4SLinus Torvalds  * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
13371da177e4SLinus Torvalds  *      unsigned char *phase, int *count, unsigned char **data)
13381da177e4SLinus Torvalds  *
13391da177e4SLinus Torvalds  * Purpose : transfers data in given phase using polled I/O
13401da177e4SLinus Torvalds  *
13411da177e4SLinus Torvalds  * Inputs : instance - instance of driver, *phase - pointer to
13421da177e4SLinus Torvalds  *      what phase is expected, *count - pointer to number of
13431da177e4SLinus Torvalds  *      bytes to transfer, **data - pointer to data pointer.
13441da177e4SLinus Torvalds  *
13451da177e4SLinus Torvalds  * Returns : -1 when different phase is entered without transferring
134625985edcSLucas De Marchi  *      maximum number of bytes, 0 if all bytes or transferred or exit
13471da177e4SLinus Torvalds  *      is in same phase.
13481da177e4SLinus Torvalds  *
13491da177e4SLinus Torvalds  *      Also, *phase, *count, *data are modified in place.
13501da177e4SLinus Torvalds  *
13511da177e4SLinus Torvalds  * XXX Note : handling for bus free may be useful.
13521da177e4SLinus Torvalds  */
13531da177e4SLinus Torvalds 
13541da177e4SLinus Torvalds /*
13551da177e4SLinus Torvalds  * Note : this code is not as quick as it could be, however it
13561da177e4SLinus Torvalds  * IS 100% reliable, and for the actual data transfer where speed
13571da177e4SLinus Torvalds  * counts, we will always do a pseudo DMA or DMA transfer.
13581da177e4SLinus Torvalds  */
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
13611da177e4SLinus Torvalds 	unsigned char p = *phase, tmp;
13621da177e4SLinus Torvalds 	int c = *count;
13631da177e4SLinus Torvalds 	unsigned char *d = *data;
13641da177e4SLinus Torvalds 
13651da177e4SLinus Torvalds 	if (!(p & SR_IO))
136652a6a1cbSFinn Thain 		dprintk(NDEBUG_PIO, "scsi%d : pio write %d bytes\n", instance->host_no, c);
13671da177e4SLinus Torvalds 	else
136852a6a1cbSFinn Thain 		dprintk(NDEBUG_PIO, "scsi%d : pio read %d bytes\n", instance->host_no, c);
13691da177e4SLinus Torvalds 
13701da177e4SLinus Torvalds 	/*
13711da177e4SLinus Torvalds 	 * The NCR5380 chip will only drive the SCSI bus when the
13721da177e4SLinus Torvalds 	 * phase specified in the appropriate bits of the TARGET COMMAND
13731da177e4SLinus Torvalds 	 * REGISTER match the STATUS REGISTER
13741da177e4SLinus Torvalds 	 */
13751da177e4SLinus Torvalds 
13761da177e4SLinus Torvalds 	 NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
13771da177e4SLinus Torvalds 
13781da177e4SLinus Torvalds 	do {
13791da177e4SLinus Torvalds 		/*
13801da177e4SLinus Torvalds 		 * Wait for assertion of REQ, after which the phase bits will be
13811da177e4SLinus Torvalds 		 * valid
13821da177e4SLinus Torvalds 		 */
13831da177e4SLinus Torvalds 
1384686f3990SFinn Thain 		if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0)
13851da177e4SLinus Torvalds 			break;
13861da177e4SLinus Torvalds 
138752a6a1cbSFinn Thain 		dprintk(NDEBUG_HANDSHAKE, "scsi%d : REQ detected\n", instance->host_no);
13881da177e4SLinus Torvalds 
13891da177e4SLinus Torvalds 		/* Check for phase mismatch */
1390686f3990SFinn Thain 		if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) {
139152a6a1cbSFinn Thain 			dprintk(NDEBUG_HANDSHAKE, "scsi%d : phase mismatch\n", instance->host_no);
13921da177e4SLinus Torvalds 			NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance);
13931da177e4SLinus Torvalds 			break;
13941da177e4SLinus Torvalds 		}
13951da177e4SLinus Torvalds 		/* Do actual transfer from SCSI bus to / from memory */
13961da177e4SLinus Torvalds 		if (!(p & SR_IO))
13971da177e4SLinus Torvalds 			NCR5380_write(OUTPUT_DATA_REG, *d);
13981da177e4SLinus Torvalds 		else
13991da177e4SLinus Torvalds 			*d = NCR5380_read(CURRENT_SCSI_DATA_REG);
14001da177e4SLinus Torvalds 
14011da177e4SLinus Torvalds 		++d;
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds 		/*
14041da177e4SLinus Torvalds 		 * The SCSI standard suggests that in MSGOUT phase, the initiator
14051da177e4SLinus Torvalds 		 * should drop ATN on the last byte of the message phase
14061da177e4SLinus Torvalds 		 * after REQ has been asserted for the handshake but before
14071da177e4SLinus Torvalds 		 * the initiator raises ACK.
14081da177e4SLinus Torvalds 		 */
14091da177e4SLinus Torvalds 
14101da177e4SLinus Torvalds 		if (!(p & SR_IO)) {
14111da177e4SLinus Torvalds 			if (!((p & SR_MSG) && c > 1)) {
14121da177e4SLinus Torvalds 				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
14131da177e4SLinus Torvalds 				NCR5380_dprint(NDEBUG_PIO, instance);
14141da177e4SLinus Torvalds 				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK);
14151da177e4SLinus Torvalds 			} else {
14161da177e4SLinus Torvalds 				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN);
14171da177e4SLinus Torvalds 				NCR5380_dprint(NDEBUG_PIO, instance);
14181da177e4SLinus Torvalds 				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
14191da177e4SLinus Torvalds 			}
14201da177e4SLinus Torvalds 		} else {
14211da177e4SLinus Torvalds 			NCR5380_dprint(NDEBUG_PIO, instance);
14221da177e4SLinus Torvalds 			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
14231da177e4SLinus Torvalds 		}
14241da177e4SLinus Torvalds 
1425a2edc4a6SFinn Thain 		if (NCR5380_poll_politely(instance,
1426a2edc4a6SFinn Thain 		                          STATUS_REG, SR_REQ, 0, 5 * HZ) < 0)
1427a2edc4a6SFinn Thain 			break;
1428a2edc4a6SFinn Thain 
142952a6a1cbSFinn Thain 		dprintk(NDEBUG_HANDSHAKE, "scsi%d : req false, handshake complete\n", instance->host_no);
14301da177e4SLinus Torvalds 
14311da177e4SLinus Torvalds /*
14321da177e4SLinus Torvalds  * We have several special cases to consider during REQ/ACK handshaking :
14331da177e4SLinus Torvalds  * 1.  We were in MSGOUT phase, and we are on the last byte of the
14341da177e4SLinus Torvalds  *      message.  ATN must be dropped as ACK is dropped.
14351da177e4SLinus Torvalds  *
14361da177e4SLinus Torvalds  * 2.  We are in a MSGIN phase, and we are on the last byte of the
14371da177e4SLinus Torvalds  *      message.  We must exit with ACK asserted, so that the calling
14381da177e4SLinus Torvalds  *      code may raise ATN before dropping ACK to reject the message.
14391da177e4SLinus Torvalds  *
14401da177e4SLinus Torvalds  * 3.  ACK and ATN are clear and the target may proceed as normal.
14411da177e4SLinus Torvalds  */
14421da177e4SLinus Torvalds 		if (!(p == PHASE_MSGIN && c == 1)) {
14431da177e4SLinus Torvalds 			if (p == PHASE_MSGOUT && c > 1)
14441da177e4SLinus Torvalds 				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
14451da177e4SLinus Torvalds 			else
14461da177e4SLinus Torvalds 				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
14471da177e4SLinus Torvalds 		}
14481da177e4SLinus Torvalds 	} while (--c);
14491da177e4SLinus Torvalds 
145052a6a1cbSFinn Thain 	dprintk(NDEBUG_PIO, "scsi%d : residual %d\n", instance->host_no, c);
14511da177e4SLinus Torvalds 
14521da177e4SLinus Torvalds 	*count = c;
14531da177e4SLinus Torvalds 	*data = d;
14541da177e4SLinus Torvalds 	tmp = NCR5380_read(STATUS_REG);
1455a2edc4a6SFinn Thain 	/* The phase read from the bus is valid if either REQ is (already)
1456a2edc4a6SFinn Thain 	 * asserted or if ACK hasn't been released yet. The latter applies if
1457a2edc4a6SFinn Thain 	 * we're in MSG IN, DATA IN or STATUS and all bytes have been received.
1458a2edc4a6SFinn Thain 	 */
1459a2edc4a6SFinn Thain 	if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0))
14601da177e4SLinus Torvalds 		*phase = tmp & PHASE_MASK;
14611da177e4SLinus Torvalds 	else
14621da177e4SLinus Torvalds 		*phase = PHASE_UNKNOWN;
14631da177e4SLinus Torvalds 
14641da177e4SLinus Torvalds 	if (!c || (*phase == p))
14651da177e4SLinus Torvalds 		return 0;
14661da177e4SLinus Torvalds 	else
14671da177e4SLinus Torvalds 		return -1;
14681da177e4SLinus Torvalds }
14691da177e4SLinus Torvalds 
14701da177e4SLinus Torvalds /**
14711da177e4SLinus Torvalds  * do_reset - issue a reset command
1472636b1ec8SFinn Thain  * @instance: adapter to reset
14731da177e4SLinus Torvalds  *
14741da177e4SLinus Torvalds  * Issue a reset sequence to the NCR5380 and try and get the bus
14751da177e4SLinus Torvalds  * back into sane shape.
14761da177e4SLinus Torvalds  *
1477636b1ec8SFinn Thain  * This clears the reset interrupt flag because there may be no handler for
1478636b1ec8SFinn Thain  * it. When the driver is initialized, the NCR5380_intr() handler has not yet
1479636b1ec8SFinn Thain  * been installed. And when in EH we may have released the ST DMA interrupt.
14801da177e4SLinus Torvalds  */
14811da177e4SLinus Torvalds 
148254d8fe44SFinn Thain static void do_reset(struct Scsi_Host *instance)
148354d8fe44SFinn Thain {
1484636b1ec8SFinn Thain 	unsigned long flags;
1485636b1ec8SFinn Thain 
1486636b1ec8SFinn Thain 	local_irq_save(flags);
1487636b1ec8SFinn Thain 	NCR5380_write(TARGET_COMMAND_REG,
1488636b1ec8SFinn Thain 	              PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
14891da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
1490636b1ec8SFinn Thain 	udelay(50);
14911da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
1492636b1ec8SFinn Thain 	(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
1493636b1ec8SFinn Thain 	local_irq_restore(flags);
14941da177e4SLinus Torvalds }
14951da177e4SLinus Torvalds 
149680d3eb6dSFinn Thain /**
149780d3eb6dSFinn Thain  * do_abort - abort the currently established nexus by going to
149880d3eb6dSFinn Thain  * MESSAGE OUT phase and sending an ABORT message.
149980d3eb6dSFinn Thain  * @instance: relevant scsi host instance
15001da177e4SLinus Torvalds  *
150180d3eb6dSFinn Thain  * Returns 0 on success, -1 on failure.
15021da177e4SLinus Torvalds  */
15031da177e4SLinus Torvalds 
150454d8fe44SFinn Thain static int do_abort(struct Scsi_Host *instance)
150554d8fe44SFinn Thain {
15061da177e4SLinus Torvalds 	unsigned char *msgptr, phase, tmp;
15071da177e4SLinus Torvalds 	int len;
15081da177e4SLinus Torvalds 	int rc;
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds 	/* Request message out phase */
15111da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
15121da177e4SLinus Torvalds 
15131da177e4SLinus Torvalds 	/*
15141da177e4SLinus Torvalds 	 * Wait for the target to indicate a valid phase by asserting
15151da177e4SLinus Torvalds 	 * REQ.  Once this happens, we'll have either a MSGOUT phase
15161da177e4SLinus Torvalds 	 * and can immediately send the ABORT message, or we'll have some
15171da177e4SLinus Torvalds 	 * other phase and will have to source/sink data.
15181da177e4SLinus Torvalds 	 *
15191da177e4SLinus Torvalds 	 * We really don't care what value was on the bus or what value
15201da177e4SLinus Torvalds 	 * the target sees, so we just handshake.
15211da177e4SLinus Torvalds 	 */
15221da177e4SLinus Torvalds 
152380d3eb6dSFinn Thain 	rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ);
15241da177e4SLinus Torvalds 	if (rc < 0)
152580d3eb6dSFinn Thain 		goto timeout;
15261da177e4SLinus Torvalds 
1527f35d3474SFinn Thain 	tmp = NCR5380_read(STATUS_REG) & PHASE_MASK;
15281da177e4SLinus Torvalds 
15291da177e4SLinus Torvalds 	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
15301da177e4SLinus Torvalds 
1531f35d3474SFinn Thain 	if (tmp != PHASE_MSGOUT) {
15321da177e4SLinus Torvalds 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
153354d8fe44SFinn Thain 		rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ);
15341cc160e1SFinn Thain 		if (rc < 0)
153580d3eb6dSFinn Thain 			goto timeout;
153680d3eb6dSFinn Thain 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
15371da177e4SLinus Torvalds 	}
15381da177e4SLinus Torvalds 	tmp = ABORT;
15391da177e4SLinus Torvalds 	msgptr = &tmp;
15401da177e4SLinus Torvalds 	len = 1;
15411da177e4SLinus Torvalds 	phase = PHASE_MSGOUT;
154254d8fe44SFinn Thain 	NCR5380_transfer_pio(instance, &phase, &len, &msgptr);
15431da177e4SLinus Torvalds 
15441da177e4SLinus Torvalds 	/*
15451da177e4SLinus Torvalds 	 * If we got here, and the command completed successfully,
15461da177e4SLinus Torvalds 	 * we're about to go into bus free state.
15471da177e4SLinus Torvalds 	 */
15481da177e4SLinus Torvalds 
15491da177e4SLinus Torvalds 	return len ? -1 : 0;
155080d3eb6dSFinn Thain 
155180d3eb6dSFinn Thain timeout:
155280d3eb6dSFinn Thain 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
155380d3eb6dSFinn Thain 	return -1;
15541da177e4SLinus Torvalds }
15551da177e4SLinus Torvalds 
15561da177e4SLinus Torvalds #if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)
15571da177e4SLinus Torvalds /*
15581da177e4SLinus Torvalds  * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
15591da177e4SLinus Torvalds  *      unsigned char *phase, int *count, unsigned char **data)
15601da177e4SLinus Torvalds  *
15611da177e4SLinus Torvalds  * Purpose : transfers data in given phase using either real
15621da177e4SLinus Torvalds  *      or pseudo DMA.
15631da177e4SLinus Torvalds  *
15641da177e4SLinus Torvalds  * Inputs : instance - instance of driver, *phase - pointer to
15651da177e4SLinus Torvalds  *      what phase is expected, *count - pointer to number of
15661da177e4SLinus Torvalds  *      bytes to transfer, **data - pointer to data pointer.
15671da177e4SLinus Torvalds  *
15681da177e4SLinus Torvalds  * Returns : -1 when different phase is entered without transferring
156925985edcSLucas De Marchi  *      maximum number of bytes, 0 if all bytes or transferred or exit
15701da177e4SLinus Torvalds  *      is in same phase.
15711da177e4SLinus Torvalds  *
15721da177e4SLinus Torvalds  *      Also, *phase, *count, *data are modified in place.
15731da177e4SLinus Torvalds  *
15741da177e4SLinus Torvalds  *	Locks: io_request lock held by caller
15751da177e4SLinus Torvalds  */
15761da177e4SLinus Torvalds 
15771da177e4SLinus Torvalds 
15781da177e4SLinus Torvalds static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
15791da177e4SLinus Torvalds 	register int c = *count;
15801da177e4SLinus Torvalds 	register unsigned char p = *phase;
15811da177e4SLinus Torvalds 	register unsigned char *d = *data;
15821da177e4SLinus Torvalds 	unsigned char tmp;
15831da177e4SLinus Torvalds 	int foo;
15841da177e4SLinus Torvalds #if defined(REAL_DMA_POLL)
15851da177e4SLinus Torvalds 	int cnt, toPIO;
15861da177e4SLinus Torvalds 	unsigned char saved_data = 0, overrun = 0, residue;
15871da177e4SLinus Torvalds #endif
15881da177e4SLinus Torvalds 
1589e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
15901da177e4SLinus Torvalds 
15911da177e4SLinus Torvalds 	if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
15921da177e4SLinus Torvalds 		*phase = tmp;
15931da177e4SLinus Torvalds 		return -1;
15941da177e4SLinus Torvalds 	}
15951da177e4SLinus Torvalds #if defined(REAL_DMA) || defined(REAL_DMA_POLL)
15961da177e4SLinus Torvalds 	if (p & SR_IO) {
15979db6024eSFinn Thain 		if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS))
15981da177e4SLinus Torvalds 			c -= 2;
15991da177e4SLinus Torvalds 	}
160052a6a1cbSFinn Thain 	dprintk(NDEBUG_DMA, "scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
16011da177e4SLinus Torvalds 	hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c);
16021da177e4SLinus Torvalds #endif
16031da177e4SLinus Torvalds 
16041da177e4SLinus Torvalds 	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
16051da177e4SLinus Torvalds 
16061da177e4SLinus Torvalds #ifdef REAL_DMA
1607cd400825SFinn Thain 	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
1608cd400825SFinn Thain 	                        MR_ENABLE_EOP_INTR);
16091da177e4SLinus Torvalds #elif defined(REAL_DMA_POLL)
1610cd400825SFinn Thain 	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY);
16111da177e4SLinus Torvalds #else
16121da177e4SLinus Torvalds 	/*
16131da177e4SLinus Torvalds 	 * Note : on my sample board, watch-dog timeouts occurred when interrupts
16141da177e4SLinus Torvalds 	 * were not disabled for the duration of a single DMA transfer, from
16151da177e4SLinus Torvalds 	 * before the setting of DMA mode to after transfer of the last byte.
16161da177e4SLinus Torvalds 	 */
16171da177e4SLinus Torvalds 
161855181be8SFinn Thain 	if (hostdata->flags & FLAG_NO_DMA_FIXUP)
1619cd400825SFinn Thain 		NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY |
1620cd400825SFinn Thain 		                        MR_ENABLE_EOP_INTR);
16211da177e4SLinus Torvalds 	else
1622cd400825SFinn Thain 		NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY);
16231da177e4SLinus Torvalds #endif				/* def REAL_DMA */
16241da177e4SLinus Torvalds 
162552a6a1cbSFinn Thain 	dprintk(NDEBUG_DMA, "scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG));
16261da177e4SLinus Torvalds 
16271da177e4SLinus Torvalds 	/*
16281da177e4SLinus Torvalds 	 *	On the PAS16 at least I/O recovery delays are not needed here.
16291da177e4SLinus Torvalds 	 *	Everyone else seems to want them.
16301da177e4SLinus Torvalds 	 */
16311da177e4SLinus Torvalds 
16321da177e4SLinus Torvalds 	if (p & SR_IO) {
16331da177e4SLinus Torvalds 		io_recovery_delay(1);
16341da177e4SLinus Torvalds 		NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
16351da177e4SLinus Torvalds 	} else {
16361da177e4SLinus Torvalds 		io_recovery_delay(1);
16371da177e4SLinus Torvalds 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
16381da177e4SLinus Torvalds 		io_recovery_delay(1);
16391da177e4SLinus Torvalds 		NCR5380_write(START_DMA_SEND_REG, 0);
16401da177e4SLinus Torvalds 		io_recovery_delay(1);
16411da177e4SLinus Torvalds 	}
16421da177e4SLinus Torvalds 
16431da177e4SLinus Torvalds #if defined(REAL_DMA_POLL)
16441da177e4SLinus Torvalds 	do {
16451da177e4SLinus Torvalds 		tmp = NCR5380_read(BUS_AND_STATUS_REG);
16461da177e4SLinus Torvalds 	} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER)));
16471da177e4SLinus Torvalds 
16481da177e4SLinus Torvalds /*
16491da177e4SLinus Torvalds    At this point, either we've completed DMA, or we have a phase mismatch,
16501da177e4SLinus Torvalds    or we've unexpectedly lost BUSY (which is a real error).
16511da177e4SLinus Torvalds 
16521da177e4SLinus Torvalds    For write DMAs, we want to wait until the last byte has been
16531da177e4SLinus Torvalds    transferred out over the bus before we turn off DMA mode.  Alas, there
16541da177e4SLinus Torvalds    seems to be no terribly good way of doing this on a 5380 under all
16551da177e4SLinus Torvalds    conditions.  For non-scatter-gather operations, we can wait until REQ
16561da177e4SLinus Torvalds    and ACK both go false, or until a phase mismatch occurs.  Gather-writes
16571da177e4SLinus Torvalds    are nastier, since the device will be expecting more data than we
16581da177e4SLinus Torvalds    are prepared to send it, and REQ will remain asserted.  On a 53C8[01] we
16591da177e4SLinus Torvalds    could test LAST BIT SENT to assure transfer (I imagine this is precisely
16601da177e4SLinus Torvalds    why this signal was added to the newer chips) but on the older 538[01]
16611da177e4SLinus Torvalds    this signal does not exist.  The workaround for this lack is a watchdog;
16621da177e4SLinus Torvalds    we bail out of the wait-loop after a modest amount of wait-time if
16631da177e4SLinus Torvalds    the usual exit conditions are not met.  Not a terribly clean or
16641da177e4SLinus Torvalds    correct solution :-%
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds    Reads are equally tricky due to a nasty characteristic of the NCR5380.
16671da177e4SLinus Torvalds    If the chip is in DMA mode for an READ, it will respond to a target's
16681da177e4SLinus Torvalds    REQ by latching the SCSI data into the INPUT DATA register and asserting
16691da177e4SLinus Torvalds    ACK, even if it has _already_ been notified by the DMA controller that
16701da177e4SLinus Torvalds    the current DMA transfer has completed!  If the NCR5380 is then taken
16711da177e4SLinus Torvalds    out of DMA mode, this already-acknowledged byte is lost.
16721da177e4SLinus Torvalds 
16731da177e4SLinus Torvalds    This is not a problem for "one DMA transfer per command" reads, because
16741da177e4SLinus Torvalds    the situation will never arise... either all of the data is DMA'ed
16751da177e4SLinus Torvalds    properly, or the target switches to MESSAGE IN phase to signal a
16761da177e4SLinus Torvalds    disconnection (either operation bringing the DMA to a clean halt).
16771da177e4SLinus Torvalds    However, in order to handle scatter-reads, we must work around the
16781da177e4SLinus Torvalds    problem.  The chosen fix is to DMA N-2 bytes, then check for the
16791da177e4SLinus Torvalds    condition before taking the NCR5380 out of DMA mode.  One or two extra
16801da177e4SLinus Torvalds    bytes are transferred via PIO as necessary to fill out the original
16811da177e4SLinus Torvalds    request.
16821da177e4SLinus Torvalds  */
16831da177e4SLinus Torvalds 
16841da177e4SLinus Torvalds 	if (p & SR_IO) {
16859db6024eSFinn Thain 		if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS)) {
16861da177e4SLinus Torvalds 			udelay(10);
16879db6024eSFinn Thain 			if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) ==
16889db6024eSFinn Thain 			    (BASR_PHASE_MATCH | BASR_ACK)) {
16891da177e4SLinus Torvalds 				saved_data = NCR5380_read(INPUT_DATA_REGISTER);
16901da177e4SLinus Torvalds 				overrun = 1;
16911da177e4SLinus Torvalds 			}
16929db6024eSFinn Thain 		}
16931da177e4SLinus Torvalds 	} else {
16941da177e4SLinus Torvalds 		int limit = 100;
16951da177e4SLinus Torvalds 		while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) {
16961da177e4SLinus Torvalds 			if (!(tmp & BASR_PHASE_MATCH))
16971da177e4SLinus Torvalds 				break;
16981da177e4SLinus Torvalds 			if (--limit < 0)
16991da177e4SLinus Torvalds 				break;
17001da177e4SLinus Torvalds 		}
17011da177e4SLinus Torvalds 	}
17021da177e4SLinus Torvalds 
170352a6a1cbSFinn Thain 	dprintk(NDEBUG_DMA, "scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG));
17041da177e4SLinus Torvalds 
17051da177e4SLinus Torvalds 	NCR5380_write(MODE_REG, MR_BASE);
17061da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
17071da177e4SLinus Torvalds 
17081da177e4SLinus Torvalds 	residue = NCR5380_dma_residual(instance);
17091da177e4SLinus Torvalds 	c -= residue;
17101da177e4SLinus Torvalds 	*count -= c;
17111da177e4SLinus Torvalds 	*data += c;
17121da177e4SLinus Torvalds 	*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
17131da177e4SLinus Torvalds 
17149db6024eSFinn Thain 	if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS) &&
17159db6024eSFinn Thain 	    *phase == p && (p & SR_IO) && residue == 0) {
17161da177e4SLinus Torvalds 		if (overrun) {
171752a6a1cbSFinn Thain 			dprintk(NDEBUG_DMA, "Got an input overrun, using saved byte\n");
17181da177e4SLinus Torvalds 			**data = saved_data;
17191da177e4SLinus Torvalds 			*data += 1;
17201da177e4SLinus Torvalds 			*count -= 1;
17211da177e4SLinus Torvalds 			cnt = toPIO = 1;
17221da177e4SLinus Torvalds 		} else {
17231da177e4SLinus Torvalds 			printk("No overrun??\n");
17241da177e4SLinus Torvalds 			cnt = toPIO = 2;
17251da177e4SLinus Torvalds 		}
172652a6a1cbSFinn Thain 		dprintk(NDEBUG_DMA, "Doing %d-byte PIO to 0x%X\n", cnt, *data);
17271da177e4SLinus Torvalds 		NCR5380_transfer_pio(instance, phase, &cnt, data);
17281da177e4SLinus Torvalds 		*count -= toPIO - cnt;
17291da177e4SLinus Torvalds 	}
17301da177e4SLinus Torvalds 
173152a6a1cbSFinn Thain 	dprintk(NDEBUG_DMA, "Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count));
17321da177e4SLinus Torvalds 	return 0;
17331da177e4SLinus Torvalds 
17341da177e4SLinus Torvalds #elif defined(REAL_DMA)
17351da177e4SLinus Torvalds 	return 0;
17361da177e4SLinus Torvalds #else				/* defined(REAL_DMA_POLL) */
17371da177e4SLinus Torvalds 	if (p & SR_IO) {
173855181be8SFinn Thain 		foo = NCR5380_pread(instance, d,
173955181be8SFinn Thain 			hostdata->flags & FLAG_NO_DMA_FIXUP ? c : c - 1);
174055181be8SFinn Thain 		if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) {
17411da177e4SLinus Torvalds 			/*
17421da177e4SLinus Torvalds 			 * We can't disable DMA mode after successfully transferring
17431da177e4SLinus Torvalds 			 * what we plan to be the last byte, since that would open up
17441da177e4SLinus Torvalds 			 * a race condition where if the target asserted REQ before
17451da177e4SLinus Torvalds 			 * we got the DMA mode reset, the NCR5380 would have latched
17461da177e4SLinus Torvalds 			 * an additional byte into the INPUT DATA register and we'd
17471da177e4SLinus Torvalds 			 * have dropped it.
17481da177e4SLinus Torvalds 			 *
17491da177e4SLinus Torvalds 			 * The workaround was to transfer one fewer bytes than we
17501da177e4SLinus Torvalds 			 * intended to with the pseudo-DMA read function, wait for
17511da177e4SLinus Torvalds 			 * the chip to latch the last byte, read it, and then disable
17521da177e4SLinus Torvalds 			 * pseudo-DMA mode.
17531da177e4SLinus Torvalds 			 *
17541da177e4SLinus Torvalds 			 * After REQ is asserted, the NCR5380 asserts DRQ and ACK.
17551da177e4SLinus Torvalds 			 * REQ is deasserted when ACK is asserted, and not reasserted
17561da177e4SLinus Torvalds 			 * until ACK goes false.  Since the NCR5380 won't lower ACK
17571da177e4SLinus Torvalds 			 * until DACK is asserted, which won't happen unless we twiddle
17581da177e4SLinus Torvalds 			 * the DMA port or we take the NCR5380 out of DMA mode, we
17591da177e4SLinus Torvalds 			 * can guarantee that we won't handshake another extra
17601da177e4SLinus Torvalds 			 * byte.
17611da177e4SLinus Torvalds 			 */
17621da177e4SLinus Torvalds 
176355181be8SFinn Thain 			if (NCR5380_poll_politely(instance, BUS_AND_STATUS_REG,
176455181be8SFinn Thain 			                          BASR_DRQ, BASR_DRQ, HZ) < 0) {
176555181be8SFinn Thain 				foo = -1;
176655181be8SFinn Thain 				shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n");
176755181be8SFinn Thain 			}
176855181be8SFinn Thain 			if (NCR5380_poll_politely(instance, STATUS_REG,
176955181be8SFinn Thain 			                          SR_REQ, 0, HZ) < 0) {
177055181be8SFinn Thain 				foo = -1;
177155181be8SFinn Thain 				shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n");
177255181be8SFinn Thain 			}
17731da177e4SLinus Torvalds 			d[c - 1] = NCR5380_read(INPUT_DATA_REG);
17741da177e4SLinus Torvalds 		}
17751da177e4SLinus Torvalds 	} else {
17761da177e4SLinus Torvalds 		foo = NCR5380_pwrite(instance, d, c);
177755181be8SFinn Thain 		if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) {
17781da177e4SLinus Torvalds 			/*
17791da177e4SLinus Torvalds 			 * Wait for the last byte to be sent.  If REQ is being asserted for
17801da177e4SLinus Torvalds 			 * the byte we're interested, we'll ACK it and it will go false.
17811da177e4SLinus Torvalds 			 */
178255181be8SFinn Thain 			if (NCR5380_poll_politely2(instance,
178355181be8SFinn Thain 			     BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ,
178455181be8SFinn Thain 			     BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) {
178555181be8SFinn Thain 				foo = -1;
178655181be8SFinn Thain 				shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n");
17871da177e4SLinus Torvalds 			}
17881da177e4SLinus Torvalds 		}
17891da177e4SLinus Torvalds 	}
17901da177e4SLinus Torvalds 	NCR5380_write(MODE_REG, MR_BASE);
17911da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
17921da177e4SLinus Torvalds 	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
17931da177e4SLinus Torvalds 	*data = d + c;
17941da177e4SLinus Torvalds 	*count = 0;
17951da177e4SLinus Torvalds 	*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
17961da177e4SLinus Torvalds 	return foo;
17971da177e4SLinus Torvalds #endif				/* def REAL_DMA */
17981da177e4SLinus Torvalds }
17991da177e4SLinus Torvalds #endif				/* defined(REAL_DMA) | defined(PSEUDO_DMA) */
18001da177e4SLinus Torvalds 
18011da177e4SLinus Torvalds /*
18021da177e4SLinus Torvalds  * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
18031da177e4SLinus Torvalds  *
18041da177e4SLinus Torvalds  * Purpose : run through the various SCSI phases and do as the target
18051da177e4SLinus Torvalds  *      directs us to.  Operates on the currently connected command,
18061da177e4SLinus Torvalds  *      instance->connected.
18071da177e4SLinus Torvalds  *
18081da177e4SLinus Torvalds  * Inputs : instance, instance for which we are doing commands
18091da177e4SLinus Torvalds  *
18101da177e4SLinus Torvalds  * Side effects : SCSI things happen, the disconnected queue will be
18111da177e4SLinus Torvalds  *      modified if a command disconnects, *instance->connected will
18121da177e4SLinus Torvalds  *      change.
18131da177e4SLinus Torvalds  *
18141da177e4SLinus Torvalds  * XXX Note : we need to watch for bus free or a reset condition here
18151da177e4SLinus Torvalds  *      to recover from an unexpected bus free condition.
18161da177e4SLinus Torvalds  *
18171da177e4SLinus Torvalds  * Locks: io_request_lock held by caller in IRQ mode
18181da177e4SLinus Torvalds  */
18191da177e4SLinus Torvalds 
18201da177e4SLinus Torvalds static void NCR5380_information_transfer(struct Scsi_Host *instance) {
1821e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
18221da177e4SLinus Torvalds 	unsigned char msgout = NOP;
18231da177e4SLinus Torvalds 	int sink = 0;
18241da177e4SLinus Torvalds 	int len;
18251da177e4SLinus Torvalds #if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
18261da177e4SLinus Torvalds 	int transfersize;
18271da177e4SLinus Torvalds #endif
18281da177e4SLinus Torvalds 	unsigned char *data;
18291da177e4SLinus Torvalds 	unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
183011d2f63bSFinn Thain 	struct scsi_cmnd *cmd;
18311da177e4SLinus Torvalds 
183211d2f63bSFinn Thain 	while ((cmd = hostdata->connected)) {
183332b26a10SFinn Thain 		struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
183432b26a10SFinn Thain 
18351da177e4SLinus Torvalds 		tmp = NCR5380_read(STATUS_REG);
18361da177e4SLinus Torvalds 		/* We only have a valid SCSI phase when REQ is asserted */
18371da177e4SLinus Torvalds 		if (tmp & SR_REQ) {
18381da177e4SLinus Torvalds 			phase = (tmp & PHASE_MASK);
18391da177e4SLinus Torvalds 			if (phase != old_phase) {
18401da177e4SLinus Torvalds 				old_phase = phase;
18411da177e4SLinus Torvalds 				NCR5380_dprint_phase(NDEBUG_INFORMATION, instance);
18421da177e4SLinus Torvalds 			}
18431da177e4SLinus Torvalds 			if (sink && (phase != PHASE_MSGOUT)) {
18441da177e4SLinus Torvalds 				NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
18451da177e4SLinus Torvalds 
18461da177e4SLinus Torvalds 				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
18471da177e4SLinus Torvalds 				while (NCR5380_read(STATUS_REG) & SR_REQ);
18481da177e4SLinus Torvalds 				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
18491da177e4SLinus Torvalds 				sink = 0;
18501da177e4SLinus Torvalds 				continue;
18511da177e4SLinus Torvalds 			}
18521da177e4SLinus Torvalds 			switch (phase) {
18531da177e4SLinus Torvalds 			case PHASE_DATAOUT:
18541da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_DATAOUT)
18551da177e4SLinus Torvalds 				printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no);
18561da177e4SLinus Torvalds 				sink = 1;
18571da177e4SLinus Torvalds 				do_abort(instance);
18581da177e4SLinus Torvalds 				cmd->result = DID_ERROR << 16;
1859677e0194SFinn Thain 				complete_cmd(instance, cmd);
18601da177e4SLinus Torvalds 				return;
18611da177e4SLinus Torvalds #endif
1862bf1a0c6fSFinn Thain 			case PHASE_DATAIN:
18631da177e4SLinus Torvalds 				/*
18641da177e4SLinus Torvalds 				 * If there is no room left in the current buffer in the
18651da177e4SLinus Torvalds 				 * scatter-gather list, move onto the next one.
18661da177e4SLinus Torvalds 				 */
18671da177e4SLinus Torvalds 
18681da177e4SLinus Torvalds 				if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
18691da177e4SLinus Torvalds 					++cmd->SCp.buffer;
18701da177e4SLinus Torvalds 					--cmd->SCp.buffers_residual;
18711da177e4SLinus Torvalds 					cmd->SCp.this_residual = cmd->SCp.buffer->length;
187245711f1aSJens Axboe 					cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
187352a6a1cbSFinn Thain 					dprintk(NDEBUG_INFORMATION, "scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual);
18741da177e4SLinus Torvalds 				}
18751da177e4SLinus Torvalds 				/*
18761da177e4SLinus Torvalds 				 * The preferred transfer method is going to be
18771da177e4SLinus Torvalds 				 * PSEUDO-DMA for systems that are strictly PIO,
18781da177e4SLinus Torvalds 				 * since we can let the hardware do the handshaking.
18791da177e4SLinus Torvalds 				 *
18801da177e4SLinus Torvalds 				 * For this to work, we need to know the transfersize
18811da177e4SLinus Torvalds 				 * ahead of time, since the pseudo-DMA code will sit
18821da177e4SLinus Torvalds 				 * in an unconditional loop.
18831da177e4SLinus Torvalds 				 */
18841da177e4SLinus Torvalds 
18851da177e4SLinus Torvalds #if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
1886ff3d4578SFinn Thain 				transfersize = 0;
1887ff3d4578SFinn Thain 				if (!cmd->device->borken &&
1888ff3d4578SFinn Thain 				    !(hostdata->flags & FLAG_NO_PSEUDO_DMA))
1889ff3d4578SFinn Thain 					transfersize = NCR5380_dma_xfer_len(instance, cmd, phase);
18901da177e4SLinus Torvalds 
1891ff3d4578SFinn Thain 				if (transfersize) {
18921da177e4SLinus Torvalds 					len = transfersize;
18931da177e4SLinus Torvalds 					if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) {
18941da177e4SLinus Torvalds 						/*
18951da177e4SLinus Torvalds 						 * If the watchdog timer fires, all future accesses to this
18961da177e4SLinus Torvalds 						 * device will use the polled-IO.
18971da177e4SLinus Torvalds 						 */
1898017560fcSJeff Garzik 						scmd_printk(KERN_INFO, cmd,
1899017560fcSJeff Garzik 							    "switching to slow handshake\n");
19001da177e4SLinus Torvalds 						cmd->device->borken = 1;
19011da177e4SLinus Torvalds 						sink = 1;
19021da177e4SLinus Torvalds 						do_abort(instance);
19031da177e4SLinus Torvalds 						cmd->result = DID_ERROR << 16;
1904677e0194SFinn Thain 						complete_cmd(instance, cmd);
19051da177e4SLinus Torvalds 						/* XXX - need to source or sink data here, as appropriate */
19061da177e4SLinus Torvalds 					} else
19071da177e4SLinus Torvalds 						cmd->SCp.this_residual -= transfersize - len;
19081da177e4SLinus Torvalds 				} else
19091da177e4SLinus Torvalds #endif				/* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */
191011d2f63bSFinn Thain 				{
191111d2f63bSFinn Thain 					spin_unlock_irq(&hostdata->lock);
19121da177e4SLinus Torvalds 					NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **)
19131da177e4SLinus Torvalds 							     &cmd->SCp.ptr);
191411d2f63bSFinn Thain 					spin_lock_irq(&hostdata->lock);
191511d2f63bSFinn Thain 				}
19161da177e4SLinus Torvalds 				break;
19171da177e4SLinus Torvalds 			case PHASE_MSGIN:
19181da177e4SLinus Torvalds 				len = 1;
19191da177e4SLinus Torvalds 				data = &tmp;
19201da177e4SLinus Torvalds 				NCR5380_transfer_pio(instance, &phase, &len, &data);
19211da177e4SLinus Torvalds 				cmd->SCp.Message = tmp;
19221da177e4SLinus Torvalds 
19231da177e4SLinus Torvalds 				switch (tmp) {
19241da177e4SLinus Torvalds 				case ABORT:
19251da177e4SLinus Torvalds 				case COMMAND_COMPLETE:
19261da177e4SLinus Torvalds 					/* Accept message by clearing ACK */
19271da177e4SLinus Torvalds 					sink = 1;
19281da177e4SLinus Torvalds 					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
19290d3d9a42SFinn Thain 					dsprintk(NDEBUG_QUEUES, instance,
19300d3d9a42SFinn Thain 					         "COMMAND COMPLETE %p target %d lun %llu\n",
19310d3d9a42SFinn Thain 					         cmd, scmd_id(cmd), cmd->device->lun);
19320d3d9a42SFinn Thain 
19331da177e4SLinus Torvalds 					hostdata->connected = NULL;
19341da177e4SLinus Torvalds 
1935f27db8ebSFinn Thain 					cmd->result &= ~0xffff;
1936f27db8ebSFinn Thain 					cmd->result |= cmd->SCp.Status;
1937f27db8ebSFinn Thain 					cmd->result |= cmd->SCp.Message << 8;
19381da177e4SLinus Torvalds 
1939f27db8ebSFinn Thain 					if (cmd->cmnd[0] == REQUEST_SENSE)
1940f27db8ebSFinn Thain 						complete_cmd(instance, cmd);
1941f27db8ebSFinn Thain 					else {
1942f27db8ebSFinn Thain 						if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION ||
1943f27db8ebSFinn Thain 						    cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) {
1944f27db8ebSFinn Thain 							dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n",
1945dbb6b350SFinn Thain 							         cmd);
1946f27db8ebSFinn Thain 							list_add_tail(&ncmd->list,
1947f27db8ebSFinn Thain 							              &hostdata->autosense);
1948f27db8ebSFinn Thain 						} else
1949677e0194SFinn Thain 							complete_cmd(instance, cmd);
19501da177e4SLinus Torvalds 					}
19511da177e4SLinus Torvalds 
19521da177e4SLinus Torvalds 					/*
19531da177e4SLinus Torvalds 					 * Restore phase bits to 0 so an interrupted selection,
19541da177e4SLinus Torvalds 					 * arbitration can resume.
19551da177e4SLinus Torvalds 					 */
19561da177e4SLinus Torvalds 					NCR5380_write(TARGET_COMMAND_REG, 0);
195772064a78SFinn Thain 
195872064a78SFinn Thain 					/* Enable reselect interrupts */
195972064a78SFinn Thain 					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
19601da177e4SLinus Torvalds 					return;
19611da177e4SLinus Torvalds 				case MESSAGE_REJECT:
19621da177e4SLinus Torvalds 					/* Accept message by clearing ACK */
19631da177e4SLinus Torvalds 					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
19641da177e4SLinus Torvalds 					switch (hostdata->last_message) {
19651da177e4SLinus Torvalds 					case HEAD_OF_QUEUE_TAG:
19661da177e4SLinus Torvalds 					case ORDERED_QUEUE_TAG:
19671da177e4SLinus Torvalds 					case SIMPLE_QUEUE_TAG:
19681da177e4SLinus Torvalds 						cmd->device->simple_tags = 0;
19699cb78c16SHannes Reinecke 						hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF));
19701da177e4SLinus Torvalds 						break;
19711da177e4SLinus Torvalds 					default:
19721da177e4SLinus Torvalds 						break;
19731da177e4SLinus Torvalds 					}
1974340b9612SFinn Thain 					break;
19751da177e4SLinus Torvalds 				case DISCONNECT:{
19761da177e4SLinus Torvalds 						/* Accept message by clearing ACK */
19771da177e4SLinus Torvalds 						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
19781da177e4SLinus Torvalds 						hostdata->connected = NULL;
197932b26a10SFinn Thain 						list_add(&ncmd->list, &hostdata->disconnected);
19800d3d9a42SFinn Thain 						dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES,
19810d3d9a42SFinn Thain 						         instance, "connected command %p for target %d lun %llu moved to disconnected queue\n",
19820d3d9a42SFinn Thain 						         cmd, scmd_id(cmd), cmd->device->lun);
19830d3d9a42SFinn Thain 
19841da177e4SLinus Torvalds 						/*
19851da177e4SLinus Torvalds 						 * Restore phase bits to 0 so an interrupted selection,
19861da177e4SLinus Torvalds 						 * arbitration can resume.
19871da177e4SLinus Torvalds 						 */
19881da177e4SLinus Torvalds 						NCR5380_write(TARGET_COMMAND_REG, 0);
19891da177e4SLinus Torvalds 
19901da177e4SLinus Torvalds 						/* Enable reselect interrupts */
19911da177e4SLinus Torvalds 						NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
19921da177e4SLinus Torvalds 						return;
19931da177e4SLinus Torvalds 					}
19941da177e4SLinus Torvalds 					/*
19951da177e4SLinus Torvalds 					 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
19961da177e4SLinus Torvalds 					 * operation, in violation of the SCSI spec so we can safely
19971da177e4SLinus Torvalds 					 * ignore SAVE/RESTORE pointers calls.
19981da177e4SLinus Torvalds 					 *
19991da177e4SLinus Torvalds 					 * Unfortunately, some disks violate the SCSI spec and
20001da177e4SLinus Torvalds 					 * don't issue the required SAVE_POINTERS message before
20011da177e4SLinus Torvalds 					 * disconnecting, and we have to break spec to remain
20021da177e4SLinus Torvalds 					 * compatible.
20031da177e4SLinus Torvalds 					 */
20041da177e4SLinus Torvalds 				case SAVE_POINTERS:
20051da177e4SLinus Torvalds 				case RESTORE_POINTERS:
20061da177e4SLinus Torvalds 					/* Accept message by clearing ACK */
20071da177e4SLinus Torvalds 					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
20081da177e4SLinus Torvalds 					break;
20091da177e4SLinus Torvalds 				case EXTENDED_MESSAGE:
20101da177e4SLinus Torvalds /*
20111da177e4SLinus Torvalds  * Extended messages are sent in the following format :
20121da177e4SLinus Torvalds  * Byte
20131da177e4SLinus Torvalds  * 0            EXTENDED_MESSAGE == 1
20141da177e4SLinus Torvalds  * 1            length (includes one byte for code, doesn't
20151da177e4SLinus Torvalds  *              include first two bytes)
20161da177e4SLinus Torvalds  * 2            code
20171da177e4SLinus Torvalds  * 3..length+1  arguments
20181da177e4SLinus Torvalds  *
20191da177e4SLinus Torvalds  * Start the extended message buffer with the EXTENDED_MESSAGE
20201abfd370SMatthew Wilcox  * byte, since spi_print_msg() wants the whole thing.
20211da177e4SLinus Torvalds  */
20221da177e4SLinus Torvalds 					extended_msg[0] = EXTENDED_MESSAGE;
20231da177e4SLinus Torvalds 					/* Accept first byte by clearing ACK */
20241da177e4SLinus Torvalds 					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
202511d2f63bSFinn Thain 
202611d2f63bSFinn Thain 					spin_unlock_irq(&hostdata->lock);
202711d2f63bSFinn Thain 
202852a6a1cbSFinn Thain 					dprintk(NDEBUG_EXTENDED, "scsi%d : receiving extended message\n", instance->host_no);
20291da177e4SLinus Torvalds 
20301da177e4SLinus Torvalds 					len = 2;
20311da177e4SLinus Torvalds 					data = extended_msg + 1;
20321da177e4SLinus Torvalds 					phase = PHASE_MSGIN;
20331da177e4SLinus Torvalds 					NCR5380_transfer_pio(instance, &phase, &len, &data);
20341da177e4SLinus Torvalds 
203552a6a1cbSFinn Thain 					dprintk(NDEBUG_EXTENDED, "scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2]);
20361da177e4SLinus Torvalds 
2037e0783ed3SFinn Thain 					if (!len && extended_msg[1] > 0 &&
2038e0783ed3SFinn Thain 					    extended_msg[1] <= sizeof(extended_msg) - 2) {
20391da177e4SLinus Torvalds 						/* Accept third byte by clearing ACK */
20401da177e4SLinus Torvalds 						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
20411da177e4SLinus Torvalds 						len = extended_msg[1] - 1;
20421da177e4SLinus Torvalds 						data = extended_msg + 3;
20431da177e4SLinus Torvalds 						phase = PHASE_MSGIN;
20441da177e4SLinus Torvalds 
20451da177e4SLinus Torvalds 						NCR5380_transfer_pio(instance, &phase, &len, &data);
204652a6a1cbSFinn Thain 						dprintk(NDEBUG_EXTENDED, "scsi%d : message received, residual %d\n", instance->host_no, len);
20471da177e4SLinus Torvalds 
20481da177e4SLinus Torvalds 						switch (extended_msg[2]) {
20491da177e4SLinus Torvalds 						case EXTENDED_SDTR:
20501da177e4SLinus Torvalds 						case EXTENDED_WDTR:
20511da177e4SLinus Torvalds 						case EXTENDED_MODIFY_DATA_POINTER:
20521da177e4SLinus Torvalds 						case EXTENDED_EXTENDED_IDENTIFY:
20531da177e4SLinus Torvalds 							tmp = 0;
20541da177e4SLinus Torvalds 						}
20551da177e4SLinus Torvalds 					} else if (len) {
20561da177e4SLinus Torvalds 						printk("scsi%d: error receiving extended message\n", instance->host_no);
20571da177e4SLinus Torvalds 						tmp = 0;
20581da177e4SLinus Torvalds 					} else {
20591da177e4SLinus Torvalds 						printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]);
20601da177e4SLinus Torvalds 						tmp = 0;
20611da177e4SLinus Torvalds 					}
206211d2f63bSFinn Thain 
206311d2f63bSFinn Thain 					spin_lock_irq(&hostdata->lock);
206411d2f63bSFinn Thain 					if (!hostdata->connected)
206511d2f63bSFinn Thain 						return;
206611d2f63bSFinn Thain 
20671da177e4SLinus Torvalds 					/* Fall through to reject message */
20681da177e4SLinus Torvalds 
20691da177e4SLinus Torvalds 					/*
20701da177e4SLinus Torvalds 					 * If we get something weird that we aren't expecting,
20711da177e4SLinus Torvalds 					 * reject it.
20721da177e4SLinus Torvalds 					 */
20731da177e4SLinus Torvalds 				default:
20741da177e4SLinus Torvalds 					if (!tmp) {
20751da177e4SLinus Torvalds 						printk("scsi%d: rejecting message ", instance->host_no);
20761abfd370SMatthew Wilcox 						spi_print_msg(extended_msg);
20771da177e4SLinus Torvalds 						printk("\n");
20781da177e4SLinus Torvalds 					} else if (tmp != EXTENDED_MESSAGE)
2079017560fcSJeff Garzik 						scmd_printk(KERN_INFO, cmd,
2080017560fcSJeff Garzik 							"rejecting unknown message %02x\n",tmp);
20811da177e4SLinus Torvalds 					else
2082017560fcSJeff Garzik 						scmd_printk(KERN_INFO, cmd,
2083017560fcSJeff Garzik 							"rejecting unknown extended message code %02x, length %d\n", extended_msg[1], extended_msg[0]);
20841da177e4SLinus Torvalds 
20851da177e4SLinus Torvalds 					msgout = MESSAGE_REJECT;
20861da177e4SLinus Torvalds 					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
20871da177e4SLinus Torvalds 					break;
20881da177e4SLinus Torvalds 				}	/* switch (tmp) */
20891da177e4SLinus Torvalds 				break;
20901da177e4SLinus Torvalds 			case PHASE_MSGOUT:
20911da177e4SLinus Torvalds 				len = 1;
20921da177e4SLinus Torvalds 				data = &msgout;
20931da177e4SLinus Torvalds 				hostdata->last_message = msgout;
20941da177e4SLinus Torvalds 				NCR5380_transfer_pio(instance, &phase, &len, &data);
20951da177e4SLinus Torvalds 				if (msgout == ABORT) {
20961da177e4SLinus Torvalds 					hostdata->connected = NULL;
20971da177e4SLinus Torvalds 					cmd->result = DID_ERROR << 16;
2098677e0194SFinn Thain 					complete_cmd(instance, cmd);
20991da177e4SLinus Torvalds 					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
21001da177e4SLinus Torvalds 					return;
21011da177e4SLinus Torvalds 				}
21021da177e4SLinus Torvalds 				msgout = NOP;
21031da177e4SLinus Torvalds 				break;
21041da177e4SLinus Torvalds 			case PHASE_CMDOUT:
21051da177e4SLinus Torvalds 				len = cmd->cmd_len;
21061da177e4SLinus Torvalds 				data = cmd->cmnd;
21071da177e4SLinus Torvalds 				/*
21081da177e4SLinus Torvalds 				 * XXX for performance reasons, on machines with a
21091da177e4SLinus Torvalds 				 * PSEUDO-DMA architecture we should probably
21101da177e4SLinus Torvalds 				 * use the dma transfer function.
21111da177e4SLinus Torvalds 				 */
21121da177e4SLinus Torvalds 				NCR5380_transfer_pio(instance, &phase, &len, &data);
21131da177e4SLinus Torvalds 				break;
21141da177e4SLinus Torvalds 			case PHASE_STATIN:
21151da177e4SLinus Torvalds 				len = 1;
21161da177e4SLinus Torvalds 				data = &tmp;
21171da177e4SLinus Torvalds 				NCR5380_transfer_pio(instance, &phase, &len, &data);
21181da177e4SLinus Torvalds 				cmd->SCp.Status = tmp;
21191da177e4SLinus Torvalds 				break;
21201da177e4SLinus Torvalds 			default:
21211da177e4SLinus Torvalds 				printk("scsi%d : unknown phase\n", instance->host_no);
21224dde8f7dSFinn Thain 				NCR5380_dprint(NDEBUG_ANY, instance);
21231da177e4SLinus Torvalds 			}	/* switch(phase) */
2124686f3990SFinn Thain 		} else {
212511d2f63bSFinn Thain 			spin_unlock_irq(&hostdata->lock);
2126686f3990SFinn Thain 			NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
212711d2f63bSFinn Thain 			spin_lock_irq(&hostdata->lock);
21281da177e4SLinus Torvalds 		}
212911d2f63bSFinn Thain 	}
21301da177e4SLinus Torvalds }
21311da177e4SLinus Torvalds 
21321da177e4SLinus Torvalds /*
21331da177e4SLinus Torvalds  * Function : void NCR5380_reselect (struct Scsi_Host *instance)
21341da177e4SLinus Torvalds  *
21351da177e4SLinus Torvalds  * Purpose : does reselection, initializing the instance->connected
2136710ddd0dSFinn Thain  *      field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
21371da177e4SLinus Torvalds  *      nexus has been reestablished,
21381da177e4SLinus Torvalds  *
21391da177e4SLinus Torvalds  * Inputs : instance - this instance of the NCR5380.
21401da177e4SLinus Torvalds  *
21411da177e4SLinus Torvalds  * Locks: io_request_lock held by caller if IRQ driven
21421da177e4SLinus Torvalds  */
21431da177e4SLinus Torvalds 
21441da177e4SLinus Torvalds static void NCR5380_reselect(struct Scsi_Host *instance) {
2145e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
21461da177e4SLinus Torvalds 	unsigned char target_mask;
21471da177e4SLinus Torvalds 	unsigned char lun, phase;
21481da177e4SLinus Torvalds 	int len;
21491da177e4SLinus Torvalds 	unsigned char msg[3];
21501da177e4SLinus Torvalds 	unsigned char *data;
215132b26a10SFinn Thain 	struct NCR5380_cmd *ncmd;
215232b26a10SFinn Thain 	struct scsi_cmnd *tmp;
21531da177e4SLinus Torvalds 
21541da177e4SLinus Torvalds 	/*
21551da177e4SLinus Torvalds 	 * Disable arbitration, etc. since the host adapter obviously
21561da177e4SLinus Torvalds 	 * lost, and tell an interrupted NCR5380_select() to restart.
21571da177e4SLinus Torvalds 	 */
21581da177e4SLinus Torvalds 
21591da177e4SLinus Torvalds 	NCR5380_write(MODE_REG, MR_BASE);
21601da177e4SLinus Torvalds 
21611da177e4SLinus Torvalds 	target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
216272064a78SFinn Thain 	dprintk(NDEBUG_RESELECTION, "scsi%d : reselect\n", instance->host_no);
21631da177e4SLinus Torvalds 
21641da177e4SLinus Torvalds 	/*
21651da177e4SLinus Torvalds 	 * At this point, we have detected that our SCSI ID is on the bus,
21661da177e4SLinus Torvalds 	 * SEL is true and BSY was false for at least one bus settle delay
21671da177e4SLinus Torvalds 	 * (400 ns).
21681da177e4SLinus Torvalds 	 *
21691da177e4SLinus Torvalds 	 * We must assert BSY ourselves, until the target drops the SEL
21701da177e4SLinus Torvalds 	 * signal.
21711da177e4SLinus Torvalds 	 */
21721da177e4SLinus Torvalds 
21731da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
217472064a78SFinn Thain 	if (NCR5380_poll_politely(instance,
217572064a78SFinn Thain 	                          STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) {
217672064a78SFinn Thain 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
217772064a78SFinn Thain 		return;
217872064a78SFinn Thain 	}
21791da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
21801da177e4SLinus Torvalds 
21811da177e4SLinus Torvalds 	/*
21821da177e4SLinus Torvalds 	 * Wait for target to go into MSGIN.
21831da177e4SLinus Torvalds 	 */
21841da177e4SLinus Torvalds 
21851cc160e1SFinn Thain 	if (NCR5380_poll_politely(instance,
218672064a78SFinn Thain 	                          STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) {
218772064a78SFinn Thain 		do_abort(instance);
218872064a78SFinn Thain 		return;
218972064a78SFinn Thain 	}
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds 	len = 1;
21921da177e4SLinus Torvalds 	data = msg;
21931da177e4SLinus Torvalds 	phase = PHASE_MSGIN;
21941da177e4SLinus Torvalds 	NCR5380_transfer_pio(instance, &phase, &len, &data);
21951da177e4SLinus Torvalds 
219672064a78SFinn Thain 	if (len) {
219772064a78SFinn Thain 		do_abort(instance);
219872064a78SFinn Thain 		return;
219972064a78SFinn Thain 	}
220072064a78SFinn Thain 
22011da177e4SLinus Torvalds 	if (!(msg[0] & 0x80)) {
220272064a78SFinn Thain 		shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got ");
22031abfd370SMatthew Wilcox 		spi_print_msg(msg);
220472064a78SFinn Thain 		printk("\n");
220572064a78SFinn Thain 		do_abort(instance);
220672064a78SFinn Thain 		return;
220772064a78SFinn Thain 	}
220872064a78SFinn Thain 	lun = msg[0] & 0x07;
22091da177e4SLinus Torvalds 
22101da177e4SLinus Torvalds 	/*
22111da177e4SLinus Torvalds 	 * We need to add code for SCSI-II to track which devices have
22121da177e4SLinus Torvalds 	 * I_T_L_Q nexuses established, and which have simple I_T_L
22131da177e4SLinus Torvalds 	 * nexuses so we can chose to do additional data transfer.
22141da177e4SLinus Torvalds 	 */
22151da177e4SLinus Torvalds 
22161da177e4SLinus Torvalds 	/*
22171da177e4SLinus Torvalds 	 * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we
22181da177e4SLinus Torvalds 	 * just reestablished, and remove it from the disconnected queue.
22191da177e4SLinus Torvalds 	 */
22201da177e4SLinus Torvalds 
222132b26a10SFinn Thain 	tmp = NULL;
222232b26a10SFinn Thain 	list_for_each_entry(ncmd, &hostdata->disconnected, list) {
222332b26a10SFinn Thain 		struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
222432b26a10SFinn Thain 
222532b26a10SFinn Thain 		if (target_mask == (1 << scmd_id(cmd)) &&
222632b26a10SFinn Thain 		    lun == (u8)cmd->device->lun) {
222732b26a10SFinn Thain 			list_del(&ncmd->list);
222832b26a10SFinn Thain 			tmp = cmd;
22291da177e4SLinus Torvalds 			break;
22301da177e4SLinus Torvalds 		}
223172064a78SFinn Thain 	}
22320d3d9a42SFinn Thain 
22330d3d9a42SFinn Thain 	if (tmp) {
22340d3d9a42SFinn Thain 		dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance,
22350d3d9a42SFinn Thain 		         "reselect: removed %p from disconnected queue\n", tmp);
22360d3d9a42SFinn Thain 	} else {
223772064a78SFinn Thain 		shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n",
223872064a78SFinn Thain 		             target_mask, lun);
22391da177e4SLinus Torvalds 		/*
22401da177e4SLinus Torvalds 		 * Since we have an established nexus that we can't do anything with,
22411da177e4SLinus Torvalds 		 * we must abort it.
22421da177e4SLinus Torvalds 		 */
224372064a78SFinn Thain 		do_abort(instance);
224472064a78SFinn Thain 		return;
22451da177e4SLinus Torvalds 	}
22461da177e4SLinus Torvalds 
224772064a78SFinn Thain 	/* Accept message by clearing ACK */
224872064a78SFinn Thain 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
224972064a78SFinn Thain 
22501da177e4SLinus Torvalds 	hostdata->connected = tmp;
225172064a78SFinn Thain 	dprintk(NDEBUG_RESELECTION, "scsi%d : nexus established, target = %d, lun = %llu, tag = %d\n",
225272064a78SFinn Thain 	        instance->host_no, tmp->device->id, tmp->device->lun, tmp->tag);
22531da177e4SLinus Torvalds }
22541da177e4SLinus Torvalds 
22551da177e4SLinus Torvalds /*
22561da177e4SLinus Torvalds  * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
22571da177e4SLinus Torvalds  *
22581da177e4SLinus Torvalds  * Purpose : called by interrupt handler when DMA finishes or a phase
22591da177e4SLinus Torvalds  *      mismatch occurs (which would finish the DMA transfer).
22601da177e4SLinus Torvalds  *
22611da177e4SLinus Torvalds  * Inputs : instance - this instance of the NCR5380.
22621da177e4SLinus Torvalds  *
2263710ddd0dSFinn Thain  * Returns : pointer to the scsi_cmnd structure for which the I_T_L
22641da177e4SLinus Torvalds  *      nexus has been reestablished, on failure NULL is returned.
22651da177e4SLinus Torvalds  */
22661da177e4SLinus Torvalds 
22671da177e4SLinus Torvalds #ifdef REAL_DMA
22681da177e4SLinus Torvalds static void NCR5380_dma_complete(NCR5380_instance * instance) {
2269e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
22701da177e4SLinus Torvalds 	int transferred;
22711da177e4SLinus Torvalds 
22721da177e4SLinus Torvalds 	/*
22731da177e4SLinus Torvalds 	 * XXX this might not be right.
22741da177e4SLinus Torvalds 	 *
22751da177e4SLinus Torvalds 	 * Wait for final byte to transfer, ie wait for ACK to go false.
22761da177e4SLinus Torvalds 	 *
22771da177e4SLinus Torvalds 	 * We should use the Last Byte Sent bit, unfortunately this is
22781da177e4SLinus Torvalds 	 * not available on the 5380/5381 (only the various CMOS chips)
22791da177e4SLinus Torvalds 	 *
22801da177e4SLinus Torvalds 	 * FIXME: timeout, and need to handle long timeout/irq case
22811da177e4SLinus Torvalds 	 */
22821da177e4SLinus Torvalds 
22831da177e4SLinus Torvalds 	NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, BASR_ACK, 0, 5*HZ);
22841da177e4SLinus Torvalds 
22851da177e4SLinus Torvalds 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
22861da177e4SLinus Torvalds 
22871da177e4SLinus Torvalds 	/*
22881da177e4SLinus Torvalds 	 * The only places we should see a phase mismatch and have to send
22891da177e4SLinus Torvalds 	 * data from the same set of pointers will be the data transfer
22901da177e4SLinus Torvalds 	 * phases.  So, residual, requested length are only important here.
22911da177e4SLinus Torvalds 	 */
22921da177e4SLinus Torvalds 
22931da177e4SLinus Torvalds 	if (!(hostdata->connected->SCp.phase & SR_CD)) {
22941da177e4SLinus Torvalds 		transferred = instance->dmalen - NCR5380_dma_residual();
22951da177e4SLinus Torvalds 		hostdata->connected->SCp.this_residual -= transferred;
22961da177e4SLinus Torvalds 		hostdata->connected->SCp.ptr += transferred;
22971da177e4SLinus Torvalds 	}
22981da177e4SLinus Torvalds }
22991da177e4SLinus Torvalds #endif				/* def REAL_DMA */
23001da177e4SLinus Torvalds 
23018b00c3d5SFinn Thain /**
23028b00c3d5SFinn Thain  * list_find_cmd - test for presence of a command in a linked list
23038b00c3d5SFinn Thain  * @haystack: list of commands
23048b00c3d5SFinn Thain  * @needle: command to search for
23058b00c3d5SFinn Thain  */
23068b00c3d5SFinn Thain 
23078b00c3d5SFinn Thain static bool list_find_cmd(struct list_head *haystack,
23088b00c3d5SFinn Thain                           struct scsi_cmnd *needle)
23098b00c3d5SFinn Thain {
23108b00c3d5SFinn Thain 	struct NCR5380_cmd *ncmd;
23118b00c3d5SFinn Thain 
23128b00c3d5SFinn Thain 	list_for_each_entry(ncmd, haystack, list)
23138b00c3d5SFinn Thain 		if (NCR5380_to_scmd(ncmd) == needle)
23148b00c3d5SFinn Thain 			return true;
23158b00c3d5SFinn Thain 	return false;
23168b00c3d5SFinn Thain }
23178b00c3d5SFinn Thain 
23188b00c3d5SFinn Thain /**
23198b00c3d5SFinn Thain  * list_remove_cmd - remove a command from linked list
23208b00c3d5SFinn Thain  * @haystack: list of commands
23218b00c3d5SFinn Thain  * @needle: command to remove
23228b00c3d5SFinn Thain  */
23238b00c3d5SFinn Thain 
23248b00c3d5SFinn Thain static bool list_del_cmd(struct list_head *haystack,
23258b00c3d5SFinn Thain                          struct scsi_cmnd *needle)
23268b00c3d5SFinn Thain {
23278b00c3d5SFinn Thain 	if (list_find_cmd(haystack, needle)) {
23288b00c3d5SFinn Thain 		struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle);
23298b00c3d5SFinn Thain 
23308b00c3d5SFinn Thain 		list_del(&ncmd->list);
23318b00c3d5SFinn Thain 		return true;
23328b00c3d5SFinn Thain 	}
23338b00c3d5SFinn Thain 	return false;
23348b00c3d5SFinn Thain }
23358b00c3d5SFinn Thain 
23368b00c3d5SFinn Thain /**
23378b00c3d5SFinn Thain  * NCR5380_abort - scsi host eh_abort_handler() method
23388b00c3d5SFinn Thain  * @cmd: the command to be aborted
23391da177e4SLinus Torvalds  *
23408b00c3d5SFinn Thain  * Try to abort a given command by removing it from queues and/or sending
23418b00c3d5SFinn Thain  * the target an abort message. This may not succeed in causing a target
23428b00c3d5SFinn Thain  * to abort the command. Nonetheless, the low-level driver must forget about
23438b00c3d5SFinn Thain  * the command because the mid-layer reclaims it and it may be re-issued.
23441da177e4SLinus Torvalds  *
23458b00c3d5SFinn Thain  * The normal path taken by a command is as follows. For EH we trace this
23468b00c3d5SFinn Thain  * same path to locate and abort the command.
23471da177e4SLinus Torvalds  *
23488b00c3d5SFinn Thain  * unissued -> selecting -> [unissued -> selecting ->]... connected ->
23498b00c3d5SFinn Thain  * [disconnected -> connected ->]...
23508b00c3d5SFinn Thain  * [autosense -> connected ->] done
23511da177e4SLinus Torvalds  *
23528b00c3d5SFinn Thain  * If cmd is unissued then just remove it.
23538b00c3d5SFinn Thain  * If cmd is disconnected, try to select the target.
23548b00c3d5SFinn Thain  * If cmd is connected, try to send an abort message.
23558b00c3d5SFinn Thain  * If cmd is waiting for autosense, give it a chance to complete but check
23568b00c3d5SFinn Thain  * that it isn't left connected.
23578b00c3d5SFinn Thain  * If cmd was not found at all then presumably it has already been completed,
23588b00c3d5SFinn Thain  * in which case return SUCCESS to try to avoid further EH measures.
23598b00c3d5SFinn Thain  * If the command has not completed yet, we must not fail to find it.
23601da177e4SLinus Torvalds  */
23611da177e4SLinus Torvalds 
2362710ddd0dSFinn Thain static int NCR5380_abort(struct scsi_cmnd *cmd)
2363710ddd0dSFinn Thain {
23641da177e4SLinus Torvalds 	struct Scsi_Host *instance = cmd->device->host;
2365e8a60144SFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
236611d2f63bSFinn Thain 	unsigned long flags;
23678b00c3d5SFinn Thain 	int result = SUCCESS;
23681da177e4SLinus Torvalds 
236911d2f63bSFinn Thain 	spin_lock_irqsave(&hostdata->lock, flags);
237011d2f63bSFinn Thain 
237132b26a10SFinn Thain #if (NDEBUG & NDEBUG_ANY)
23728b00c3d5SFinn Thain 	scmd_printk(KERN_INFO, cmd, __func__);
237332b26a10SFinn Thain #endif
2374e5c3fddfSFinn Thain 	NCR5380_dprint(NDEBUG_ANY, instance);
2375e5c3fddfSFinn Thain 	NCR5380_dprint_phase(NDEBUG_ANY, instance);
23761da177e4SLinus Torvalds 
23778b00c3d5SFinn Thain 	if (list_del_cmd(&hostdata->unissued, cmd)) {
23788b00c3d5SFinn Thain 		dsprintk(NDEBUG_ABORT, instance,
23798b00c3d5SFinn Thain 		         "abort: removed %p from issue queue\n", cmd);
23808b00c3d5SFinn Thain 		cmd->result = DID_ABORT << 16;
23818b00c3d5SFinn Thain 		cmd->scsi_done(cmd); /* No tag or busy flag to worry about */
23828b00c3d5SFinn Thain 	}
23838b00c3d5SFinn Thain 
2384707d62b3SFinn Thain 	if (hostdata->selecting == cmd) {
2385707d62b3SFinn Thain 		dsprintk(NDEBUG_ABORT, instance,
2386707d62b3SFinn Thain 		         "abort: cmd %p == selecting\n", cmd);
2387707d62b3SFinn Thain 		hostdata->selecting = NULL;
2388707d62b3SFinn Thain 		cmd->result = DID_ABORT << 16;
2389707d62b3SFinn Thain 		complete_cmd(instance, cmd);
2390707d62b3SFinn Thain 		goto out;
2391707d62b3SFinn Thain 	}
2392707d62b3SFinn Thain 
23938b00c3d5SFinn Thain 	if (list_del_cmd(&hostdata->disconnected, cmd)) {
23948b00c3d5SFinn Thain 		dsprintk(NDEBUG_ABORT, instance,
23958b00c3d5SFinn Thain 		         "abort: removed %p from disconnected list\n", cmd);
23968b00c3d5SFinn Thain 		cmd->result = DID_ERROR << 16;
23978b00c3d5SFinn Thain 		if (!hostdata->connected)
23988b00c3d5SFinn Thain 			NCR5380_select(instance, cmd);
23998b00c3d5SFinn Thain 		if (hostdata->connected != cmd) {
24008b00c3d5SFinn Thain 			complete_cmd(instance, cmd);
24018b00c3d5SFinn Thain 			result = FAILED;
24028b00c3d5SFinn Thain 			goto out;
24038b00c3d5SFinn Thain 		}
24048b00c3d5SFinn Thain 	}
24058b00c3d5SFinn Thain 
24068b00c3d5SFinn Thain 	if (hostdata->connected == cmd) {
24078b00c3d5SFinn Thain 		dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
24088b00c3d5SFinn Thain 		hostdata->connected = NULL;
24098b00c3d5SFinn Thain 		if (do_abort(instance)) {
24108b00c3d5SFinn Thain 			set_host_byte(cmd, DID_ERROR);
24118b00c3d5SFinn Thain 			complete_cmd(instance, cmd);
24128b00c3d5SFinn Thain 			result = FAILED;
24138b00c3d5SFinn Thain 			goto out;
24148b00c3d5SFinn Thain 		}
24158b00c3d5SFinn Thain 		set_host_byte(cmd, DID_ABORT);
24168b00c3d5SFinn Thain #ifdef REAL_DMA
24178b00c3d5SFinn Thain 		hostdata->dma_len = 0;
24188b00c3d5SFinn Thain #endif
24198b00c3d5SFinn Thain 		if (cmd->cmnd[0] == REQUEST_SENSE)
24208b00c3d5SFinn Thain 			complete_cmd(instance, cmd);
24218b00c3d5SFinn Thain 		else {
24228b00c3d5SFinn Thain 			struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd);
24238b00c3d5SFinn Thain 
24248b00c3d5SFinn Thain 			/* Perform autosense for this command */
24258b00c3d5SFinn Thain 			list_add(&ncmd->list, &hostdata->autosense);
24268b00c3d5SFinn Thain 		}
24278b00c3d5SFinn Thain 	}
24288b00c3d5SFinn Thain 
24298b00c3d5SFinn Thain 	if (list_find_cmd(&hostdata->autosense, cmd)) {
24308b00c3d5SFinn Thain 		dsprintk(NDEBUG_ABORT, instance,
24318b00c3d5SFinn Thain 		         "abort: found %p on sense queue\n", cmd);
24328b00c3d5SFinn Thain 		spin_unlock_irqrestore(&hostdata->lock, flags);
24338b00c3d5SFinn Thain 		queue_work(hostdata->work_q, &hostdata->main_task);
24348b00c3d5SFinn Thain 		msleep(1000);
24358b00c3d5SFinn Thain 		spin_lock_irqsave(&hostdata->lock, flags);
24368b00c3d5SFinn Thain 		if (list_del_cmd(&hostdata->autosense, cmd)) {
24378b00c3d5SFinn Thain 			dsprintk(NDEBUG_ABORT, instance,
24388b00c3d5SFinn Thain 			         "abort: removed %p from sense queue\n", cmd);
24398b00c3d5SFinn Thain 			set_host_byte(cmd, DID_ABORT);
24408b00c3d5SFinn Thain 			complete_cmd(instance, cmd);
24418b00c3d5SFinn Thain 			goto out;
24428b00c3d5SFinn Thain 		}
24438b00c3d5SFinn Thain 	}
24448b00c3d5SFinn Thain 
24458b00c3d5SFinn Thain 	if (hostdata->connected == cmd) {
24468b00c3d5SFinn Thain 		dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd);
24478b00c3d5SFinn Thain 		hostdata->connected = NULL;
24488b00c3d5SFinn Thain 		if (do_abort(instance)) {
24498b00c3d5SFinn Thain 			set_host_byte(cmd, DID_ERROR);
24508b00c3d5SFinn Thain 			complete_cmd(instance, cmd);
24518b00c3d5SFinn Thain 			result = FAILED;
24528b00c3d5SFinn Thain 			goto out;
24538b00c3d5SFinn Thain 		}
24548b00c3d5SFinn Thain 		set_host_byte(cmd, DID_ABORT);
24558b00c3d5SFinn Thain #ifdef REAL_DMA
24568b00c3d5SFinn Thain 		hostdata->dma_len = 0;
24578b00c3d5SFinn Thain #endif
24588b00c3d5SFinn Thain 		complete_cmd(instance, cmd);
24598b00c3d5SFinn Thain 	}
24608b00c3d5SFinn Thain 
24618b00c3d5SFinn Thain out:
24628b00c3d5SFinn Thain 	if (result == FAILED)
24638b00c3d5SFinn Thain 		dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd);
24648b00c3d5SFinn Thain 	else
24658b00c3d5SFinn Thain 		dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd);
24668b00c3d5SFinn Thain 
24678b00c3d5SFinn Thain 	queue_work(hostdata->work_q, &hostdata->main_task);
246811d2f63bSFinn Thain 	spin_unlock_irqrestore(&hostdata->lock, flags);
24691da177e4SLinus Torvalds 
24708b00c3d5SFinn Thain 	return result;
24711da177e4SLinus Torvalds }
24721da177e4SLinus Torvalds 
24731da177e4SLinus Torvalds 
24743be1b3eaSFinn Thain /**
24753be1b3eaSFinn Thain  * NCR5380_bus_reset - reset the SCSI bus
24763be1b3eaSFinn Thain  * @cmd: SCSI command undergoing EH
24771da177e4SLinus Torvalds  *
24783be1b3eaSFinn Thain  * Returns SUCCESS
24791da177e4SLinus Torvalds  */
24801da177e4SLinus Torvalds 
2481710ddd0dSFinn Thain static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
248268b3aa7cSJeff Garzik  {
248368b3aa7cSJeff Garzik  	struct Scsi_Host *instance = cmd->device->host;
248411d2f63bSFinn Thain 	struct NCR5380_hostdata *hostdata = shost_priv(instance);
2485*62717f53SFinn Thain 	int i;
248611d2f63bSFinn Thain 	unsigned long flags;
2487*62717f53SFinn Thain 	struct NCR5380_cmd *ncmd;
24881da177e4SLinus Torvalds 
248911d2f63bSFinn Thain 	spin_lock_irqsave(&hostdata->lock, flags);
24903be1b3eaSFinn Thain 
24913be1b3eaSFinn Thain #if (NDEBUG & NDEBUG_ANY)
2492*62717f53SFinn Thain 	scmd_printk(KERN_INFO, cmd, __func__);
24933be1b3eaSFinn Thain #endif
2494e5c3fddfSFinn Thain 	NCR5380_dprint(NDEBUG_ANY, instance);
2495e5c3fddfSFinn Thain 	NCR5380_dprint_phase(NDEBUG_ANY, instance);
24963be1b3eaSFinn Thain 
249768b3aa7cSJeff Garzik  	do_reset(instance);
24983be1b3eaSFinn Thain 
2499*62717f53SFinn Thain 	/* reset NCR registers */
2500*62717f53SFinn Thain 	NCR5380_write(MODE_REG, MR_BASE);
2501*62717f53SFinn Thain 	NCR5380_write(TARGET_COMMAND_REG, 0);
2502*62717f53SFinn Thain 	NCR5380_write(SELECT_ENABLE_REG, 0);
2503*62717f53SFinn Thain 
2504*62717f53SFinn Thain 	/* After the reset, there are no more connected or disconnected commands
2505*62717f53SFinn Thain 	 * and no busy units; so clear the low-level status here to avoid
2506*62717f53SFinn Thain 	 * conflicts when the mid-level code tries to wake up the affected
2507*62717f53SFinn Thain 	 * commands!
2508*62717f53SFinn Thain 	 */
2509*62717f53SFinn Thain 
2510*62717f53SFinn Thain 	hostdata->selecting = NULL;
2511*62717f53SFinn Thain 
2512*62717f53SFinn Thain 	list_for_each_entry(ncmd, &hostdata->disconnected, list) {
2513*62717f53SFinn Thain 		struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
2514*62717f53SFinn Thain 
2515*62717f53SFinn Thain 		set_host_byte(cmd, DID_RESET);
2516*62717f53SFinn Thain 		cmd->scsi_done(cmd);
2517*62717f53SFinn Thain 	}
2518*62717f53SFinn Thain 
2519*62717f53SFinn Thain 	list_for_each_entry(ncmd, &hostdata->autosense, list) {
2520*62717f53SFinn Thain 		struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd);
2521*62717f53SFinn Thain 
2522*62717f53SFinn Thain 		set_host_byte(cmd, DID_RESET);
2523*62717f53SFinn Thain 		cmd->scsi_done(cmd);
2524*62717f53SFinn Thain 	}
2525*62717f53SFinn Thain 
2526*62717f53SFinn Thain 	if (hostdata->connected) {
2527*62717f53SFinn Thain 		set_host_byte(hostdata->connected, DID_RESET);
2528*62717f53SFinn Thain 		complete_cmd(instance, hostdata->connected);
2529*62717f53SFinn Thain 		hostdata->connected = NULL;
2530*62717f53SFinn Thain 	}
2531*62717f53SFinn Thain 
2532*62717f53SFinn Thain 	if (hostdata->sensing) {
2533*62717f53SFinn Thain 		set_host_byte(hostdata->connected, DID_RESET);
2534*62717f53SFinn Thain 		complete_cmd(instance, hostdata->sensing);
2535*62717f53SFinn Thain 		hostdata->sensing = NULL;
2536*62717f53SFinn Thain 	}
2537*62717f53SFinn Thain 
2538*62717f53SFinn Thain 	for (i = 0; i < 8; ++i)
2539*62717f53SFinn Thain 		hostdata->busy[i] = 0;
2540*62717f53SFinn Thain #ifdef REAL_DMA
2541*62717f53SFinn Thain 	hostdata->dma_len = 0;
2542*62717f53SFinn Thain #endif
2543*62717f53SFinn Thain 
2544*62717f53SFinn Thain 	queue_work(hostdata->work_q, &hostdata->main_task);
254511d2f63bSFinn Thain 	spin_unlock_irqrestore(&hostdata->lock, flags);
254668b3aa7cSJeff Garzik  
25471da177e4SLinus Torvalds 	return SUCCESS;
25481da177e4SLinus Torvalds }
2549