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)) 4216a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n"); 4221da177e4SLinus Torvalds else { 4231da177e4SLinus Torvalds for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); 4246a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "phase %s\n", 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 ) { 929*b746545fSFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n"); 9301da177e4SLinus Torvalds NCR5380_information_transfer(instance); 9311da177e4SLinus Torvalds done = 0; 9321d3db59dSFinn Thain } 9331da177e4SLinus Torvalds } while (!done); 93411d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 9351da177e4SLinus Torvalds } 9361da177e4SLinus Torvalds 9371da177e4SLinus Torvalds #ifndef DONT_USE_INTR 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds /** 9401da177e4SLinus Torvalds * NCR5380_intr - generic NCR5380 irq handler 9411da177e4SLinus Torvalds * @irq: interrupt number 9421da177e4SLinus Torvalds * @dev_id: device info 9431da177e4SLinus Torvalds * 9441da177e4SLinus Torvalds * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses 9451da177e4SLinus Torvalds * from the disconnected queue, and restarting NCR5380_main() 9461da177e4SLinus Torvalds * as required. 9471da177e4SLinus Torvalds * 948cd400825SFinn Thain * The chip can assert IRQ in any of six different conditions. The IRQ flag 949cd400825SFinn Thain * is then cleared by reading the Reset Parity/Interrupt Register (RPIR). 950cd400825SFinn Thain * Three of these six conditions are latched in the Bus and Status Register: 951cd400825SFinn Thain * - End of DMA (cleared by ending DMA Mode) 952cd400825SFinn Thain * - Parity error (cleared by reading RPIR) 953cd400825SFinn Thain * - Loss of BSY (cleared by reading RPIR) 954cd400825SFinn Thain * Two conditions have flag bits that are not latched: 955cd400825SFinn Thain * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode) 956cd400825SFinn Thain * - Bus reset (non-maskable) 957cd400825SFinn Thain * The remaining condition has no flag bit at all: 958cd400825SFinn Thain * - Selection/reselection 959cd400825SFinn Thain * 960cd400825SFinn Thain * Hence, establishing the cause(s) of any interrupt is partly guesswork. 961cd400825SFinn Thain * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor 962cd400825SFinn Thain * claimed that "the design of the [DP8490] interrupt logic ensures 963cd400825SFinn Thain * interrupts will not be lost (they can be on the DP5380)." 964cd400825SFinn Thain * The L5380/53C80 datasheet from LOGIC Devices has more details. 965cd400825SFinn Thain * 966cd400825SFinn Thain * Checking for bus reset by reading RST is futile because of interrupt 967cd400825SFinn Thain * latency, but a bus reset will reset chip logic. Checking for parity error 968cd400825SFinn Thain * is unnecessary because that interrupt is never enabled. A Loss of BSY 969cd400825SFinn Thain * condition will clear DMA Mode. We can tell when this occurs because the 970cd400825SFinn Thain * the Busy Monitor interrupt is enabled together with DMA Mode. 9711da177e4SLinus Torvalds */ 9721da177e4SLinus Torvalds 973cd400825SFinn Thain static irqreturn_t NCR5380_intr(int irq, void *dev_id) 9741da177e4SLinus Torvalds { 975baa9aac6SJeff Garzik struct Scsi_Host *instance = dev_id; 976cd400825SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 977cd400825SFinn Thain int handled = 0; 9781da177e4SLinus Torvalds unsigned char basr; 9791da177e4SLinus Torvalds unsigned long flags; 9801da177e4SLinus Torvalds 98111d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 982cd400825SFinn Thain 9831da177e4SLinus Torvalds basr = NCR5380_read(BUS_AND_STATUS_REG); 9841da177e4SLinus Torvalds if (basr & BASR_IRQ) { 985cd400825SFinn Thain unsigned char mr = NCR5380_read(MODE_REG); 986cd400825SFinn Thain unsigned char sr = NCR5380_read(STATUS_REG); 987cd400825SFinn Thain 988*b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n", 989*b746545fSFinn Thain irq, basr, sr, mr); 990cd400825SFinn Thain 9911da177e4SLinus Torvalds #if defined(REAL_DMA) 992cd400825SFinn Thain if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) { 993cd400825SFinn Thain /* Probably End of DMA, Phase Mismatch or Loss of BSY. 994cd400825SFinn Thain * We ack IRQ after clearing Mode Register. Workarounds 995cd400825SFinn Thain * for End of DMA errata need to happen in DMA Mode. 9961da177e4SLinus Torvalds */ 9971da177e4SLinus Torvalds 998*b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n"); 999cd400825SFinn Thain 100025985edcSLucas De Marchi int transferred; 10011da177e4SLinus Torvalds 10021da177e4SLinus Torvalds if (!hostdata->connected) 1003cd400825SFinn Thain panic("scsi%d : DMA interrupt with no connected cmd\n", 1004cd400825SFinn Thain instance->hostno); 10051da177e4SLinus Torvalds 1006cd400825SFinn Thain transferred = hostdata->dmalen - NCR5380_dma_residual(instance); 10071da177e4SLinus Torvalds hostdata->connected->SCp.this_residual -= transferred; 10081da177e4SLinus Torvalds hostdata->connected->SCp.ptr += transferred; 10091da177e4SLinus Torvalds hostdata->dmalen = 0; 10101da177e4SLinus Torvalds 10111da177e4SLinus Torvalds /* FIXME: we need to poll briefly then defer a workqueue task ! */ 10121da177e4SLinus Torvalds NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2 * HZ); 10131da177e4SLinus Torvalds 10141da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1015cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1016cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 1017cd400825SFinn Thain } else 1018cd400825SFinn Thain #endif /* REAL_DMA */ 1019cd400825SFinn Thain if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) && 1020cd400825SFinn Thain (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) { 1021cd400825SFinn Thain /* Probably reselected */ 1022cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 1023cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 1024cd400825SFinn Thain 1025*b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n"); 1026cd400825SFinn Thain 1027cd400825SFinn Thain if (!hostdata->connected) { 1028cd400825SFinn Thain NCR5380_reselect(instance); 10298d8601a7SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 1030cd400825SFinn Thain } 1031cd400825SFinn Thain if (!hostdata->connected) 1032cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1033cd400825SFinn Thain } else { 1034cd400825SFinn Thain /* Probably Bus Reset */ 1035cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 1036cd400825SFinn Thain 1037*b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n"); 1038cd400825SFinn Thain } 1039cd400825SFinn Thain handled = 1; 1040cd400825SFinn Thain } else { 1041cd400825SFinn Thain shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n"); 1042cd400825SFinn Thain } 1043cd400825SFinn Thain 104411d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 1045cd400825SFinn Thain 1046cd400825SFinn Thain return IRQ_RETVAL(handled); 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds #endif 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds /* 1052710ddd0dSFinn Thain * Function : int NCR5380_select(struct Scsi_Host *instance, 1053710ddd0dSFinn Thain * struct scsi_cmnd *cmd) 10541da177e4SLinus Torvalds * 10551da177e4SLinus Torvalds * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, 10561da177e4SLinus Torvalds * including ARBITRATION, SELECTION, and initial message out for 10571da177e4SLinus Torvalds * IDENTIFY and queue messages. 10581da177e4SLinus Torvalds * 10591da177e4SLinus Torvalds * Inputs : instance - instantiation of the 5380 driver on which this 106076f13b93SFinn Thain * target lives, cmd - SCSI command to execute. 10611da177e4SLinus Torvalds * 1062707d62b3SFinn Thain * Returns cmd if selection failed but should be retried, 1063707d62b3SFinn Thain * NULL if selection failed and should not be retried, or 1064707d62b3SFinn Thain * NULL if selection succeeded (hostdata->connected == cmd). 10651da177e4SLinus Torvalds * 10661da177e4SLinus Torvalds * Side effects : 10671da177e4SLinus Torvalds * If bus busy, arbitration failed, etc, NCR5380_select() will exit 10681da177e4SLinus Torvalds * with registers as they should have been on entry - ie 10691da177e4SLinus Torvalds * SELECT_ENABLE will be set appropriately, the NCR5380 10701da177e4SLinus Torvalds * will cease to drive any SCSI bus signals. 10711da177e4SLinus Torvalds * 10721da177e4SLinus Torvalds * If successful : I_T_L or I_T_L_Q nexus will be established, 10731da177e4SLinus Torvalds * instance->connected will be set to cmd. 10741da177e4SLinus Torvalds * SELECT interrupt will be disabled. 10751da177e4SLinus Torvalds * 10761da177e4SLinus Torvalds * If failed (no target) : cmd->scsi_done() will be called, and the 10771da177e4SLinus Torvalds * cmd->result host byte set to DID_BAD_TARGET. 10781da177e4SLinus Torvalds * 10791da177e4SLinus Torvalds * Locks: caller holds hostdata lock in IRQ mode 10801da177e4SLinus Torvalds */ 10811da177e4SLinus Torvalds 1082707d62b3SFinn Thain static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, 1083707d62b3SFinn Thain struct scsi_cmnd *cmd) 10841da177e4SLinus Torvalds { 1085e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 10861da177e4SLinus Torvalds unsigned char tmp[3], phase; 10871da177e4SLinus Torvalds unsigned char *data; 10881da177e4SLinus Torvalds int len; 10891da177e4SLinus Torvalds int err; 10901da177e4SLinus Torvalds 10911da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_ARBITRATION, instance); 1092*b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n", 1093*b746545fSFinn Thain instance->this_id); 10941da177e4SLinus Torvalds 10951da177e4SLinus Torvalds /* 1096707d62b3SFinn Thain * Arbitration and selection phases are slow and involve dropping the 1097707d62b3SFinn Thain * lock, so we have to watch out for EH. An exception handler may 1098707d62b3SFinn Thain * change 'selecting' to NULL. This function will then return NULL 1099707d62b3SFinn Thain * so that the caller will forget about 'cmd'. (During information 1100707d62b3SFinn Thain * transfer phases, EH may change 'connected' to NULL.) 1101707d62b3SFinn Thain */ 1102707d62b3SFinn Thain hostdata->selecting = cmd; 1103707d62b3SFinn Thain 1104707d62b3SFinn Thain /* 11051da177e4SLinus Torvalds * Set the phase bits to 0, otherwise the NCR5380 won't drive the 11061da177e4SLinus Torvalds * data bus during SELECTION. 11071da177e4SLinus Torvalds */ 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 11101da177e4SLinus Torvalds 11111da177e4SLinus Torvalds /* 11121da177e4SLinus Torvalds * Start arbitration. 11131da177e4SLinus Torvalds */ 11141da177e4SLinus Torvalds 11151da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); 11161da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_ARBITRATE); 11171da177e4SLinus Torvalds 111855500d9bSFinn Thain /* The chip now waits for BUS FREE phase. Then after the 800 ns 111955500d9bSFinn Thain * Bus Free Delay, arbitration will begin. 11201da177e4SLinus Torvalds */ 11211da177e4SLinus Torvalds 112211d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 1123b32ade12SFinn Thain err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0, 1124b32ade12SFinn Thain INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, 1125b32ade12SFinn Thain ICR_ARBITRATION_PROGRESS, HZ); 112611d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 112755500d9bSFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) { 112855500d9bSFinn Thain /* Reselection interrupt */ 1129707d62b3SFinn Thain goto out; 113055500d9bSFinn Thain } 1131b32ade12SFinn Thain if (err < 0) { 1132b32ade12SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1133b32ade12SFinn Thain shost_printk(KERN_ERR, instance, 1134b32ade12SFinn Thain "select: arbitration timeout\n"); 1135707d62b3SFinn Thain goto out; 113655500d9bSFinn Thain } 113711d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 113855500d9bSFinn Thain 113955500d9bSFinn Thain /* The SCSI-2 arbitration delay is 2.4 us */ 11401da177e4SLinus Torvalds udelay(3); 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds /* Check for lost arbitration */ 11431da177e4SLinus 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)) { 11441da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 1145*b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n"); 114611d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1147707d62b3SFinn Thain goto out; 11481da177e4SLinus Torvalds } 1149cf13b083SFinn Thain 1150cf13b083SFinn Thain /* After/during arbitration, BSY should be asserted. 1151cf13b083SFinn Thain * IBM DPES-31080 Version S31Q works now 1152cf13b083SFinn Thain * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) 1153cf13b083SFinn Thain */ 1154cf13b083SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, 1155cf13b083SFinn Thain ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY); 11561da177e4SLinus Torvalds 11571da177e4SLinus Torvalds /* 11581da177e4SLinus Torvalds * Again, bus clear + bus settle time is 1.2us, however, this is 11591da177e4SLinus Torvalds * a minimum so we'll udelay ceil(1.2) 11601da177e4SLinus Torvalds */ 11611da177e4SLinus Torvalds 11629c3f0e2bSFinn Thain if (hostdata->flags & FLAG_TOSHIBA_DELAY) 11639c3f0e2bSFinn Thain udelay(15); 11649c3f0e2bSFinn Thain else 11651da177e4SLinus Torvalds udelay(2); 11661da177e4SLinus Torvalds 116711d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 116811d2f63bSFinn Thain 116972064a78SFinn Thain /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */ 117072064a78SFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) 1171707d62b3SFinn Thain goto out; 1172707d62b3SFinn Thain 1173707d62b3SFinn Thain if (!hostdata->selecting) { 1174707d62b3SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1175707d62b3SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1176707d62b3SFinn Thain goto out; 1177707d62b3SFinn Thain } 117872064a78SFinn Thain 1179*b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n"); 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds /* 11821da177e4SLinus Torvalds * Now that we have won arbitration, start Selection process, asserting 11831da177e4SLinus Torvalds * the host and target ID's on the SCSI bus. 11841da177e4SLinus Torvalds */ 11851da177e4SLinus Torvalds 1186422c0d61SJeff Garzik NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << scmd_id(cmd)))); 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds /* 11891da177e4SLinus Torvalds * Raise ATN while SEL is true before BSY goes false from arbitration, 11901da177e4SLinus Torvalds * since this is the only way to guarantee that we'll get a MESSAGE OUT 11911da177e4SLinus Torvalds * phase immediately after selection. 11921da177e4SLinus Torvalds */ 11931da177e4SLinus Torvalds 11941da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); 11951da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 11961da177e4SLinus Torvalds 11971da177e4SLinus Torvalds /* 11981da177e4SLinus Torvalds * Reselect interrupts must be turned off prior to the dropping of BSY, 11991da177e4SLinus Torvalds * otherwise we will trigger an interrupt. 12001da177e4SLinus Torvalds */ 12011da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 12021da177e4SLinus Torvalds 120311d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 120411d2f63bSFinn Thain 12051da177e4SLinus Torvalds /* 12061da177e4SLinus Torvalds * The initiator shall then wait at least two deskew delays and release 12071da177e4SLinus Torvalds * the BSY signal. 12081da177e4SLinus Torvalds */ 12091da177e4SLinus Torvalds udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ 12101da177e4SLinus Torvalds 12111da177e4SLinus Torvalds /* Reset BSY */ 12121da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds /* 12151da177e4SLinus Torvalds * Something weird happens when we cease to drive BSY - looks 12161da177e4SLinus Torvalds * like the board/chip is letting us do another read before the 12171da177e4SLinus Torvalds * appropriate propagation delay has expired, and we're confusing 12181da177e4SLinus Torvalds * a BSY signal from ourselves as the target's response to SELECTION. 12191da177e4SLinus Torvalds * 12201da177e4SLinus Torvalds * A small delay (the 'C++' frontend breaks the pipeline with an 12211da177e4SLinus Torvalds * unnecessary jump, making it work on my 386-33/Trantor T128, the 12221da177e4SLinus Torvalds * tighter 'C' code breaks and requires this) solves the problem - 12231da177e4SLinus Torvalds * the 1 us delay is arbitrary, and only used because this delay will 12241da177e4SLinus Torvalds * be the same on other platforms and since it works here, it should 12251da177e4SLinus Torvalds * work there. 12261da177e4SLinus Torvalds * 12271da177e4SLinus Torvalds * wingel suggests that this could be due to failing to wait 12281da177e4SLinus Torvalds * one deskew delay. 12291da177e4SLinus Torvalds */ 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds udelay(1); 12321da177e4SLinus Torvalds 1233*b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd)); 12341da177e4SLinus Torvalds 12351da177e4SLinus Torvalds /* 12361da177e4SLinus Torvalds * The SCSI specification calls for a 250 ms timeout for the actual 12371da177e4SLinus Torvalds * selection. 12381da177e4SLinus Torvalds */ 12391da177e4SLinus Torvalds 1240ae753a33SFinn Thain err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY, 1241ae753a33SFinn Thain msecs_to_jiffies(250)); 12421da177e4SLinus Torvalds 12431da177e4SLinus Torvalds if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { 124411d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 12451da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 12461da177e4SLinus Torvalds NCR5380_reselect(instance); 1247cd400825SFinn Thain if (!hostdata->connected) 12481da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 12496a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n"); 1250707d62b3SFinn Thain goto out; 12511da177e4SLinus Torvalds } 1252ae753a33SFinn Thain 1253ae753a33SFinn Thain if (err < 0) { 125411d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1255ae753a33SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1256707d62b3SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1257707d62b3SFinn Thain /* Can't touch cmd if it has been reclaimed by the scsi ML */ 1258707d62b3SFinn Thain if (hostdata->selecting) { 1259ae753a33SFinn Thain cmd->result = DID_BAD_TARGET << 16; 1260677e0194SFinn Thain complete_cmd(instance, cmd); 1261707d62b3SFinn Thain dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n"); 1262707d62b3SFinn Thain cmd = NULL; 1263707d62b3SFinn Thain } 1264707d62b3SFinn Thain goto out; 1265ae753a33SFinn Thain } 1266ae753a33SFinn Thain 12671da177e4SLinus Torvalds /* 12681da177e4SLinus Torvalds * No less than two deskew delays after the initiator detects the 12691da177e4SLinus Torvalds * BSY signal is true, it shall release the SEL signal and may 12701da177e4SLinus Torvalds * change the DATA BUS. -wingel 12711da177e4SLinus Torvalds */ 12721da177e4SLinus Torvalds 12731da177e4SLinus Torvalds udelay(1); 12741da177e4SLinus Torvalds 12751da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 12761da177e4SLinus Torvalds 12771da177e4SLinus Torvalds /* 12781da177e4SLinus Torvalds * Since we followed the SCSI spec, and raised ATN while SEL 12791da177e4SLinus Torvalds * was true but before BSY was false during selection, the information 12801da177e4SLinus Torvalds * transfer phase should be a MESSAGE OUT phase so that we can send the 12811da177e4SLinus Torvalds * IDENTIFY message. 12821da177e4SLinus Torvalds * 12831da177e4SLinus Torvalds * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG 12841da177e4SLinus Torvalds * message (2 bytes) with a tag ID that we increment with every command 12851da177e4SLinus Torvalds * until it wraps back to 0. 12861da177e4SLinus Torvalds * 12871da177e4SLinus Torvalds * XXX - it turns out that there are some broken SCSI-II devices, 12881da177e4SLinus Torvalds * which claim to support tagged queuing but fail when more than 12891da177e4SLinus Torvalds * some number of commands are issued at once. 12901da177e4SLinus Torvalds */ 12911da177e4SLinus Torvalds 12921da177e4SLinus Torvalds /* Wait for start of REQ/ACK handshake */ 12931da177e4SLinus Torvalds 12941da177e4SLinus Torvalds err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ); 129511d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 12961cc160e1SFinn Thain if (err < 0) { 129755500d9bSFinn Thain shost_printk(KERN_ERR, instance, "select: REQ timeout\n"); 129855500d9bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 12991da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1300707d62b3SFinn Thain goto out; 1301707d62b3SFinn Thain } 1302707d62b3SFinn Thain if (!hostdata->selecting) { 1303707d62b3SFinn Thain do_abort(instance); 1304707d62b3SFinn Thain goto out; 13051da177e4SLinus Torvalds } 13061da177e4SLinus Torvalds 1307*b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n", 1308*b746545fSFinn Thain scmd_id(cmd)); 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); 1318*b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n"); 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 /* 13661da177e4SLinus Torvalds * The NCR5380 chip will only drive the SCSI bus when the 13671da177e4SLinus Torvalds * phase specified in the appropriate bits of the TARGET COMMAND 13681da177e4SLinus Torvalds * REGISTER match the STATUS REGISTER 13691da177e4SLinus Torvalds */ 13701da177e4SLinus Torvalds 13711da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 13721da177e4SLinus Torvalds 13731da177e4SLinus Torvalds do { 13741da177e4SLinus Torvalds /* 13751da177e4SLinus Torvalds * Wait for assertion of REQ, after which the phase bits will be 13761da177e4SLinus Torvalds * valid 13771da177e4SLinus Torvalds */ 13781da177e4SLinus Torvalds 1379686f3990SFinn Thain if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0) 13801da177e4SLinus Torvalds break; 13811da177e4SLinus Torvalds 1382*b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n"); 13831da177e4SLinus Torvalds 13841da177e4SLinus Torvalds /* Check for phase mismatch */ 1385686f3990SFinn Thain if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) { 1386*b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "phase mismatch\n"); 1387*b746545fSFinn Thain NCR5380_dprint_phase(NDEBUG_PIO, instance); 13881da177e4SLinus Torvalds break; 13891da177e4SLinus Torvalds } 13901da177e4SLinus Torvalds /* Do actual transfer from SCSI bus to / from memory */ 13911da177e4SLinus Torvalds if (!(p & SR_IO)) 13921da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, *d); 13931da177e4SLinus Torvalds else 13941da177e4SLinus Torvalds *d = NCR5380_read(CURRENT_SCSI_DATA_REG); 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds ++d; 13971da177e4SLinus Torvalds 13981da177e4SLinus Torvalds /* 13991da177e4SLinus Torvalds * The SCSI standard suggests that in MSGOUT phase, the initiator 14001da177e4SLinus Torvalds * should drop ATN on the last byte of the message phase 14011da177e4SLinus Torvalds * after REQ has been asserted for the handshake but before 14021da177e4SLinus Torvalds * the initiator raises ACK. 14031da177e4SLinus Torvalds */ 14041da177e4SLinus Torvalds 14051da177e4SLinus Torvalds if (!(p & SR_IO)) { 14061da177e4SLinus Torvalds if (!((p & SR_MSG) && c > 1)) { 14071da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 14081da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 14091da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK); 14101da177e4SLinus Torvalds } else { 14111da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN); 14121da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 14131da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 14141da177e4SLinus Torvalds } 14151da177e4SLinus Torvalds } else { 14161da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 14171da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); 14181da177e4SLinus Torvalds } 14191da177e4SLinus Torvalds 1420a2edc4a6SFinn Thain if (NCR5380_poll_politely(instance, 1421a2edc4a6SFinn Thain STATUS_REG, SR_REQ, 0, 5 * HZ) < 0) 1422a2edc4a6SFinn Thain break; 1423a2edc4a6SFinn Thain 1424*b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n"); 14251da177e4SLinus Torvalds 14261da177e4SLinus Torvalds /* 14271da177e4SLinus Torvalds * We have several special cases to consider during REQ/ACK handshaking : 14281da177e4SLinus Torvalds * 1. We were in MSGOUT phase, and we are on the last byte of the 14291da177e4SLinus Torvalds * message. ATN must be dropped as ACK is dropped. 14301da177e4SLinus Torvalds * 14311da177e4SLinus Torvalds * 2. We are in a MSGIN phase, and we are on the last byte of the 14321da177e4SLinus Torvalds * message. We must exit with ACK asserted, so that the calling 14331da177e4SLinus Torvalds * code may raise ATN before dropping ACK to reject the message. 14341da177e4SLinus Torvalds * 14351da177e4SLinus Torvalds * 3. ACK and ATN are clear and the target may proceed as normal. 14361da177e4SLinus Torvalds */ 14371da177e4SLinus Torvalds if (!(p == PHASE_MSGIN && c == 1)) { 14381da177e4SLinus Torvalds if (p == PHASE_MSGOUT && c > 1) 14391da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 14401da177e4SLinus Torvalds else 14411da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 14421da177e4SLinus Torvalds } 14431da177e4SLinus Torvalds } while (--c); 14441da177e4SLinus Torvalds 1445*b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "residual %d\n", c); 14461da177e4SLinus Torvalds 14471da177e4SLinus Torvalds *count = c; 14481da177e4SLinus Torvalds *data = d; 14491da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 1450a2edc4a6SFinn Thain /* The phase read from the bus is valid if either REQ is (already) 1451a2edc4a6SFinn Thain * asserted or if ACK hasn't been released yet. The latter applies if 1452a2edc4a6SFinn Thain * we're in MSG IN, DATA IN or STATUS and all bytes have been received. 1453a2edc4a6SFinn Thain */ 1454a2edc4a6SFinn Thain if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0)) 14551da177e4SLinus Torvalds *phase = tmp & PHASE_MASK; 14561da177e4SLinus Torvalds else 14571da177e4SLinus Torvalds *phase = PHASE_UNKNOWN; 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds if (!c || (*phase == p)) 14601da177e4SLinus Torvalds return 0; 14611da177e4SLinus Torvalds else 14621da177e4SLinus Torvalds return -1; 14631da177e4SLinus Torvalds } 14641da177e4SLinus Torvalds 14651da177e4SLinus Torvalds /** 14661da177e4SLinus Torvalds * do_reset - issue a reset command 1467636b1ec8SFinn Thain * @instance: adapter to reset 14681da177e4SLinus Torvalds * 14691da177e4SLinus Torvalds * Issue a reset sequence to the NCR5380 and try and get the bus 14701da177e4SLinus Torvalds * back into sane shape. 14711da177e4SLinus Torvalds * 1472636b1ec8SFinn Thain * This clears the reset interrupt flag because there may be no handler for 1473636b1ec8SFinn Thain * it. When the driver is initialized, the NCR5380_intr() handler has not yet 1474636b1ec8SFinn Thain * been installed. And when in EH we may have released the ST DMA interrupt. 14751da177e4SLinus Torvalds */ 14761da177e4SLinus Torvalds 147754d8fe44SFinn Thain static void do_reset(struct Scsi_Host *instance) 147854d8fe44SFinn Thain { 1479636b1ec8SFinn Thain unsigned long flags; 1480636b1ec8SFinn Thain 1481636b1ec8SFinn Thain local_irq_save(flags); 1482636b1ec8SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 1483636b1ec8SFinn Thain PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); 14841da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); 1485636b1ec8SFinn Thain udelay(50); 14861da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1487636b1ec8SFinn Thain (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); 1488636b1ec8SFinn Thain local_irq_restore(flags); 14891da177e4SLinus Torvalds } 14901da177e4SLinus Torvalds 149180d3eb6dSFinn Thain /** 149280d3eb6dSFinn Thain * do_abort - abort the currently established nexus by going to 149380d3eb6dSFinn Thain * MESSAGE OUT phase and sending an ABORT message. 149480d3eb6dSFinn Thain * @instance: relevant scsi host instance 14951da177e4SLinus Torvalds * 149680d3eb6dSFinn Thain * Returns 0 on success, -1 on failure. 14971da177e4SLinus Torvalds */ 14981da177e4SLinus Torvalds 149954d8fe44SFinn Thain static int do_abort(struct Scsi_Host *instance) 150054d8fe44SFinn Thain { 15011da177e4SLinus Torvalds unsigned char *msgptr, phase, tmp; 15021da177e4SLinus Torvalds int len; 15031da177e4SLinus Torvalds int rc; 15041da177e4SLinus Torvalds 15051da177e4SLinus Torvalds /* Request message out phase */ 15061da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 15071da177e4SLinus Torvalds 15081da177e4SLinus Torvalds /* 15091da177e4SLinus Torvalds * Wait for the target to indicate a valid phase by asserting 15101da177e4SLinus Torvalds * REQ. Once this happens, we'll have either a MSGOUT phase 15111da177e4SLinus Torvalds * and can immediately send the ABORT message, or we'll have some 15121da177e4SLinus Torvalds * other phase and will have to source/sink data. 15131da177e4SLinus Torvalds * 15141da177e4SLinus Torvalds * We really don't care what value was on the bus or what value 15151da177e4SLinus Torvalds * the target sees, so we just handshake. 15161da177e4SLinus Torvalds */ 15171da177e4SLinus Torvalds 151880d3eb6dSFinn Thain rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ); 15191da177e4SLinus Torvalds if (rc < 0) 152080d3eb6dSFinn Thain goto timeout; 15211da177e4SLinus Torvalds 1522f35d3474SFinn Thain tmp = NCR5380_read(STATUS_REG) & PHASE_MASK; 15231da177e4SLinus Torvalds 15241da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 15251da177e4SLinus Torvalds 1526f35d3474SFinn Thain if (tmp != PHASE_MSGOUT) { 15271da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 152854d8fe44SFinn Thain rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ); 15291cc160e1SFinn Thain if (rc < 0) 153080d3eb6dSFinn Thain goto timeout; 153180d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 15321da177e4SLinus Torvalds } 15331da177e4SLinus Torvalds tmp = ABORT; 15341da177e4SLinus Torvalds msgptr = &tmp; 15351da177e4SLinus Torvalds len = 1; 15361da177e4SLinus Torvalds phase = PHASE_MSGOUT; 153754d8fe44SFinn Thain NCR5380_transfer_pio(instance, &phase, &len, &msgptr); 15381da177e4SLinus Torvalds 15391da177e4SLinus Torvalds /* 15401da177e4SLinus Torvalds * If we got here, and the command completed successfully, 15411da177e4SLinus Torvalds * we're about to go into bus free state. 15421da177e4SLinus Torvalds */ 15431da177e4SLinus Torvalds 15441da177e4SLinus Torvalds return len ? -1 : 0; 154580d3eb6dSFinn Thain 154680d3eb6dSFinn Thain timeout: 154780d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 154880d3eb6dSFinn Thain return -1; 15491da177e4SLinus Torvalds } 15501da177e4SLinus Torvalds 15511da177e4SLinus Torvalds #if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL) 15521da177e4SLinus Torvalds /* 15531da177e4SLinus Torvalds * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 15541da177e4SLinus Torvalds * unsigned char *phase, int *count, unsigned char **data) 15551da177e4SLinus Torvalds * 15561da177e4SLinus Torvalds * Purpose : transfers data in given phase using either real 15571da177e4SLinus Torvalds * or pseudo DMA. 15581da177e4SLinus Torvalds * 15591da177e4SLinus Torvalds * Inputs : instance - instance of driver, *phase - pointer to 15601da177e4SLinus Torvalds * what phase is expected, *count - pointer to number of 15611da177e4SLinus Torvalds * bytes to transfer, **data - pointer to data pointer. 15621da177e4SLinus Torvalds * 15631da177e4SLinus Torvalds * Returns : -1 when different phase is entered without transferring 156425985edcSLucas De Marchi * maximum number of bytes, 0 if all bytes or transferred or exit 15651da177e4SLinus Torvalds * is in same phase. 15661da177e4SLinus Torvalds * 15671da177e4SLinus Torvalds * Also, *phase, *count, *data are modified in place. 15681da177e4SLinus Torvalds * 15691da177e4SLinus Torvalds * Locks: io_request lock held by caller 15701da177e4SLinus Torvalds */ 15711da177e4SLinus Torvalds 15721da177e4SLinus Torvalds 15731da177e4SLinus Torvalds static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { 15741da177e4SLinus Torvalds register int c = *count; 15751da177e4SLinus Torvalds register unsigned char p = *phase; 15761da177e4SLinus Torvalds register unsigned char *d = *data; 15771da177e4SLinus Torvalds unsigned char tmp; 15781da177e4SLinus Torvalds int foo; 15791da177e4SLinus Torvalds #if defined(REAL_DMA_POLL) 15801da177e4SLinus Torvalds int cnt, toPIO; 15811da177e4SLinus Torvalds unsigned char saved_data = 0, overrun = 0, residue; 15821da177e4SLinus Torvalds #endif 15831da177e4SLinus Torvalds 1584e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { 15871da177e4SLinus Torvalds *phase = tmp; 15881da177e4SLinus Torvalds return -1; 15891da177e4SLinus Torvalds } 15901da177e4SLinus Torvalds #if defined(REAL_DMA) || defined(REAL_DMA_POLL) 15911da177e4SLinus Torvalds if (p & SR_IO) { 15929db6024eSFinn Thain if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS)) 15931da177e4SLinus Torvalds c -= 2; 15941da177e4SLinus Torvalds } 15951da177e4SLinus Torvalds hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); 1596*b746545fSFinn Thain 1597*b746545fSFinn Thain dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n", 1598*b746545fSFinn Thain (p & SR_IO) ? "receive" : "send", c, *data); 15991da177e4SLinus Torvalds #endif 16001da177e4SLinus Torvalds 16011da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 16021da177e4SLinus Torvalds 16031da177e4SLinus Torvalds #ifdef REAL_DMA 1604cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY | 1605cd400825SFinn Thain MR_ENABLE_EOP_INTR); 16061da177e4SLinus Torvalds #elif defined(REAL_DMA_POLL) 1607cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY); 16081da177e4SLinus Torvalds #else 16091da177e4SLinus Torvalds /* 16101da177e4SLinus Torvalds * Note : on my sample board, watch-dog timeouts occurred when interrupts 16111da177e4SLinus Torvalds * were not disabled for the duration of a single DMA transfer, from 16121da177e4SLinus Torvalds * before the setting of DMA mode to after transfer of the last byte. 16131da177e4SLinus Torvalds */ 16141da177e4SLinus Torvalds 161555181be8SFinn Thain if (hostdata->flags & FLAG_NO_DMA_FIXUP) 1616cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY | 1617cd400825SFinn Thain MR_ENABLE_EOP_INTR); 16181da177e4SLinus Torvalds else 1619cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY); 16201da177e4SLinus Torvalds #endif /* def REAL_DMA */ 16211da177e4SLinus Torvalds 162252a6a1cbSFinn Thain dprintk(NDEBUG_DMA, "scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); 16231da177e4SLinus Torvalds 16241da177e4SLinus Torvalds /* 16251da177e4SLinus Torvalds * On the PAS16 at least I/O recovery delays are not needed here. 16261da177e4SLinus Torvalds * Everyone else seems to want them. 16271da177e4SLinus Torvalds */ 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds if (p & SR_IO) { 16301da177e4SLinus Torvalds io_recovery_delay(1); 16311da177e4SLinus Torvalds NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); 16321da177e4SLinus Torvalds } else { 16331da177e4SLinus Torvalds io_recovery_delay(1); 16341da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 16351da177e4SLinus Torvalds io_recovery_delay(1); 16361da177e4SLinus Torvalds NCR5380_write(START_DMA_SEND_REG, 0); 16371da177e4SLinus Torvalds io_recovery_delay(1); 16381da177e4SLinus Torvalds } 16391da177e4SLinus Torvalds 16401da177e4SLinus Torvalds #if defined(REAL_DMA_POLL) 16411da177e4SLinus Torvalds do { 16421da177e4SLinus Torvalds tmp = NCR5380_read(BUS_AND_STATUS_REG); 16431da177e4SLinus Torvalds } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER))); 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds /* 16461da177e4SLinus Torvalds At this point, either we've completed DMA, or we have a phase mismatch, 16471da177e4SLinus Torvalds or we've unexpectedly lost BUSY (which is a real error). 16481da177e4SLinus Torvalds 16491da177e4SLinus Torvalds For write DMAs, we want to wait until the last byte has been 16501da177e4SLinus Torvalds transferred out over the bus before we turn off DMA mode. Alas, there 16511da177e4SLinus Torvalds seems to be no terribly good way of doing this on a 5380 under all 16521da177e4SLinus Torvalds conditions. For non-scatter-gather operations, we can wait until REQ 16531da177e4SLinus Torvalds and ACK both go false, or until a phase mismatch occurs. Gather-writes 16541da177e4SLinus Torvalds are nastier, since the device will be expecting more data than we 16551da177e4SLinus Torvalds are prepared to send it, and REQ will remain asserted. On a 53C8[01] we 16561da177e4SLinus Torvalds could test LAST BIT SENT to assure transfer (I imagine this is precisely 16571da177e4SLinus Torvalds why this signal was added to the newer chips) but on the older 538[01] 16581da177e4SLinus Torvalds this signal does not exist. The workaround for this lack is a watchdog; 16591da177e4SLinus Torvalds we bail out of the wait-loop after a modest amount of wait-time if 16601da177e4SLinus Torvalds the usual exit conditions are not met. Not a terribly clean or 16611da177e4SLinus Torvalds correct solution :-% 16621da177e4SLinus Torvalds 16631da177e4SLinus Torvalds Reads are equally tricky due to a nasty characteristic of the NCR5380. 16641da177e4SLinus Torvalds If the chip is in DMA mode for an READ, it will respond to a target's 16651da177e4SLinus Torvalds REQ by latching the SCSI data into the INPUT DATA register and asserting 16661da177e4SLinus Torvalds ACK, even if it has _already_ been notified by the DMA controller that 16671da177e4SLinus Torvalds the current DMA transfer has completed! If the NCR5380 is then taken 16681da177e4SLinus Torvalds out of DMA mode, this already-acknowledged byte is lost. 16691da177e4SLinus Torvalds 16701da177e4SLinus Torvalds This is not a problem for "one DMA transfer per command" reads, because 16711da177e4SLinus Torvalds the situation will never arise... either all of the data is DMA'ed 16721da177e4SLinus Torvalds properly, or the target switches to MESSAGE IN phase to signal a 16731da177e4SLinus Torvalds disconnection (either operation bringing the DMA to a clean halt). 16741da177e4SLinus Torvalds However, in order to handle scatter-reads, we must work around the 16751da177e4SLinus Torvalds problem. The chosen fix is to DMA N-2 bytes, then check for the 16761da177e4SLinus Torvalds condition before taking the NCR5380 out of DMA mode. One or two extra 16771da177e4SLinus Torvalds bytes are transferred via PIO as necessary to fill out the original 16781da177e4SLinus Torvalds request. 16791da177e4SLinus Torvalds */ 16801da177e4SLinus Torvalds 16811da177e4SLinus Torvalds if (p & SR_IO) { 16829db6024eSFinn Thain if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS)) { 16831da177e4SLinus Torvalds udelay(10); 16849db6024eSFinn Thain if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == 16859db6024eSFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) { 16861da177e4SLinus Torvalds saved_data = NCR5380_read(INPUT_DATA_REGISTER); 16871da177e4SLinus Torvalds overrun = 1; 16881da177e4SLinus Torvalds } 16899db6024eSFinn Thain } 16901da177e4SLinus Torvalds } else { 16911da177e4SLinus Torvalds int limit = 100; 16921da177e4SLinus Torvalds while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) { 16931da177e4SLinus Torvalds if (!(tmp & BASR_PHASE_MATCH)) 16941da177e4SLinus Torvalds break; 16951da177e4SLinus Torvalds if (--limit < 0) 16961da177e4SLinus Torvalds break; 16971da177e4SLinus Torvalds } 16981da177e4SLinus Torvalds } 16991da177e4SLinus Torvalds 1700*b746545fSFinn Thain dsprintk(NDEBUG_DMA, "polled DMA transfer complete, basr 0x%02x, sr 0x%02x\n", 1701*b746545fSFinn Thain tmp, NCR5380_read(STATUS_REG)); 17021da177e4SLinus Torvalds 17031da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 17041da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 17051da177e4SLinus Torvalds 17061da177e4SLinus Torvalds residue = NCR5380_dma_residual(instance); 17071da177e4SLinus Torvalds c -= residue; 17081da177e4SLinus Torvalds *count -= c; 17091da177e4SLinus Torvalds *data += c; 17101da177e4SLinus Torvalds *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; 17111da177e4SLinus Torvalds 17129db6024eSFinn Thain if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS) && 17139db6024eSFinn Thain *phase == p && (p & SR_IO) && residue == 0) { 17141da177e4SLinus Torvalds if (overrun) { 171552a6a1cbSFinn Thain dprintk(NDEBUG_DMA, "Got an input overrun, using saved byte\n"); 17161da177e4SLinus Torvalds **data = saved_data; 17171da177e4SLinus Torvalds *data += 1; 17181da177e4SLinus Torvalds *count -= 1; 17191da177e4SLinus Torvalds cnt = toPIO = 1; 17201da177e4SLinus Torvalds } else { 17211da177e4SLinus Torvalds printk("No overrun??\n"); 17221da177e4SLinus Torvalds cnt = toPIO = 2; 17231da177e4SLinus Torvalds } 172452a6a1cbSFinn Thain dprintk(NDEBUG_DMA, "Doing %d-byte PIO to 0x%X\n", cnt, *data); 17251da177e4SLinus Torvalds NCR5380_transfer_pio(instance, phase, &cnt, data); 17261da177e4SLinus Torvalds *count -= toPIO - cnt; 17271da177e4SLinus Torvalds } 17281da177e4SLinus Torvalds 172952a6a1cbSFinn 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)); 17301da177e4SLinus Torvalds return 0; 17311da177e4SLinus Torvalds 17321da177e4SLinus Torvalds #elif defined(REAL_DMA) 17331da177e4SLinus Torvalds return 0; 17341da177e4SLinus Torvalds #else /* defined(REAL_DMA_POLL) */ 17351da177e4SLinus Torvalds if (p & SR_IO) { 173655181be8SFinn Thain foo = NCR5380_pread(instance, d, 173755181be8SFinn Thain hostdata->flags & FLAG_NO_DMA_FIXUP ? c : c - 1); 173855181be8SFinn Thain if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) { 17391da177e4SLinus Torvalds /* 17401da177e4SLinus Torvalds * We can't disable DMA mode after successfully transferring 17411da177e4SLinus Torvalds * what we plan to be the last byte, since that would open up 17421da177e4SLinus Torvalds * a race condition where if the target asserted REQ before 17431da177e4SLinus Torvalds * we got the DMA mode reset, the NCR5380 would have latched 17441da177e4SLinus Torvalds * an additional byte into the INPUT DATA register and we'd 17451da177e4SLinus Torvalds * have dropped it. 17461da177e4SLinus Torvalds * 17471da177e4SLinus Torvalds * The workaround was to transfer one fewer bytes than we 17481da177e4SLinus Torvalds * intended to with the pseudo-DMA read function, wait for 17491da177e4SLinus Torvalds * the chip to latch the last byte, read it, and then disable 17501da177e4SLinus Torvalds * pseudo-DMA mode. 17511da177e4SLinus Torvalds * 17521da177e4SLinus Torvalds * After REQ is asserted, the NCR5380 asserts DRQ and ACK. 17531da177e4SLinus Torvalds * REQ is deasserted when ACK is asserted, and not reasserted 17541da177e4SLinus Torvalds * until ACK goes false. Since the NCR5380 won't lower ACK 17551da177e4SLinus Torvalds * until DACK is asserted, which won't happen unless we twiddle 17561da177e4SLinus Torvalds * the DMA port or we take the NCR5380 out of DMA mode, we 17571da177e4SLinus Torvalds * can guarantee that we won't handshake another extra 17581da177e4SLinus Torvalds * byte. 17591da177e4SLinus Torvalds */ 17601da177e4SLinus Torvalds 176155181be8SFinn Thain if (NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, 176255181be8SFinn Thain BASR_DRQ, BASR_DRQ, HZ) < 0) { 176355181be8SFinn Thain foo = -1; 176455181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n"); 176555181be8SFinn Thain } 176655181be8SFinn Thain if (NCR5380_poll_politely(instance, STATUS_REG, 176755181be8SFinn Thain SR_REQ, 0, HZ) < 0) { 176855181be8SFinn Thain foo = -1; 176955181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n"); 177055181be8SFinn Thain } 17711da177e4SLinus Torvalds d[c - 1] = NCR5380_read(INPUT_DATA_REG); 17721da177e4SLinus Torvalds } 17731da177e4SLinus Torvalds } else { 17741da177e4SLinus Torvalds foo = NCR5380_pwrite(instance, d, c); 177555181be8SFinn Thain if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) { 17761da177e4SLinus Torvalds /* 17771da177e4SLinus Torvalds * Wait for the last byte to be sent. If REQ is being asserted for 17781da177e4SLinus Torvalds * the byte we're interested, we'll ACK it and it will go false. 17791da177e4SLinus Torvalds */ 178055181be8SFinn Thain if (NCR5380_poll_politely2(instance, 178155181be8SFinn Thain BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ, 178255181be8SFinn Thain BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) { 178355181be8SFinn Thain foo = -1; 178455181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n"); 17851da177e4SLinus Torvalds } 17861da177e4SLinus Torvalds } 17871da177e4SLinus Torvalds } 17881da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 17891da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 17901da177e4SLinus Torvalds NCR5380_read(RESET_PARITY_INTERRUPT_REG); 17911da177e4SLinus Torvalds *data = d + c; 17921da177e4SLinus Torvalds *count = 0; 17931da177e4SLinus Torvalds *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; 17941da177e4SLinus Torvalds return foo; 17951da177e4SLinus Torvalds #endif /* def REAL_DMA */ 17961da177e4SLinus Torvalds } 17971da177e4SLinus Torvalds #endif /* defined(REAL_DMA) | defined(PSEUDO_DMA) */ 17981da177e4SLinus Torvalds 17991da177e4SLinus Torvalds /* 18001da177e4SLinus Torvalds * Function : NCR5380_information_transfer (struct Scsi_Host *instance) 18011da177e4SLinus Torvalds * 18021da177e4SLinus Torvalds * Purpose : run through the various SCSI phases and do as the target 18031da177e4SLinus Torvalds * directs us to. Operates on the currently connected command, 18041da177e4SLinus Torvalds * instance->connected. 18051da177e4SLinus Torvalds * 18061da177e4SLinus Torvalds * Inputs : instance, instance for which we are doing commands 18071da177e4SLinus Torvalds * 18081da177e4SLinus Torvalds * Side effects : SCSI things happen, the disconnected queue will be 18091da177e4SLinus Torvalds * modified if a command disconnects, *instance->connected will 18101da177e4SLinus Torvalds * change. 18111da177e4SLinus Torvalds * 18121da177e4SLinus Torvalds * XXX Note : we need to watch for bus free or a reset condition here 18131da177e4SLinus Torvalds * to recover from an unexpected bus free condition. 18141da177e4SLinus Torvalds * 18151da177e4SLinus Torvalds * Locks: io_request_lock held by caller in IRQ mode 18161da177e4SLinus Torvalds */ 18171da177e4SLinus Torvalds 18181da177e4SLinus Torvalds static void NCR5380_information_transfer(struct Scsi_Host *instance) { 1819e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 18201da177e4SLinus Torvalds unsigned char msgout = NOP; 18211da177e4SLinus Torvalds int sink = 0; 18221da177e4SLinus Torvalds int len; 18231da177e4SLinus Torvalds #if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) 18241da177e4SLinus Torvalds int transfersize; 18251da177e4SLinus Torvalds #endif 18261da177e4SLinus Torvalds unsigned char *data; 18271da177e4SLinus Torvalds unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; 182811d2f63bSFinn Thain struct scsi_cmnd *cmd; 18291da177e4SLinus Torvalds 183011d2f63bSFinn Thain while ((cmd = hostdata->connected)) { 183132b26a10SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 183232b26a10SFinn Thain 18331da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 18341da177e4SLinus Torvalds /* We only have a valid SCSI phase when REQ is asserted */ 18351da177e4SLinus Torvalds if (tmp & SR_REQ) { 18361da177e4SLinus Torvalds phase = (tmp & PHASE_MASK); 18371da177e4SLinus Torvalds if (phase != old_phase) { 18381da177e4SLinus Torvalds old_phase = phase; 18391da177e4SLinus Torvalds NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); 18401da177e4SLinus Torvalds } 18411da177e4SLinus Torvalds if (sink && (phase != PHASE_MSGOUT)) { 18421da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 18431da177e4SLinus Torvalds 18441da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 18451da177e4SLinus Torvalds while (NCR5380_read(STATUS_REG) & SR_REQ); 18461da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 18471da177e4SLinus Torvalds sink = 0; 18481da177e4SLinus Torvalds continue; 18491da177e4SLinus Torvalds } 18501da177e4SLinus Torvalds switch (phase) { 18511da177e4SLinus Torvalds case PHASE_DATAOUT: 18521da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_DATAOUT) 18536a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n"); 18541da177e4SLinus Torvalds sink = 1; 18551da177e4SLinus Torvalds do_abort(instance); 18561da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 1857677e0194SFinn Thain complete_cmd(instance, cmd); 18581da177e4SLinus Torvalds return; 18591da177e4SLinus Torvalds #endif 1860bf1a0c6fSFinn Thain case PHASE_DATAIN: 18611da177e4SLinus Torvalds /* 18621da177e4SLinus Torvalds * If there is no room left in the current buffer in the 18631da177e4SLinus Torvalds * scatter-gather list, move onto the next one. 18641da177e4SLinus Torvalds */ 18651da177e4SLinus Torvalds 18661da177e4SLinus Torvalds if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { 18671da177e4SLinus Torvalds ++cmd->SCp.buffer; 18681da177e4SLinus Torvalds --cmd->SCp.buffers_residual; 18691da177e4SLinus Torvalds cmd->SCp.this_residual = cmd->SCp.buffer->length; 187045711f1aSJens Axboe cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 1871*b746545fSFinn Thain dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n", 1872*b746545fSFinn Thain cmd->SCp.this_residual, 1873*b746545fSFinn Thain 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 2028*b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n"); 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); 2034*b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n", 2035*b746545fSFinn Thain (int)extended_msg[1], 2036*b746545fSFinn Thain (int)extended_msg[2]); 20371da177e4SLinus Torvalds 2038e0783ed3SFinn Thain if (!len && extended_msg[1] > 0 && 2039e0783ed3SFinn Thain extended_msg[1] <= sizeof(extended_msg) - 2) { 20401da177e4SLinus Torvalds /* Accept third byte by clearing ACK */ 20411da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 20421da177e4SLinus Torvalds len = extended_msg[1] - 1; 20431da177e4SLinus Torvalds data = extended_msg + 3; 20441da177e4SLinus Torvalds phase = PHASE_MSGIN; 20451da177e4SLinus Torvalds 20461da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 2047*b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n", 2048*b746545fSFinn Thain len); 20491da177e4SLinus Torvalds 20501da177e4SLinus Torvalds switch (extended_msg[2]) { 20511da177e4SLinus Torvalds case EXTENDED_SDTR: 20521da177e4SLinus Torvalds case EXTENDED_WDTR: 20531da177e4SLinus Torvalds case EXTENDED_MODIFY_DATA_POINTER: 20541da177e4SLinus Torvalds case EXTENDED_EXTENDED_IDENTIFY: 20551da177e4SLinus Torvalds tmp = 0; 20561da177e4SLinus Torvalds } 20571da177e4SLinus Torvalds } else if (len) { 20586a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "error receiving extended message\n"); 20591da177e4SLinus Torvalds tmp = 0; 20601da177e4SLinus Torvalds } else { 20616a6ff4acSFinn Thain shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n", 20626a6ff4acSFinn Thain extended_msg[2], extended_msg[1]); 20631da177e4SLinus Torvalds tmp = 0; 20641da177e4SLinus Torvalds } 206511d2f63bSFinn Thain 206611d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 206711d2f63bSFinn Thain if (!hostdata->connected) 206811d2f63bSFinn Thain return; 206911d2f63bSFinn Thain 20701da177e4SLinus Torvalds /* Fall through to reject message */ 20711da177e4SLinus Torvalds 20721da177e4SLinus Torvalds /* 20731da177e4SLinus Torvalds * If we get something weird that we aren't expecting, 20741da177e4SLinus Torvalds * reject it. 20751da177e4SLinus Torvalds */ 20761da177e4SLinus Torvalds default: 20771da177e4SLinus Torvalds if (!tmp) { 20786a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "rejecting message "); 20791abfd370SMatthew Wilcox spi_print_msg(extended_msg); 20801da177e4SLinus Torvalds printk("\n"); 20811da177e4SLinus Torvalds } else if (tmp != EXTENDED_MESSAGE) 2082017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 2083017560fcSJeff Garzik "rejecting unknown message %02x\n",tmp); 20841da177e4SLinus Torvalds else 2085017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 2086017560fcSJeff Garzik "rejecting unknown extended message code %02x, length %d\n", extended_msg[1], extended_msg[0]); 20871da177e4SLinus Torvalds 20881da177e4SLinus Torvalds msgout = MESSAGE_REJECT; 20891da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 20901da177e4SLinus Torvalds break; 20911da177e4SLinus Torvalds } /* switch (tmp) */ 20921da177e4SLinus Torvalds break; 20931da177e4SLinus Torvalds case PHASE_MSGOUT: 20941da177e4SLinus Torvalds len = 1; 20951da177e4SLinus Torvalds data = &msgout; 20961da177e4SLinus Torvalds hostdata->last_message = msgout; 20971da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 20981da177e4SLinus Torvalds if (msgout == ABORT) { 20991da177e4SLinus Torvalds hostdata->connected = NULL; 21001da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 2101677e0194SFinn Thain complete_cmd(instance, cmd); 21021da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 21031da177e4SLinus Torvalds return; 21041da177e4SLinus Torvalds } 21051da177e4SLinus Torvalds msgout = NOP; 21061da177e4SLinus Torvalds break; 21071da177e4SLinus Torvalds case PHASE_CMDOUT: 21081da177e4SLinus Torvalds len = cmd->cmd_len; 21091da177e4SLinus Torvalds data = cmd->cmnd; 21101da177e4SLinus Torvalds /* 21111da177e4SLinus Torvalds * XXX for performance reasons, on machines with a 21121da177e4SLinus Torvalds * PSEUDO-DMA architecture we should probably 21131da177e4SLinus Torvalds * use the dma transfer function. 21141da177e4SLinus Torvalds */ 21151da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 21161da177e4SLinus Torvalds break; 21171da177e4SLinus Torvalds case PHASE_STATIN: 21181da177e4SLinus Torvalds len = 1; 21191da177e4SLinus Torvalds data = &tmp; 21201da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 21211da177e4SLinus Torvalds cmd->SCp.Status = tmp; 21221da177e4SLinus Torvalds break; 21231da177e4SLinus Torvalds default: 21246a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "unknown phase\n"); 21254dde8f7dSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 21261da177e4SLinus Torvalds } /* switch(phase) */ 2127686f3990SFinn Thain } else { 212811d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 2129686f3990SFinn Thain NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ); 213011d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 21311da177e4SLinus Torvalds } 213211d2f63bSFinn Thain } 21331da177e4SLinus Torvalds } 21341da177e4SLinus Torvalds 21351da177e4SLinus Torvalds /* 21361da177e4SLinus Torvalds * Function : void NCR5380_reselect (struct Scsi_Host *instance) 21371da177e4SLinus Torvalds * 21381da177e4SLinus Torvalds * Purpose : does reselection, initializing the instance->connected 2139710ddd0dSFinn Thain * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q 21401da177e4SLinus Torvalds * nexus has been reestablished, 21411da177e4SLinus Torvalds * 21421da177e4SLinus Torvalds * Inputs : instance - this instance of the NCR5380. 21431da177e4SLinus Torvalds * 21441da177e4SLinus Torvalds * Locks: io_request_lock held by caller if IRQ driven 21451da177e4SLinus Torvalds */ 21461da177e4SLinus Torvalds 21471da177e4SLinus Torvalds static void NCR5380_reselect(struct Scsi_Host *instance) { 2148e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 21491da177e4SLinus Torvalds unsigned char target_mask; 21501da177e4SLinus Torvalds unsigned char lun, phase; 21511da177e4SLinus Torvalds int len; 21521da177e4SLinus Torvalds unsigned char msg[3]; 21531da177e4SLinus Torvalds unsigned char *data; 215432b26a10SFinn Thain struct NCR5380_cmd *ncmd; 215532b26a10SFinn Thain struct scsi_cmnd *tmp; 21561da177e4SLinus Torvalds 21571da177e4SLinus Torvalds /* 21581da177e4SLinus Torvalds * Disable arbitration, etc. since the host adapter obviously 21591da177e4SLinus Torvalds * lost, and tell an interrupted NCR5380_select() to restart. 21601da177e4SLinus Torvalds */ 21611da177e4SLinus Torvalds 21621da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 21631da177e4SLinus Torvalds 21641da177e4SLinus Torvalds target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); 2165*b746545fSFinn Thain 2166*b746545fSFinn Thain dsprintk(NDEBUG_RESELECTION, instance, "reselect\n"); 21671da177e4SLinus Torvalds 21681da177e4SLinus Torvalds /* 21691da177e4SLinus Torvalds * At this point, we have detected that our SCSI ID is on the bus, 21701da177e4SLinus Torvalds * SEL is true and BSY was false for at least one bus settle delay 21711da177e4SLinus Torvalds * (400 ns). 21721da177e4SLinus Torvalds * 21731da177e4SLinus Torvalds * We must assert BSY ourselves, until the target drops the SEL 21741da177e4SLinus Torvalds * signal. 21751da177e4SLinus Torvalds */ 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); 217872064a78SFinn Thain if (NCR5380_poll_politely(instance, 217972064a78SFinn Thain STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) { 218072064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 218172064a78SFinn Thain return; 218272064a78SFinn Thain } 21831da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 21841da177e4SLinus Torvalds 21851da177e4SLinus Torvalds /* 21861da177e4SLinus Torvalds * Wait for target to go into MSGIN. 21871da177e4SLinus Torvalds */ 21881da177e4SLinus Torvalds 21891cc160e1SFinn Thain if (NCR5380_poll_politely(instance, 219072064a78SFinn Thain STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) { 219172064a78SFinn Thain do_abort(instance); 219272064a78SFinn Thain return; 219372064a78SFinn Thain } 21941da177e4SLinus Torvalds 21951da177e4SLinus Torvalds len = 1; 21961da177e4SLinus Torvalds data = msg; 21971da177e4SLinus Torvalds phase = PHASE_MSGIN; 21981da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 21991da177e4SLinus Torvalds 220072064a78SFinn Thain if (len) { 220172064a78SFinn Thain do_abort(instance); 220272064a78SFinn Thain return; 220372064a78SFinn Thain } 220472064a78SFinn Thain 22051da177e4SLinus Torvalds if (!(msg[0] & 0x80)) { 220672064a78SFinn Thain shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got "); 22071abfd370SMatthew Wilcox spi_print_msg(msg); 220872064a78SFinn Thain printk("\n"); 220972064a78SFinn Thain do_abort(instance); 221072064a78SFinn Thain return; 221172064a78SFinn Thain } 221272064a78SFinn Thain lun = msg[0] & 0x07; 22131da177e4SLinus Torvalds 22141da177e4SLinus Torvalds /* 22151da177e4SLinus Torvalds * We need to add code for SCSI-II to track which devices have 22161da177e4SLinus Torvalds * I_T_L_Q nexuses established, and which have simple I_T_L 22171da177e4SLinus Torvalds * nexuses so we can chose to do additional data transfer. 22181da177e4SLinus Torvalds */ 22191da177e4SLinus Torvalds 22201da177e4SLinus Torvalds /* 22211da177e4SLinus Torvalds * Find the command corresponding to the I_T_L or I_T_L_Q nexus we 22221da177e4SLinus Torvalds * just reestablished, and remove it from the disconnected queue. 22231da177e4SLinus Torvalds */ 22241da177e4SLinus Torvalds 222532b26a10SFinn Thain tmp = NULL; 222632b26a10SFinn Thain list_for_each_entry(ncmd, &hostdata->disconnected, list) { 222732b26a10SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 222832b26a10SFinn Thain 222932b26a10SFinn Thain if (target_mask == (1 << scmd_id(cmd)) && 223032b26a10SFinn Thain lun == (u8)cmd->device->lun) { 223132b26a10SFinn Thain list_del(&ncmd->list); 223232b26a10SFinn Thain tmp = cmd; 22331da177e4SLinus Torvalds break; 22341da177e4SLinus Torvalds } 223572064a78SFinn Thain } 22360d3d9a42SFinn Thain 22370d3d9a42SFinn Thain if (tmp) { 22380d3d9a42SFinn Thain dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance, 22390d3d9a42SFinn Thain "reselect: removed %p from disconnected queue\n", tmp); 22400d3d9a42SFinn Thain } else { 224172064a78SFinn Thain shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n", 224272064a78SFinn Thain target_mask, lun); 22431da177e4SLinus Torvalds /* 22441da177e4SLinus Torvalds * Since we have an established nexus that we can't do anything with, 22451da177e4SLinus Torvalds * we must abort it. 22461da177e4SLinus Torvalds */ 224772064a78SFinn Thain do_abort(instance); 224872064a78SFinn Thain return; 22491da177e4SLinus Torvalds } 22501da177e4SLinus Torvalds 225172064a78SFinn Thain /* Accept message by clearing ACK */ 225272064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 225372064a78SFinn Thain 22541da177e4SLinus Torvalds hostdata->connected = tmp; 2255*b746545fSFinn Thain dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu, tag %d\n", 2256*b746545fSFinn Thain scmd_id(tmp), tmp->device->lun, tmp->tag); 22571da177e4SLinus Torvalds } 22581da177e4SLinus Torvalds 22591da177e4SLinus Torvalds /* 22601da177e4SLinus Torvalds * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) 22611da177e4SLinus Torvalds * 22621da177e4SLinus Torvalds * Purpose : called by interrupt handler when DMA finishes or a phase 22631da177e4SLinus Torvalds * mismatch occurs (which would finish the DMA transfer). 22641da177e4SLinus Torvalds * 22651da177e4SLinus Torvalds * Inputs : instance - this instance of the NCR5380. 22661da177e4SLinus Torvalds * 2267710ddd0dSFinn Thain * Returns : pointer to the scsi_cmnd structure for which the I_T_L 22681da177e4SLinus Torvalds * nexus has been reestablished, on failure NULL is returned. 22691da177e4SLinus Torvalds */ 22701da177e4SLinus Torvalds 22711da177e4SLinus Torvalds #ifdef REAL_DMA 22721da177e4SLinus Torvalds static void NCR5380_dma_complete(NCR5380_instance * instance) { 2273e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 22741da177e4SLinus Torvalds int transferred; 22751da177e4SLinus Torvalds 22761da177e4SLinus Torvalds /* 22771da177e4SLinus Torvalds * XXX this might not be right. 22781da177e4SLinus Torvalds * 22791da177e4SLinus Torvalds * Wait for final byte to transfer, ie wait for ACK to go false. 22801da177e4SLinus Torvalds * 22811da177e4SLinus Torvalds * We should use the Last Byte Sent bit, unfortunately this is 22821da177e4SLinus Torvalds * not available on the 5380/5381 (only the various CMOS chips) 22831da177e4SLinus Torvalds * 22841da177e4SLinus Torvalds * FIXME: timeout, and need to handle long timeout/irq case 22851da177e4SLinus Torvalds */ 22861da177e4SLinus Torvalds 22871da177e4SLinus Torvalds NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, BASR_ACK, 0, 5*HZ); 22881da177e4SLinus Torvalds 22891da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 22901da177e4SLinus Torvalds 22911da177e4SLinus Torvalds /* 22921da177e4SLinus Torvalds * The only places we should see a phase mismatch and have to send 22931da177e4SLinus Torvalds * data from the same set of pointers will be the data transfer 22941da177e4SLinus Torvalds * phases. So, residual, requested length are only important here. 22951da177e4SLinus Torvalds */ 22961da177e4SLinus Torvalds 22971da177e4SLinus Torvalds if (!(hostdata->connected->SCp.phase & SR_CD)) { 22981da177e4SLinus Torvalds transferred = instance->dmalen - NCR5380_dma_residual(); 22991da177e4SLinus Torvalds hostdata->connected->SCp.this_residual -= transferred; 23001da177e4SLinus Torvalds hostdata->connected->SCp.ptr += transferred; 23011da177e4SLinus Torvalds } 23021da177e4SLinus Torvalds } 23031da177e4SLinus Torvalds #endif /* def REAL_DMA */ 23041da177e4SLinus Torvalds 23058b00c3d5SFinn Thain /** 23068b00c3d5SFinn Thain * list_find_cmd - test for presence of a command in a linked list 23078b00c3d5SFinn Thain * @haystack: list of commands 23088b00c3d5SFinn Thain * @needle: command to search for 23098b00c3d5SFinn Thain */ 23108b00c3d5SFinn Thain 23118b00c3d5SFinn Thain static bool list_find_cmd(struct list_head *haystack, 23128b00c3d5SFinn Thain struct scsi_cmnd *needle) 23138b00c3d5SFinn Thain { 23148b00c3d5SFinn Thain struct NCR5380_cmd *ncmd; 23158b00c3d5SFinn Thain 23168b00c3d5SFinn Thain list_for_each_entry(ncmd, haystack, list) 23178b00c3d5SFinn Thain if (NCR5380_to_scmd(ncmd) == needle) 23188b00c3d5SFinn Thain return true; 23198b00c3d5SFinn Thain return false; 23208b00c3d5SFinn Thain } 23218b00c3d5SFinn Thain 23228b00c3d5SFinn Thain /** 23238b00c3d5SFinn Thain * list_remove_cmd - remove a command from linked list 23248b00c3d5SFinn Thain * @haystack: list of commands 23258b00c3d5SFinn Thain * @needle: command to remove 23268b00c3d5SFinn Thain */ 23278b00c3d5SFinn Thain 23288b00c3d5SFinn Thain static bool list_del_cmd(struct list_head *haystack, 23298b00c3d5SFinn Thain struct scsi_cmnd *needle) 23308b00c3d5SFinn Thain { 23318b00c3d5SFinn Thain if (list_find_cmd(haystack, needle)) { 23328b00c3d5SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle); 23338b00c3d5SFinn Thain 23348b00c3d5SFinn Thain list_del(&ncmd->list); 23358b00c3d5SFinn Thain return true; 23368b00c3d5SFinn Thain } 23378b00c3d5SFinn Thain return false; 23388b00c3d5SFinn Thain } 23398b00c3d5SFinn Thain 23408b00c3d5SFinn Thain /** 23418b00c3d5SFinn Thain * NCR5380_abort - scsi host eh_abort_handler() method 23428b00c3d5SFinn Thain * @cmd: the command to be aborted 23431da177e4SLinus Torvalds * 23448b00c3d5SFinn Thain * Try to abort a given command by removing it from queues and/or sending 23458b00c3d5SFinn Thain * the target an abort message. This may not succeed in causing a target 23468b00c3d5SFinn Thain * to abort the command. Nonetheless, the low-level driver must forget about 23478b00c3d5SFinn Thain * the command because the mid-layer reclaims it and it may be re-issued. 23481da177e4SLinus Torvalds * 23498b00c3d5SFinn Thain * The normal path taken by a command is as follows. For EH we trace this 23508b00c3d5SFinn Thain * same path to locate and abort the command. 23511da177e4SLinus Torvalds * 23528b00c3d5SFinn Thain * unissued -> selecting -> [unissued -> selecting ->]... connected -> 23538b00c3d5SFinn Thain * [disconnected -> connected ->]... 23548b00c3d5SFinn Thain * [autosense -> connected ->] done 23551da177e4SLinus Torvalds * 23568b00c3d5SFinn Thain * If cmd is unissued then just remove it. 23578b00c3d5SFinn Thain * If cmd is disconnected, try to select the target. 23588b00c3d5SFinn Thain * If cmd is connected, try to send an abort message. 23598b00c3d5SFinn Thain * If cmd is waiting for autosense, give it a chance to complete but check 23608b00c3d5SFinn Thain * that it isn't left connected. 23618b00c3d5SFinn Thain * If cmd was not found at all then presumably it has already been completed, 23628b00c3d5SFinn Thain * in which case return SUCCESS to try to avoid further EH measures. 23638b00c3d5SFinn Thain * If the command has not completed yet, we must not fail to find it. 23641da177e4SLinus Torvalds */ 23651da177e4SLinus Torvalds 2366710ddd0dSFinn Thain static int NCR5380_abort(struct scsi_cmnd *cmd) 2367710ddd0dSFinn Thain { 23681da177e4SLinus Torvalds struct Scsi_Host *instance = cmd->device->host; 2369e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 237011d2f63bSFinn Thain unsigned long flags; 23718b00c3d5SFinn Thain int result = SUCCESS; 23721da177e4SLinus Torvalds 237311d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 237411d2f63bSFinn Thain 237532b26a10SFinn Thain #if (NDEBUG & NDEBUG_ANY) 23768b00c3d5SFinn Thain scmd_printk(KERN_INFO, cmd, __func__); 237732b26a10SFinn Thain #endif 2378e5c3fddfSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 2379e5c3fddfSFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 23801da177e4SLinus Torvalds 23818b00c3d5SFinn Thain if (list_del_cmd(&hostdata->unissued, cmd)) { 23828b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 23838b00c3d5SFinn Thain "abort: removed %p from issue queue\n", cmd); 23848b00c3d5SFinn Thain cmd->result = DID_ABORT << 16; 23858b00c3d5SFinn Thain cmd->scsi_done(cmd); /* No tag or busy flag to worry about */ 23868b00c3d5SFinn Thain } 23878b00c3d5SFinn Thain 2388707d62b3SFinn Thain if (hostdata->selecting == cmd) { 2389707d62b3SFinn Thain dsprintk(NDEBUG_ABORT, instance, 2390707d62b3SFinn Thain "abort: cmd %p == selecting\n", cmd); 2391707d62b3SFinn Thain hostdata->selecting = NULL; 2392707d62b3SFinn Thain cmd->result = DID_ABORT << 16; 2393707d62b3SFinn Thain complete_cmd(instance, cmd); 2394707d62b3SFinn Thain goto out; 2395707d62b3SFinn Thain } 2396707d62b3SFinn Thain 23978b00c3d5SFinn Thain if (list_del_cmd(&hostdata->disconnected, cmd)) { 23988b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 23998b00c3d5SFinn Thain "abort: removed %p from disconnected list\n", cmd); 24008b00c3d5SFinn Thain cmd->result = DID_ERROR << 16; 24018b00c3d5SFinn Thain if (!hostdata->connected) 24028b00c3d5SFinn Thain NCR5380_select(instance, cmd); 24038b00c3d5SFinn Thain if (hostdata->connected != cmd) { 24048b00c3d5SFinn Thain complete_cmd(instance, cmd); 24058b00c3d5SFinn Thain result = FAILED; 24068b00c3d5SFinn Thain goto out; 24078b00c3d5SFinn Thain } 24088b00c3d5SFinn Thain } 24098b00c3d5SFinn Thain 24108b00c3d5SFinn Thain if (hostdata->connected == cmd) { 24118b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); 24128b00c3d5SFinn Thain hostdata->connected = NULL; 24138b00c3d5SFinn Thain if (do_abort(instance)) { 24148b00c3d5SFinn Thain set_host_byte(cmd, DID_ERROR); 24158b00c3d5SFinn Thain complete_cmd(instance, cmd); 24168b00c3d5SFinn Thain result = FAILED; 24178b00c3d5SFinn Thain goto out; 24188b00c3d5SFinn Thain } 24198b00c3d5SFinn Thain set_host_byte(cmd, DID_ABORT); 24208b00c3d5SFinn Thain #ifdef REAL_DMA 24218b00c3d5SFinn Thain hostdata->dma_len = 0; 24228b00c3d5SFinn Thain #endif 24238b00c3d5SFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 24248b00c3d5SFinn Thain complete_cmd(instance, cmd); 24258b00c3d5SFinn Thain else { 24268b00c3d5SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 24278b00c3d5SFinn Thain 24288b00c3d5SFinn Thain /* Perform autosense for this command */ 24298b00c3d5SFinn Thain list_add(&ncmd->list, &hostdata->autosense); 24308b00c3d5SFinn Thain } 24318b00c3d5SFinn Thain } 24328b00c3d5SFinn Thain 24338b00c3d5SFinn Thain if (list_find_cmd(&hostdata->autosense, cmd)) { 24348b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 24358b00c3d5SFinn Thain "abort: found %p on sense queue\n", cmd); 24368b00c3d5SFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 24378b00c3d5SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 24388b00c3d5SFinn Thain msleep(1000); 24398b00c3d5SFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 24408b00c3d5SFinn Thain if (list_del_cmd(&hostdata->autosense, cmd)) { 24418b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 24428b00c3d5SFinn Thain "abort: removed %p from sense queue\n", cmd); 24438b00c3d5SFinn Thain set_host_byte(cmd, DID_ABORT); 24448b00c3d5SFinn Thain complete_cmd(instance, cmd); 24458b00c3d5SFinn Thain goto out; 24468b00c3d5SFinn Thain } 24478b00c3d5SFinn Thain } 24488b00c3d5SFinn Thain 24498b00c3d5SFinn Thain if (hostdata->connected == cmd) { 24508b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); 24518b00c3d5SFinn Thain hostdata->connected = NULL; 24528b00c3d5SFinn Thain if (do_abort(instance)) { 24538b00c3d5SFinn Thain set_host_byte(cmd, DID_ERROR); 24548b00c3d5SFinn Thain complete_cmd(instance, cmd); 24558b00c3d5SFinn Thain result = FAILED; 24568b00c3d5SFinn Thain goto out; 24578b00c3d5SFinn Thain } 24588b00c3d5SFinn Thain set_host_byte(cmd, DID_ABORT); 24598b00c3d5SFinn Thain #ifdef REAL_DMA 24608b00c3d5SFinn Thain hostdata->dma_len = 0; 24618b00c3d5SFinn Thain #endif 24628b00c3d5SFinn Thain complete_cmd(instance, cmd); 24638b00c3d5SFinn Thain } 24648b00c3d5SFinn Thain 24658b00c3d5SFinn Thain out: 24668b00c3d5SFinn Thain if (result == FAILED) 24678b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd); 24688b00c3d5SFinn Thain else 24698b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd); 24708b00c3d5SFinn Thain 24718b00c3d5SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 247211d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 24731da177e4SLinus Torvalds 24748b00c3d5SFinn Thain return result; 24751da177e4SLinus Torvalds } 24761da177e4SLinus Torvalds 24771da177e4SLinus Torvalds 24783be1b3eaSFinn Thain /** 24793be1b3eaSFinn Thain * NCR5380_bus_reset - reset the SCSI bus 24803be1b3eaSFinn Thain * @cmd: SCSI command undergoing EH 24811da177e4SLinus Torvalds * 24823be1b3eaSFinn Thain * Returns SUCCESS 24831da177e4SLinus Torvalds */ 24841da177e4SLinus Torvalds 2485710ddd0dSFinn Thain static int NCR5380_bus_reset(struct scsi_cmnd *cmd) 248668b3aa7cSJeff Garzik { 248768b3aa7cSJeff Garzik struct Scsi_Host *instance = cmd->device->host; 248811d2f63bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 248962717f53SFinn Thain int i; 249011d2f63bSFinn Thain unsigned long flags; 249162717f53SFinn Thain struct NCR5380_cmd *ncmd; 24921da177e4SLinus Torvalds 249311d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 24943be1b3eaSFinn Thain 24953be1b3eaSFinn Thain #if (NDEBUG & NDEBUG_ANY) 249662717f53SFinn Thain scmd_printk(KERN_INFO, cmd, __func__); 24973be1b3eaSFinn Thain #endif 2498e5c3fddfSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 2499e5c3fddfSFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 25003be1b3eaSFinn Thain 250168b3aa7cSJeff Garzik do_reset(instance); 25023be1b3eaSFinn Thain 250362717f53SFinn Thain /* reset NCR registers */ 250462717f53SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 250562717f53SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 0); 250662717f53SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 250762717f53SFinn Thain 250862717f53SFinn Thain /* After the reset, there are no more connected or disconnected commands 250962717f53SFinn Thain * and no busy units; so clear the low-level status here to avoid 251062717f53SFinn Thain * conflicts when the mid-level code tries to wake up the affected 251162717f53SFinn Thain * commands! 251262717f53SFinn Thain */ 251362717f53SFinn Thain 251462717f53SFinn Thain hostdata->selecting = NULL; 251562717f53SFinn Thain 251662717f53SFinn Thain list_for_each_entry(ncmd, &hostdata->disconnected, list) { 251762717f53SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 251862717f53SFinn Thain 251962717f53SFinn Thain set_host_byte(cmd, DID_RESET); 252062717f53SFinn Thain cmd->scsi_done(cmd); 252162717f53SFinn Thain } 252262717f53SFinn Thain 252362717f53SFinn Thain list_for_each_entry(ncmd, &hostdata->autosense, list) { 252462717f53SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 252562717f53SFinn Thain 252662717f53SFinn Thain set_host_byte(cmd, DID_RESET); 252762717f53SFinn Thain cmd->scsi_done(cmd); 252862717f53SFinn Thain } 252962717f53SFinn Thain 253062717f53SFinn Thain if (hostdata->connected) { 253162717f53SFinn Thain set_host_byte(hostdata->connected, DID_RESET); 253262717f53SFinn Thain complete_cmd(instance, hostdata->connected); 253362717f53SFinn Thain hostdata->connected = NULL; 253462717f53SFinn Thain } 253562717f53SFinn Thain 253662717f53SFinn Thain if (hostdata->sensing) { 253762717f53SFinn Thain set_host_byte(hostdata->connected, DID_RESET); 253862717f53SFinn Thain complete_cmd(instance, hostdata->sensing); 253962717f53SFinn Thain hostdata->sensing = NULL; 254062717f53SFinn Thain } 254162717f53SFinn Thain 254262717f53SFinn Thain for (i = 0; i < 8; ++i) 254362717f53SFinn Thain hostdata->busy[i] = 0; 254462717f53SFinn Thain #ifdef REAL_DMA 254562717f53SFinn Thain hostdata->dma_len = 0; 254662717f53SFinn Thain #endif 254762717f53SFinn Thain 254862717f53SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 254911d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 255068b3aa7cSJeff Garzik 25511da177e4SLinus Torvalds return SUCCESS; 25521da177e4SLinus Torvalds } 2553