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 /* 28c16df32eSFinn Thain * With contributions from Ray Van Tassle, Ingmar Baumgart, 29c16df32eSFinn Thain * Ronald van Cuijlenborg, Alan Cox and others. 301da177e4SLinus Torvalds */ 311da177e4SLinus Torvalds 3252d3e561SFinn Thain /* Ported to Atari by Roman Hodek and others. */ 3352d3e561SFinn Thain 34e9db3198SFinn Thain /* Adapted for the Sun 3 by Sam Creasey. */ 35e9db3198SFinn Thain 361da177e4SLinus Torvalds /* 371da177e4SLinus Torvalds * Design 381da177e4SLinus Torvalds * 391da177e4SLinus Torvalds * This is a generic 5380 driver. To use it on a different platform, 401da177e4SLinus Torvalds * one simply writes appropriate system specific macros (ie, data 411da177e4SLinus Torvalds * transfer - some PC's will use the I/O bus, 68K's must use 421da177e4SLinus Torvalds * memory mapped) and drops this file in their 'C' wrapper. 431da177e4SLinus Torvalds * 441da177e4SLinus Torvalds * As far as command queueing, two queues are maintained for 451da177e4SLinus Torvalds * each 5380 in the system - commands that haven't been issued yet, 461da177e4SLinus Torvalds * and commands that are currently executing. This means that an 471da177e4SLinus Torvalds * unlimited number of commands may be queued, letting 481da177e4SLinus Torvalds * more commands propagate from the higher driver levels giving higher 491da177e4SLinus Torvalds * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, 501da177e4SLinus Torvalds * allowing multiple commands to propagate all the way to a SCSI-II device 511da177e4SLinus Torvalds * while a command is already executing. 521da177e4SLinus Torvalds * 531da177e4SLinus Torvalds * 541da177e4SLinus Torvalds * Issues specific to the NCR5380 : 551da177e4SLinus Torvalds * 561da177e4SLinus Torvalds * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 571da177e4SLinus Torvalds * piece of hardware that requires you to sit in a loop polling for 581da177e4SLinus Torvalds * the REQ signal as long as you are connected. Some devices are 591da177e4SLinus Torvalds * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 60686f3990SFinn Thain * while doing long seek operations. [...] These 611da177e4SLinus Torvalds * broken devices are the exception rather than the rule and I'd rather 621da177e4SLinus Torvalds * spend my time optimizing for the normal case. 631da177e4SLinus Torvalds * 641da177e4SLinus Torvalds * Architecture : 651da177e4SLinus Torvalds * 661da177e4SLinus Torvalds * At the heart of the design is a coroutine, NCR5380_main, 671da177e4SLinus Torvalds * which is started from a workqueue for each NCR5380 host in the 681da177e4SLinus Torvalds * system. It attempts to establish I_T_L or I_T_L_Q nexuses by 691da177e4SLinus Torvalds * removing the commands from the issue queue and calling 701da177e4SLinus Torvalds * NCR5380_select() if a nexus is not established. 711da177e4SLinus Torvalds * 721da177e4SLinus Torvalds * Once a nexus is established, the NCR5380_information_transfer() 731da177e4SLinus Torvalds * phase goes through the various phases as instructed by the target. 741da177e4SLinus Torvalds * if the target goes into MSG IN and sends a DISCONNECT message, 751da177e4SLinus Torvalds * the command structure is placed into the per instance disconnected 761da177e4SLinus Torvalds * queue, and NCR5380_main tries to find more work. If the target is 771da177e4SLinus Torvalds * idle for too long, the system will try to sleep. 781da177e4SLinus Torvalds * 791da177e4SLinus Torvalds * If a command has disconnected, eventually an interrupt will trigger, 801da177e4SLinus Torvalds * calling NCR5380_intr() which will in turn call NCR5380_reselect 811da177e4SLinus Torvalds * to reestablish a nexus. This will run main if necessary. 821da177e4SLinus Torvalds * 831da177e4SLinus Torvalds * On command termination, the done function will be called as 841da177e4SLinus Torvalds * appropriate. 851da177e4SLinus Torvalds * 861da177e4SLinus Torvalds * SCSI pointers are maintained in the SCp field of SCSI command 871da177e4SLinus Torvalds * structures, being initialized after the command is connected 881da177e4SLinus Torvalds * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. 891da177e4SLinus Torvalds * Note that in violation of the standard, an implicit SAVE POINTERS operation 901da177e4SLinus Torvalds * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS. 911da177e4SLinus Torvalds */ 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds /* 941da177e4SLinus Torvalds * Using this file : 951da177e4SLinus Torvalds * This file a skeleton Linux SCSI driver for the NCR 5380 series 961da177e4SLinus Torvalds * of chips. To use it, you write an architecture specific functions 971da177e4SLinus Torvalds * and macros and include this file in your driver. 981da177e4SLinus Torvalds * 991da177e4SLinus Torvalds * These macros control options : 1001da177e4SLinus Torvalds * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be 1011da177e4SLinus Torvalds * defined. 1021da177e4SLinus Torvalds * 1031da177e4SLinus Torvalds * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically 1041da177e4SLinus Torvalds * for commands that return with a CHECK CONDITION status. 1051da177e4SLinus Torvalds * 1061da177e4SLinus Torvalds * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential 1071da177e4SLinus Torvalds * transceivers. 1081da177e4SLinus Torvalds * 1091da177e4SLinus Torvalds * DONT_USE_INTR - if defined, never use interrupts, even if we probe or 1101da177e4SLinus Torvalds * override-configure an IRQ. 1111da177e4SLinus Torvalds * 1121da177e4SLinus Torvalds * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases. 1131da177e4SLinus Torvalds * 1148053b0eeSFinn Thain * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. 1158053b0eeSFinn Thain * 1161da177e4SLinus Torvalds * These macros MUST be defined : 1171da177e4SLinus Torvalds * 1181da177e4SLinus Torvalds * NCR5380_read(register) - read from the specified register 1191da177e4SLinus Torvalds * 1201da177e4SLinus Torvalds * NCR5380_write(register, value) - write to the specific register 1211da177e4SLinus Torvalds * 1221da177e4SLinus Torvalds * NCR5380_implementation_fields - additional fields needed for this 1231da177e4SLinus Torvalds * specific implementation of the NCR5380 1241da177e4SLinus Torvalds * 1251da177e4SLinus Torvalds * Either real DMA *or* pseudo DMA may be implemented 1261da177e4SLinus Torvalds * 1271da177e4SLinus Torvalds * NCR5380_dma_write_setup(instance, src, count) - initialize 1281da177e4SLinus Torvalds * NCR5380_dma_read_setup(instance, dst, count) - initialize 1291da177e4SLinus Torvalds * NCR5380_dma_residual(instance); - residual count 1301da177e4SLinus Torvalds * 1311da177e4SLinus Torvalds * The generic driver is initialized by calling NCR5380_init(instance), 1321da177e4SLinus Torvalds * after setting the appropriate host specific fields and ID. If the 1331da177e4SLinus Torvalds * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, 1341da177e4SLinus Torvalds * possible) function may be used. 1351da177e4SLinus Torvalds */ 1361da177e4SLinus Torvalds 137e5d55d1aSFinn Thain #ifndef NCR5380_io_delay 138e5d55d1aSFinn Thain #define NCR5380_io_delay(x) 139e5d55d1aSFinn Thain #endif 140e5d55d1aSFinn Thain 14152d3e561SFinn Thain #ifndef NCR5380_acquire_dma_irq 14252d3e561SFinn Thain #define NCR5380_acquire_dma_irq(x) (1) 14352d3e561SFinn Thain #endif 14452d3e561SFinn Thain 14552d3e561SFinn Thain #ifndef NCR5380_release_dma_irq 14652d3e561SFinn Thain #define NCR5380_release_dma_irq(x) 14752d3e561SFinn Thain #endif 14852d3e561SFinn Thain 14954d8fe44SFinn Thain static int do_abort(struct Scsi_Host *); 15054d8fe44SFinn Thain static void do_reset(struct Scsi_Host *); 1511da177e4SLinus Torvalds 152c16df32eSFinn Thain /** 1531da177e4SLinus Torvalds * initialize_SCp - init the scsi pointer field 1541da177e4SLinus Torvalds * @cmd: command block to set up 1551da177e4SLinus Torvalds * 1561da177e4SLinus Torvalds * Set up the internal fields in the SCSI command. 1571da177e4SLinus Torvalds */ 1581da177e4SLinus Torvalds 159710ddd0dSFinn Thain static inline void initialize_SCp(struct scsi_cmnd *cmd) 1601da177e4SLinus Torvalds { 1611da177e4SLinus Torvalds /* 1621da177e4SLinus Torvalds * Initialize the Scsi Pointer field so that all of the commands in the 1631da177e4SLinus Torvalds * various queues are valid. 1641da177e4SLinus Torvalds */ 1651da177e4SLinus Torvalds 1669e0fe44dSBoaz Harrosh if (scsi_bufflen(cmd)) { 1679e0fe44dSBoaz Harrosh cmd->SCp.buffer = scsi_sglist(cmd); 1689e0fe44dSBoaz Harrosh cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; 16945711f1aSJens Axboe cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 1701da177e4SLinus Torvalds cmd->SCp.this_residual = cmd->SCp.buffer->length; 1711da177e4SLinus Torvalds } else { 1721da177e4SLinus Torvalds cmd->SCp.buffer = NULL; 1731da177e4SLinus Torvalds cmd->SCp.buffers_residual = 0; 1749e0fe44dSBoaz Harrosh cmd->SCp.ptr = NULL; 1759e0fe44dSBoaz Harrosh cmd->SCp.this_residual = 0; 1761da177e4SLinus Torvalds } 177f27db8ebSFinn Thain 178f27db8ebSFinn Thain cmd->SCp.Status = 0; 179f27db8ebSFinn Thain cmd->SCp.Message = 0; 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds /** 183b32ade12SFinn Thain * NCR5380_poll_politely2 - wait for two chip register values 1841da177e4SLinus Torvalds * @instance: controller to poll 185b32ade12SFinn Thain * @reg1: 5380 register to poll 186b32ade12SFinn Thain * @bit1: Bitmask to check 187b32ade12SFinn Thain * @val1: Expected value 188b32ade12SFinn Thain * @reg2: Second 5380 register to poll 189b32ade12SFinn Thain * @bit2: Second bitmask to check 190b32ade12SFinn Thain * @val2: Second expected value 1912f854b82SFinn Thain * @wait: Time-out in jiffies 1921da177e4SLinus Torvalds * 1932f854b82SFinn Thain * Polls the chip in a reasonably efficient manner waiting for an 1942f854b82SFinn Thain * event to occur. After a short quick poll we begin to yield the CPU 1952f854b82SFinn Thain * (if possible). In irq contexts the time-out is arbitrarily limited. 1962f854b82SFinn Thain * Callers may hold locks as long as they are held in irq mode. 1971da177e4SLinus Torvalds * 198b32ade12SFinn Thain * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT. 1991da177e4SLinus Torvalds */ 2001da177e4SLinus Torvalds 201b32ade12SFinn Thain static int NCR5380_poll_politely2(struct Scsi_Host *instance, 202b32ade12SFinn Thain int reg1, int bit1, int val1, 203b32ade12SFinn Thain int reg2, int bit2, int val2, int wait) 2041da177e4SLinus Torvalds { 2052f854b82SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 2062f854b82SFinn Thain unsigned long deadline = jiffies + wait; 2072f854b82SFinn Thain unsigned long n; 2081da177e4SLinus Torvalds 2092f854b82SFinn Thain /* Busy-wait for up to 10 ms */ 2102f854b82SFinn Thain n = min(10000U, jiffies_to_usecs(wait)); 2112f854b82SFinn Thain n *= hostdata->accesses_per_ms; 212b32ade12SFinn Thain n /= 2000; 2132f854b82SFinn Thain do { 214b32ade12SFinn Thain if ((NCR5380_read(reg1) & bit1) == val1) 215b32ade12SFinn Thain return 0; 216b32ade12SFinn Thain if ((NCR5380_read(reg2) & bit2) == val2) 2171da177e4SLinus Torvalds return 0; 2181da177e4SLinus Torvalds cpu_relax(); 2192f854b82SFinn Thain } while (n--); 2202f854b82SFinn Thain 2212f854b82SFinn Thain if (irqs_disabled() || in_interrupt()) 2222f854b82SFinn Thain return -ETIMEDOUT; 2232f854b82SFinn Thain 2242f854b82SFinn Thain /* Repeatedly sleep for 1 ms until deadline */ 2252f854b82SFinn Thain while (time_is_after_jiffies(deadline)) { 2262f854b82SFinn Thain schedule_timeout_uninterruptible(1); 227b32ade12SFinn Thain if ((NCR5380_read(reg1) & bit1) == val1) 228b32ade12SFinn Thain return 0; 229b32ade12SFinn Thain if ((NCR5380_read(reg2) & bit2) == val2) 2302f854b82SFinn Thain return 0; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds return -ETIMEDOUT; 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 236b32ade12SFinn Thain static inline int NCR5380_poll_politely(struct Scsi_Host *instance, 237b32ade12SFinn Thain int reg, int bit, int val, int wait) 238b32ade12SFinn Thain { 239b32ade12SFinn Thain return NCR5380_poll_politely2(instance, reg, bit, val, 240b32ade12SFinn Thain reg, bit, val, wait); 241b32ade12SFinn Thain } 242b32ade12SFinn Thain 243185a7a1cSviro@ZenIV.linux.org.uk #if NDEBUG 2441da177e4SLinus Torvalds static struct { 2451da177e4SLinus Torvalds unsigned char mask; 2461da177e4SLinus Torvalds const char *name; 2471da177e4SLinus Torvalds } signals[] = { 2481da177e4SLinus Torvalds {SR_DBP, "PARITY"}, 2491da177e4SLinus Torvalds {SR_RST, "RST"}, 2501da177e4SLinus Torvalds {SR_BSY, "BSY"}, 2511da177e4SLinus Torvalds {SR_REQ, "REQ"}, 2521da177e4SLinus Torvalds {SR_MSG, "MSG"}, 2531da177e4SLinus Torvalds {SR_CD, "CD"}, 2541da177e4SLinus Torvalds {SR_IO, "IO"}, 2551da177e4SLinus Torvalds {SR_SEL, "SEL"}, 2561da177e4SLinus Torvalds {0, NULL} 2571da177e4SLinus Torvalds }, 2581da177e4SLinus Torvalds basrs[] = { 2591da177e4SLinus Torvalds {BASR_ATN, "ATN"}, 2601da177e4SLinus Torvalds {BASR_ACK, "ACK"}, 2611da177e4SLinus Torvalds {0, NULL} 2621da177e4SLinus Torvalds }, 2631da177e4SLinus Torvalds icrs[] = { 2641da177e4SLinus Torvalds {ICR_ASSERT_RST, "ASSERT RST"}, 2651da177e4SLinus Torvalds {ICR_ASSERT_ACK, "ASSERT ACK"}, 2661da177e4SLinus Torvalds {ICR_ASSERT_BSY, "ASSERT BSY"}, 2671da177e4SLinus Torvalds {ICR_ASSERT_SEL, "ASSERT SEL"}, 2681da177e4SLinus Torvalds {ICR_ASSERT_ATN, "ASSERT ATN"}, 2691da177e4SLinus Torvalds {ICR_ASSERT_DATA, "ASSERT DATA"}, 2701da177e4SLinus Torvalds {0, NULL} 2711da177e4SLinus Torvalds }, 2721da177e4SLinus Torvalds mrs[] = { 2731da177e4SLinus Torvalds {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, 2741da177e4SLinus Torvalds {MR_TARGET, "MODE TARGET"}, 2751da177e4SLinus Torvalds {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, 2761da177e4SLinus Torvalds {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, 2770d2cf867SFinn Thain {MR_ENABLE_EOP_INTR, "MODE EOP INTR"}, 2781da177e4SLinus Torvalds {MR_MONITOR_BSY, "MODE MONITOR BSY"}, 2791da177e4SLinus Torvalds {MR_DMA_MODE, "MODE DMA"}, 2801da177e4SLinus Torvalds {MR_ARBITRATE, "MODE ARBITRATION"}, 2811da177e4SLinus Torvalds {0, NULL} 2821da177e4SLinus Torvalds }; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds /** 2851da177e4SLinus Torvalds * NCR5380_print - print scsi bus signals 2861da177e4SLinus Torvalds * @instance: adapter state to dump 2871da177e4SLinus Torvalds * 2881da177e4SLinus Torvalds * Print the SCSI bus signals for debugging purposes 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds static void NCR5380_print(struct Scsi_Host *instance) 2921da177e4SLinus Torvalds { 2931da177e4SLinus Torvalds unsigned char status, data, basr, mr, icr, i; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds data = NCR5380_read(CURRENT_SCSI_DATA_REG); 2961da177e4SLinus Torvalds status = NCR5380_read(STATUS_REG); 2971da177e4SLinus Torvalds mr = NCR5380_read(MODE_REG); 2981da177e4SLinus Torvalds icr = NCR5380_read(INITIATOR_COMMAND_REG); 2991da177e4SLinus Torvalds basr = NCR5380_read(BUS_AND_STATUS_REG); 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds printk("STATUS_REG: %02x ", status); 3021da177e4SLinus Torvalds for (i = 0; signals[i].mask; ++i) 3031da177e4SLinus Torvalds if (status & signals[i].mask) 3041da177e4SLinus Torvalds printk(",%s", signals[i].name); 3051da177e4SLinus Torvalds printk("\nBASR: %02x ", basr); 3061da177e4SLinus Torvalds for (i = 0; basrs[i].mask; ++i) 3071da177e4SLinus Torvalds if (basr & basrs[i].mask) 3081da177e4SLinus Torvalds printk(",%s", basrs[i].name); 3091da177e4SLinus Torvalds printk("\nICR: %02x ", icr); 3101da177e4SLinus Torvalds for (i = 0; icrs[i].mask; ++i) 3111da177e4SLinus Torvalds if (icr & icrs[i].mask) 3121da177e4SLinus Torvalds printk(",%s", icrs[i].name); 3131da177e4SLinus Torvalds printk("\nMODE: %02x ", mr); 3141da177e4SLinus Torvalds for (i = 0; mrs[i].mask; ++i) 3151da177e4SLinus Torvalds if (mr & mrs[i].mask) 3161da177e4SLinus Torvalds printk(",%s", mrs[i].name); 3171da177e4SLinus Torvalds printk("\n"); 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds 3200d2cf867SFinn Thain static struct { 3210d2cf867SFinn Thain unsigned char value; 3220d2cf867SFinn Thain const char *name; 3230d2cf867SFinn Thain } phases[] = { 3240d2cf867SFinn Thain {PHASE_DATAOUT, "DATAOUT"}, 3250d2cf867SFinn Thain {PHASE_DATAIN, "DATAIN"}, 3260d2cf867SFinn Thain {PHASE_CMDOUT, "CMDOUT"}, 3270d2cf867SFinn Thain {PHASE_STATIN, "STATIN"}, 3280d2cf867SFinn Thain {PHASE_MSGOUT, "MSGOUT"}, 3290d2cf867SFinn Thain {PHASE_MSGIN, "MSGIN"}, 3300d2cf867SFinn Thain {PHASE_UNKNOWN, "UNKNOWN"} 3310d2cf867SFinn Thain }; 3321da177e4SLinus Torvalds 333c16df32eSFinn Thain /** 3341da177e4SLinus Torvalds * NCR5380_print_phase - show SCSI phase 3351da177e4SLinus Torvalds * @instance: adapter to dump 3361da177e4SLinus Torvalds * 3371da177e4SLinus Torvalds * Print the current SCSI phase for debugging purposes 3381da177e4SLinus Torvalds */ 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds static void NCR5380_print_phase(struct Scsi_Host *instance) 3411da177e4SLinus Torvalds { 3421da177e4SLinus Torvalds unsigned char status; 3431da177e4SLinus Torvalds int i; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds status = NCR5380_read(STATUS_REG); 3461da177e4SLinus Torvalds if (!(status & SR_REQ)) 3476a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n"); 3481da177e4SLinus Torvalds else { 3490d2cf867SFinn Thain for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 3500d2cf867SFinn Thain (phases[i].value != (status & PHASE_MASK)); ++i) 3510d2cf867SFinn Thain ; 3526a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name); 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds #endif 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds 358d5f7e65dSFinn Thain static int probe_irq __initdata; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds /** 3611da177e4SLinus Torvalds * probe_intr - helper for IRQ autoprobe 3621da177e4SLinus Torvalds * @irq: interrupt number 3631da177e4SLinus Torvalds * @dev_id: unused 3641da177e4SLinus Torvalds * @regs: unused 3651da177e4SLinus Torvalds * 3661da177e4SLinus Torvalds * Set a flag to indicate the IRQ in question was received. This is 3671da177e4SLinus Torvalds * used by the IRQ probe code. 3681da177e4SLinus Torvalds */ 3691da177e4SLinus Torvalds 3707d12e780SDavid Howells static irqreturn_t __init probe_intr(int irq, void *dev_id) 3711da177e4SLinus Torvalds { 3721da177e4SLinus Torvalds probe_irq = irq; 3731da177e4SLinus Torvalds return IRQ_HANDLED; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds /** 3771da177e4SLinus Torvalds * NCR5380_probe_irq - find the IRQ of an NCR5380 3781da177e4SLinus Torvalds * @instance: NCR5380 controller 3791da177e4SLinus Torvalds * @possible: bitmask of ISA IRQ lines 3801da177e4SLinus Torvalds * 3811da177e4SLinus Torvalds * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ 3821da177e4SLinus Torvalds * and then looking to see what interrupt actually turned up. 3831da177e4SLinus Torvalds */ 3841da177e4SLinus Torvalds 385702809ceSAndrew Morton static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance, 386702809ceSAndrew Morton int possible) 3871da177e4SLinus Torvalds { 388e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 3891da177e4SLinus Torvalds unsigned long timeout; 3901da177e4SLinus Torvalds int trying_irqs, i, mask; 3911da177e4SLinus Torvalds 39222f5f10dSFinn Thain for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1) 3934909cc2bSMichael Opdenacker if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0)) 3941da177e4SLinus Torvalds trying_irqs |= mask; 3951da177e4SLinus Torvalds 3964e5a800cSNicholas Mc Guire timeout = jiffies + msecs_to_jiffies(250); 39722f5f10dSFinn Thain probe_irq = NO_IRQ; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds /* 4001da177e4SLinus Torvalds * A interrupt is triggered whenever BSY = false, SEL = true 4011da177e4SLinus Torvalds * and a bit set in the SELECT_ENABLE_REG is asserted on the 4021da177e4SLinus Torvalds * SCSI bus. 4031da177e4SLinus Torvalds * 4041da177e4SLinus Torvalds * Note that the bus is only driven when the phase control signals 4051da177e4SLinus Torvalds * (I/O, C/D, and MSG) match those in the TCR, so we must reset that 4061da177e4SLinus Torvalds * to zero. 4071da177e4SLinus Torvalds */ 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 4101da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 4111da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); 4121da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); 4131da177e4SLinus Torvalds 41422f5f10dSFinn Thain while (probe_irq == NO_IRQ && time_before(jiffies, timeout)) 415a9a3047dSNishanth Aravamudan schedule_timeout_uninterruptible(1); 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 4181da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 4191da177e4SLinus Torvalds 42022f5f10dSFinn Thain for (i = 1, mask = 2; i < 16; ++i, mask <<= 1) 4211da177e4SLinus Torvalds if (trying_irqs & mask) 4221da177e4SLinus Torvalds free_irq(i, NULL); 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds return probe_irq; 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds /** 4288c32513bSFinn Thain * NCR58380_info - report driver and host information 4298c32513bSFinn Thain * @instance: relevant scsi host instance 4301da177e4SLinus Torvalds * 4318c32513bSFinn Thain * For use as the host template info() handler. 4321da177e4SLinus Torvalds */ 4331da177e4SLinus Torvalds 4348c32513bSFinn Thain static const char *NCR5380_info(struct Scsi_Host *instance) 4351da177e4SLinus Torvalds { 4368c32513bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 4378c32513bSFinn Thain 4388c32513bSFinn Thain return hostdata->info; 4398c32513bSFinn Thain } 4408c32513bSFinn Thain 4418c32513bSFinn Thain static void prepare_info(struct Scsi_Host *instance) 4428c32513bSFinn Thain { 4438c32513bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 4448c32513bSFinn Thain 4458c32513bSFinn Thain snprintf(hostdata->info, sizeof(hostdata->info), 4468c32513bSFinn Thain "%s, io_port 0x%lx, n_io_port %d, " 4478c32513bSFinn Thain "base 0x%lx, irq %d, " 4488c32513bSFinn Thain "can_queue %d, cmd_per_lun %d, " 4498c32513bSFinn Thain "sg_tablesize %d, this_id %d, " 450be3f4121SFinn Thain "flags { %s%s%s}, " 4518c32513bSFinn Thain "options { %s} ", 4528c32513bSFinn Thain instance->hostt->name, instance->io_port, instance->n_io_port, 4538c32513bSFinn Thain instance->base, instance->irq, 4548c32513bSFinn Thain instance->can_queue, instance->cmd_per_lun, 4558c32513bSFinn Thain instance->sg_tablesize, instance->this_id, 4561bb46002SFinn Thain hostdata->flags & FLAG_DMA_FIXUP ? "DMA_FIXUP " : "", 4578c32513bSFinn Thain hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "", 4589c3f0e2bSFinn Thain hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "", 4591da177e4SLinus Torvalds #ifdef AUTOPROBE_IRQ 4601da177e4SLinus Torvalds "AUTOPROBE_IRQ " 4611da177e4SLinus Torvalds #endif 4621da177e4SLinus Torvalds #ifdef DIFFERENTIAL 4631da177e4SLinus Torvalds "DIFFERENTIAL " 4641da177e4SLinus Torvalds #endif 4651da177e4SLinus Torvalds #ifdef PARITY 4661da177e4SLinus Torvalds "PARITY " 4671da177e4SLinus Torvalds #endif 4688c32513bSFinn Thain ""); 4691da177e4SLinus Torvalds } 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds /** 4721da177e4SLinus Torvalds * NCR5380_init - initialise an NCR5380 4731da177e4SLinus Torvalds * @instance: adapter to configure 4741da177e4SLinus Torvalds * @flags: control flags 4751da177e4SLinus Torvalds * 4761da177e4SLinus Torvalds * Initializes *instance and corresponding 5380 chip, 4771da177e4SLinus Torvalds * with flags OR'd into the initial flags value. 4781da177e4SLinus Torvalds * 4791da177e4SLinus Torvalds * Notes : I assume that the host, hostno, and id bits have been 4801da177e4SLinus Torvalds * set correctly. I don't care about the irq and other fields. 4811da177e4SLinus Torvalds * 4821da177e4SLinus Torvalds * Returns 0 for success 4831da177e4SLinus Torvalds */ 4841da177e4SLinus Torvalds 4856f039790SGreg Kroah-Hartman static int NCR5380_init(struct Scsi_Host *instance, int flags) 4861da177e4SLinus Torvalds { 487e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 488b6488f97SFinn Thain int i; 4892f854b82SFinn Thain unsigned long deadline; 4901da177e4SLinus Torvalds 4910d2cf867SFinn Thain hostdata->host = instance; 4921da177e4SLinus Torvalds hostdata->id_mask = 1 << instance->this_id; 4930d2cf867SFinn Thain hostdata->id_higher_mask = 0; 4941da177e4SLinus Torvalds for (i = hostdata->id_mask; i <= 0x80; i <<= 1) 4951da177e4SLinus Torvalds if (i > hostdata->id_mask) 4961da177e4SLinus Torvalds hostdata->id_higher_mask |= i; 4971da177e4SLinus Torvalds for (i = 0; i < 8; ++i) 4981da177e4SLinus Torvalds hostdata->busy[i] = 0; 499e4dec680SFinn Thain hostdata->dma_len = 0; 500e4dec680SFinn Thain 50111d2f63bSFinn Thain spin_lock_init(&hostdata->lock); 5021da177e4SLinus Torvalds hostdata->connected = NULL; 503f27db8ebSFinn Thain hostdata->sensing = NULL; 504f27db8ebSFinn Thain INIT_LIST_HEAD(&hostdata->autosense); 50532b26a10SFinn Thain INIT_LIST_HEAD(&hostdata->unissued); 50632b26a10SFinn Thain INIT_LIST_HEAD(&hostdata->disconnected); 50732b26a10SFinn Thain 50855181be8SFinn Thain hostdata->flags = flags; 5091da177e4SLinus Torvalds 5108d8601a7SFinn Thain INIT_WORK(&hostdata->main_task, NCR5380_main); 5110ad0eff9SFinn Thain hostdata->work_q = alloc_workqueue("ncr5380_%d", 5120ad0eff9SFinn Thain WQ_UNBOUND | WQ_MEM_RECLAIM, 5130ad0eff9SFinn Thain 1, instance->host_no); 5140ad0eff9SFinn Thain if (!hostdata->work_q) 5150ad0eff9SFinn Thain return -ENOMEM; 5161da177e4SLinus Torvalds 5178c32513bSFinn Thain prepare_info(instance); 5188c32513bSFinn Thain 5191da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 5201da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 5211da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 5221da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 5232f854b82SFinn Thain 5242f854b82SFinn Thain /* Calibrate register polling loop */ 5252f854b82SFinn Thain i = 0; 5262f854b82SFinn Thain deadline = jiffies + 1; 5272f854b82SFinn Thain do { 5282f854b82SFinn Thain cpu_relax(); 5292f854b82SFinn Thain } while (time_is_after_jiffies(deadline)); 5302f854b82SFinn Thain deadline += msecs_to_jiffies(256); 5312f854b82SFinn Thain do { 5322f854b82SFinn Thain NCR5380_read(STATUS_REG); 5332f854b82SFinn Thain ++i; 5342f854b82SFinn Thain cpu_relax(); 5352f854b82SFinn Thain } while (time_is_after_jiffies(deadline)); 5362f854b82SFinn Thain hostdata->accesses_per_ms = i / 256; 5372f854b82SFinn Thain 538b6488f97SFinn Thain return 0; 539b6488f97SFinn Thain } 5401da177e4SLinus Torvalds 541b6488f97SFinn Thain /** 542b6488f97SFinn Thain * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems. 543b6488f97SFinn Thain * @instance: adapter to check 5441da177e4SLinus Torvalds * 545b6488f97SFinn Thain * If the system crashed, it may have crashed with a connected target and 546b6488f97SFinn Thain * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the 547b6488f97SFinn Thain * currently established nexus, which we know nothing about. Failing that 548b6488f97SFinn Thain * do a bus reset. 5491da177e4SLinus Torvalds * 550b6488f97SFinn Thain * Note that a bus reset will cause the chip to assert IRQ. 551b6488f97SFinn Thain * 552b6488f97SFinn Thain * Returns 0 if successful, otherwise -ENXIO. 5531da177e4SLinus Torvalds */ 5541da177e4SLinus Torvalds 555b6488f97SFinn Thain static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance) 556b6488f97SFinn Thain { 5579c3f0e2bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 558b6488f97SFinn Thain int pass; 559b6488f97SFinn Thain 5601da177e4SLinus Torvalds for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) { 5611da177e4SLinus Torvalds switch (pass) { 5621da177e4SLinus Torvalds case 1: 5631da177e4SLinus Torvalds case 3: 5641da177e4SLinus Torvalds case 5: 565636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n"); 566636b1ec8SFinn Thain NCR5380_poll_politely(instance, 567636b1ec8SFinn Thain STATUS_REG, SR_BSY, 0, 5 * HZ); 5681da177e4SLinus Torvalds break; 5691da177e4SLinus Torvalds case 2: 570636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n"); 5711da177e4SLinus Torvalds do_abort(instance); 5721da177e4SLinus Torvalds break; 5731da177e4SLinus Torvalds case 4: 574636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n"); 5751da177e4SLinus Torvalds do_reset(instance); 5769c3f0e2bSFinn Thain /* Wait after a reset; the SCSI standard calls for 5779c3f0e2bSFinn Thain * 250ms, we wait 500ms to be on the safe side. 5789c3f0e2bSFinn Thain * But some Toshiba CD-ROMs need ten times that. 5799c3f0e2bSFinn Thain */ 5809c3f0e2bSFinn Thain if (hostdata->flags & FLAG_TOSHIBA_DELAY) 5819c3f0e2bSFinn Thain msleep(2500); 5829c3f0e2bSFinn Thain else 5839c3f0e2bSFinn Thain msleep(500); 5841da177e4SLinus Torvalds break; 5851da177e4SLinus Torvalds case 6: 586636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus locked solid\n"); 5871da177e4SLinus Torvalds return -ENXIO; 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds } 5901da177e4SLinus Torvalds return 0; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds /** 5941da177e4SLinus Torvalds * NCR5380_exit - remove an NCR5380 5951da177e4SLinus Torvalds * @instance: adapter to remove 5960d2cf867SFinn Thain * 5970d2cf867SFinn Thain * Assumes that no more work can be queued (e.g. by NCR5380_intr). 5981da177e4SLinus Torvalds */ 5991da177e4SLinus Torvalds 600a43cf0f3SRandy Dunlap static void NCR5380_exit(struct Scsi_Host *instance) 6011da177e4SLinus Torvalds { 602e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 6031da177e4SLinus Torvalds 6048d8601a7SFinn Thain cancel_work_sync(&hostdata->main_task); 6050ad0eff9SFinn Thain destroy_workqueue(hostdata->work_q); 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds /** 609677e0194SFinn Thain * complete_cmd - finish processing a command and return it to the SCSI ML 610677e0194SFinn Thain * @instance: the host instance 611677e0194SFinn Thain * @cmd: command to complete 612677e0194SFinn Thain */ 613677e0194SFinn Thain 614677e0194SFinn Thain static void complete_cmd(struct Scsi_Host *instance, 615677e0194SFinn Thain struct scsi_cmnd *cmd) 616677e0194SFinn Thain { 617677e0194SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 618677e0194SFinn Thain 619677e0194SFinn Thain dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd); 620677e0194SFinn Thain 621f27db8ebSFinn Thain if (hostdata->sensing == cmd) { 622f27db8ebSFinn Thain /* Autosense processing ends here */ 623f27db8ebSFinn Thain if ((cmd->result & 0xff) != SAM_STAT_GOOD) { 624f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 625f27db8ebSFinn Thain set_host_byte(cmd, DID_ERROR); 626f27db8ebSFinn Thain } else 627f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 628f27db8ebSFinn Thain hostdata->sensing = NULL; 629f27db8ebSFinn Thain } 630f27db8ebSFinn Thain 631677e0194SFinn Thain hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); 632677e0194SFinn Thain 633677e0194SFinn Thain cmd->scsi_done(cmd); 634677e0194SFinn Thain } 635677e0194SFinn Thain 636677e0194SFinn Thain /** 6371da177e4SLinus Torvalds * NCR5380_queue_command - queue a command 6381bb40589SFinn Thain * @instance: the relevant SCSI adapter 6391da177e4SLinus Torvalds * @cmd: SCSI command 6401da177e4SLinus Torvalds * 6411bb40589SFinn Thain * cmd is added to the per-instance issue queue, with minor 6421da177e4SLinus Torvalds * twiddling done to the host specific fields of cmd. If the 6431da177e4SLinus Torvalds * main coroutine is not running, it is restarted. 6441da177e4SLinus Torvalds */ 6451da177e4SLinus Torvalds 6461bb40589SFinn Thain static int NCR5380_queue_command(struct Scsi_Host *instance, 6471bb40589SFinn Thain struct scsi_cmnd *cmd) 6481da177e4SLinus Torvalds { 6491bb40589SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 65032b26a10SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 6511bb40589SFinn Thain unsigned long flags; 6521da177e4SLinus Torvalds 6531da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_WRITE) 6541da177e4SLinus Torvalds switch (cmd->cmnd[0]) { 6551da177e4SLinus Torvalds case WRITE_6: 6561da177e4SLinus Torvalds case WRITE_10: 657dbb6b350SFinn Thain shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n"); 6581da177e4SLinus Torvalds cmd->result = (DID_ERROR << 16); 6591bb40589SFinn Thain cmd->scsi_done(cmd); 6601da177e4SLinus Torvalds return 0; 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds cmd->result = 0; 6651da177e4SLinus Torvalds 66652d3e561SFinn Thain if (!NCR5380_acquire_dma_irq(instance)) 66752d3e561SFinn Thain return SCSI_MLQUEUE_HOST_BUSY; 66852d3e561SFinn Thain 66911d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 6701bb40589SFinn Thain 6711da177e4SLinus Torvalds /* 6721da177e4SLinus Torvalds * Insert the cmd into the issue queue. Note that REQUEST SENSE 6731da177e4SLinus Torvalds * commands are added to the head of the queue since any command will 6741da177e4SLinus Torvalds * clear the contingent allegiance condition that exists and the 6751da177e4SLinus Torvalds * sense data is only guaranteed to be valid while the condition exists. 6761da177e4SLinus Torvalds */ 6771da177e4SLinus Torvalds 67832b26a10SFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 67932b26a10SFinn Thain list_add(&ncmd->list, &hostdata->unissued); 68032b26a10SFinn Thain else 68132b26a10SFinn Thain list_add_tail(&ncmd->list, &hostdata->unissued); 68232b26a10SFinn Thain 68311d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 6841bb40589SFinn Thain 685dbb6b350SFinn Thain dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n", 686dbb6b350SFinn Thain cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds /* Kick off command processing */ 6898d8601a7SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 6901da177e4SLinus Torvalds return 0; 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds 69352d3e561SFinn Thain static inline void maybe_release_dma_irq(struct Scsi_Host *instance) 69452d3e561SFinn Thain { 69552d3e561SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 69652d3e561SFinn Thain 69752d3e561SFinn Thain /* Caller does the locking needed to set & test these data atomically */ 69852d3e561SFinn Thain if (list_empty(&hostdata->disconnected) && 69952d3e561SFinn Thain list_empty(&hostdata->unissued) && 70052d3e561SFinn Thain list_empty(&hostdata->autosense) && 70152d3e561SFinn Thain !hostdata->connected && 70252d3e561SFinn Thain !hostdata->selecting) 70352d3e561SFinn Thain NCR5380_release_dma_irq(instance); 70452d3e561SFinn Thain } 70552d3e561SFinn Thain 7061da177e4SLinus Torvalds /** 707f27db8ebSFinn Thain * dequeue_next_cmd - dequeue a command for processing 708f27db8ebSFinn Thain * @instance: the scsi host instance 709f27db8ebSFinn Thain * 710f27db8ebSFinn Thain * Priority is given to commands on the autosense queue. These commands 711f27db8ebSFinn Thain * need autosense because of a CHECK CONDITION result. 712f27db8ebSFinn Thain * 713f27db8ebSFinn Thain * Returns a command pointer if a command is found for a target that is 714f27db8ebSFinn Thain * not already busy. Otherwise returns NULL. 715f27db8ebSFinn Thain */ 716f27db8ebSFinn Thain 717f27db8ebSFinn Thain static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance) 718f27db8ebSFinn Thain { 719f27db8ebSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 720f27db8ebSFinn Thain struct NCR5380_cmd *ncmd; 721f27db8ebSFinn Thain struct scsi_cmnd *cmd; 722f27db8ebSFinn Thain 7238d5dbec3SFinn Thain if (hostdata->sensing || list_empty(&hostdata->autosense)) { 724f27db8ebSFinn Thain list_for_each_entry(ncmd, &hostdata->unissued, list) { 725f27db8ebSFinn Thain cmd = NCR5380_to_scmd(ncmd); 726f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n", 727f27db8ebSFinn Thain cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun); 728f27db8ebSFinn Thain 729f27db8ebSFinn Thain if (!(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))) { 730f27db8ebSFinn Thain list_del(&ncmd->list); 731f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, 732f27db8ebSFinn Thain "dequeue: removed %p from issue queue\n", cmd); 733f27db8ebSFinn Thain return cmd; 734f27db8ebSFinn Thain } 735f27db8ebSFinn Thain } 736f27db8ebSFinn Thain } else { 737f27db8ebSFinn Thain /* Autosense processing begins here */ 738f27db8ebSFinn Thain ncmd = list_first_entry(&hostdata->autosense, 739f27db8ebSFinn Thain struct NCR5380_cmd, list); 740f27db8ebSFinn Thain list_del(&ncmd->list); 741f27db8ebSFinn Thain cmd = NCR5380_to_scmd(ncmd); 742f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, 743f27db8ebSFinn Thain "dequeue: removed %p from autosense queue\n", cmd); 744f27db8ebSFinn Thain scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); 745f27db8ebSFinn Thain hostdata->sensing = cmd; 746f27db8ebSFinn Thain return cmd; 747f27db8ebSFinn Thain } 748f27db8ebSFinn Thain return NULL; 749f27db8ebSFinn Thain } 750f27db8ebSFinn Thain 751f27db8ebSFinn Thain static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd) 752f27db8ebSFinn Thain { 753f27db8ebSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 754f27db8ebSFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 755f27db8ebSFinn Thain 7568d5dbec3SFinn Thain if (hostdata->sensing == cmd) { 757f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 758f27db8ebSFinn Thain list_add(&ncmd->list, &hostdata->autosense); 759f27db8ebSFinn Thain hostdata->sensing = NULL; 760f27db8ebSFinn Thain } else 761f27db8ebSFinn Thain list_add(&ncmd->list, &hostdata->unissued); 762f27db8ebSFinn Thain } 763f27db8ebSFinn Thain 764f27db8ebSFinn Thain /** 7651da177e4SLinus Torvalds * NCR5380_main - NCR state machines 7661da177e4SLinus Torvalds * 7671da177e4SLinus Torvalds * NCR5380_main is a coroutine that runs as long as more work can 7681da177e4SLinus Torvalds * be done on the NCR5380 host adapters in a system. Both 7691da177e4SLinus Torvalds * NCR5380_queue_command() and NCR5380_intr() will try to start it 7701da177e4SLinus Torvalds * in case it is not running. 7711da177e4SLinus Torvalds */ 7721da177e4SLinus Torvalds 773c4028958SDavid Howells static void NCR5380_main(struct work_struct *work) 7741da177e4SLinus Torvalds { 775c4028958SDavid Howells struct NCR5380_hostdata *hostdata = 7768d8601a7SFinn Thain container_of(work, struct NCR5380_hostdata, main_task); 7771da177e4SLinus Torvalds struct Scsi_Host *instance = hostdata->host; 7781da177e4SLinus Torvalds int done; 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds do { 7811da177e4SLinus Torvalds done = 1; 78211d2f63bSFinn Thain 7830a4e3612SFinn Thain spin_lock_irq(&hostdata->lock); 784ccf6efd7SFinn Thain while (!hostdata->connected && !hostdata->selecting) { 785ccf6efd7SFinn Thain struct scsi_cmnd *cmd = dequeue_next_cmd(instance); 786ccf6efd7SFinn Thain 787ccf6efd7SFinn Thain if (!cmd) 788ccf6efd7SFinn Thain break; 78932b26a10SFinn Thain 790f27db8ebSFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd); 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds /* 7931da177e4SLinus Torvalds * Attempt to establish an I_T_L nexus here. 7941da177e4SLinus Torvalds * On success, instance->hostdata->connected is set. 7951da177e4SLinus Torvalds * On failure, we must add the command back to the 7961da177e4SLinus Torvalds * issue queue so we can keep trying. 7971da177e4SLinus Torvalds */ 7981da177e4SLinus Torvalds /* 7991da177e4SLinus Torvalds * REQUEST SENSE commands are issued without tagged 8001da177e4SLinus Torvalds * queueing, even on SCSI-II devices because the 8011da177e4SLinus Torvalds * contingent allegiance condition exists for the 8021da177e4SLinus Torvalds * entire unit. 8031da177e4SLinus Torvalds */ 80476f13b93SFinn Thain 805ccf6efd7SFinn Thain if (!NCR5380_select(instance, cmd)) { 806707d62b3SFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: select complete\n"); 80752d3e561SFinn Thain maybe_release_dma_irq(instance); 8081da177e4SLinus Torvalds } else { 809f27db8ebSFinn Thain dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance, 810f27db8ebSFinn Thain "main: select failed, returning %p to queue\n", cmd); 811f27db8ebSFinn Thain requeue_cmd(instance, cmd); 8121da177e4SLinus Torvalds } 813f27db8ebSFinn Thain } 814e4dec680SFinn Thain if (hostdata->connected && !hostdata->dma_len) { 815b746545fSFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n"); 8161da177e4SLinus Torvalds NCR5380_information_transfer(instance); 8171da177e4SLinus Torvalds done = 0; 8181d3db59dSFinn Thain } 81911d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 8200a4e3612SFinn Thain if (!done) 8210a4e3612SFinn Thain cond_resched(); 8220a4e3612SFinn Thain } while (!done); 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds 8258053b0eeSFinn Thain /* 8268053b0eeSFinn Thain * NCR5380_dma_complete - finish DMA transfer 8278053b0eeSFinn Thain * @instance: the scsi host instance 8288053b0eeSFinn Thain * 8298053b0eeSFinn Thain * Called by the interrupt handler when DMA finishes or a phase 8308053b0eeSFinn Thain * mismatch occurs (which would end the DMA transfer). 8318053b0eeSFinn Thain */ 8328053b0eeSFinn Thain 8338053b0eeSFinn Thain static void NCR5380_dma_complete(struct Scsi_Host *instance) 8348053b0eeSFinn Thain { 8358053b0eeSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 8368053b0eeSFinn Thain int transferred; 8378053b0eeSFinn Thain unsigned char **data; 8388053b0eeSFinn Thain int *count; 8398053b0eeSFinn Thain int saved_data = 0, overrun = 0; 8408053b0eeSFinn Thain unsigned char p; 8418053b0eeSFinn Thain 8428053b0eeSFinn Thain if (hostdata->read_overruns) { 8438053b0eeSFinn Thain p = hostdata->connected->SCp.phase; 8448053b0eeSFinn Thain if (p & SR_IO) { 8458053b0eeSFinn Thain udelay(10); 8468053b0eeSFinn Thain if ((NCR5380_read(BUS_AND_STATUS_REG) & 8478053b0eeSFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) == 8488053b0eeSFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) { 8498053b0eeSFinn Thain saved_data = NCR5380_read(INPUT_DATA_REG); 8508053b0eeSFinn Thain overrun = 1; 8518053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, "read overrun handled\n"); 8528053b0eeSFinn Thain } 8538053b0eeSFinn Thain } 8548053b0eeSFinn Thain } 8558053b0eeSFinn Thain 856e9db3198SFinn Thain #ifdef CONFIG_SUN3 857e9db3198SFinn Thain if ((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) { 858e9db3198SFinn Thain pr_err("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", 859e9db3198SFinn Thain instance->host_no); 860e9db3198SFinn Thain BUG(); 861e9db3198SFinn Thain } 862e9db3198SFinn Thain 863e9db3198SFinn Thain if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == 864e9db3198SFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) { 865e9db3198SFinn Thain pr_err("scsi%d: BASR %02x\n", instance->host_no, 866e9db3198SFinn Thain NCR5380_read(BUS_AND_STATUS_REG)); 867e9db3198SFinn Thain pr_err("scsi%d: bus stuck in data phase -- probably a single byte overrun!\n", 868e9db3198SFinn Thain instance->host_no); 869e9db3198SFinn Thain BUG(); 870e9db3198SFinn Thain } 871e9db3198SFinn Thain #endif 872e9db3198SFinn Thain 8738053b0eeSFinn Thain NCR5380_write(MODE_REG, MR_BASE); 8748053b0eeSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 8758053b0eeSFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 8768053b0eeSFinn Thain 8778053b0eeSFinn Thain transferred = hostdata->dma_len - NCR5380_dma_residual(instance); 8788053b0eeSFinn Thain hostdata->dma_len = 0; 8798053b0eeSFinn Thain 8808053b0eeSFinn Thain data = (unsigned char **)&hostdata->connected->SCp.ptr; 8818053b0eeSFinn Thain count = &hostdata->connected->SCp.this_residual; 8828053b0eeSFinn Thain *data += transferred; 8838053b0eeSFinn Thain *count -= transferred; 8848053b0eeSFinn Thain 8858053b0eeSFinn Thain if (hostdata->read_overruns) { 8868053b0eeSFinn Thain int cnt, toPIO; 8878053b0eeSFinn Thain 8888053b0eeSFinn Thain if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { 8898053b0eeSFinn Thain cnt = toPIO = hostdata->read_overruns; 8908053b0eeSFinn Thain if (overrun) { 8918053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, 8928053b0eeSFinn Thain "Got an input overrun, using saved byte\n"); 8938053b0eeSFinn Thain *(*data)++ = saved_data; 8948053b0eeSFinn Thain (*count)--; 8958053b0eeSFinn Thain cnt--; 8968053b0eeSFinn Thain toPIO--; 8978053b0eeSFinn Thain } 8988053b0eeSFinn Thain if (toPIO > 0) { 8998053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, 9008053b0eeSFinn Thain "Doing %d byte PIO to 0x%p\n", cnt, *data); 9018053b0eeSFinn Thain NCR5380_transfer_pio(instance, &p, &cnt, data); 9028053b0eeSFinn Thain *count -= toPIO - cnt; 9038053b0eeSFinn Thain } 9048053b0eeSFinn Thain } 9058053b0eeSFinn Thain } 9068053b0eeSFinn Thain } 9078053b0eeSFinn Thain 9081da177e4SLinus Torvalds #ifndef DONT_USE_INTR 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds /** 9111da177e4SLinus Torvalds * NCR5380_intr - generic NCR5380 irq handler 9121da177e4SLinus Torvalds * @irq: interrupt number 9131da177e4SLinus Torvalds * @dev_id: device info 9141da177e4SLinus Torvalds * 9151da177e4SLinus Torvalds * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses 9161da177e4SLinus Torvalds * from the disconnected queue, and restarting NCR5380_main() 9171da177e4SLinus Torvalds * as required. 9181da177e4SLinus Torvalds * 919cd400825SFinn Thain * The chip can assert IRQ in any of six different conditions. The IRQ flag 920cd400825SFinn Thain * is then cleared by reading the Reset Parity/Interrupt Register (RPIR). 921cd400825SFinn Thain * Three of these six conditions are latched in the Bus and Status Register: 922cd400825SFinn Thain * - End of DMA (cleared by ending DMA Mode) 923cd400825SFinn Thain * - Parity error (cleared by reading RPIR) 924cd400825SFinn Thain * - Loss of BSY (cleared by reading RPIR) 925cd400825SFinn Thain * Two conditions have flag bits that are not latched: 926cd400825SFinn Thain * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode) 927cd400825SFinn Thain * - Bus reset (non-maskable) 928cd400825SFinn Thain * The remaining condition has no flag bit at all: 929cd400825SFinn Thain * - Selection/reselection 930cd400825SFinn Thain * 931cd400825SFinn Thain * Hence, establishing the cause(s) of any interrupt is partly guesswork. 932cd400825SFinn Thain * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor 933cd400825SFinn Thain * claimed that "the design of the [DP8490] interrupt logic ensures 934cd400825SFinn Thain * interrupts will not be lost (they can be on the DP5380)." 935cd400825SFinn Thain * The L5380/53C80 datasheet from LOGIC Devices has more details. 936cd400825SFinn Thain * 937cd400825SFinn Thain * Checking for bus reset by reading RST is futile because of interrupt 938cd400825SFinn Thain * latency, but a bus reset will reset chip logic. Checking for parity error 939cd400825SFinn Thain * is unnecessary because that interrupt is never enabled. A Loss of BSY 940cd400825SFinn Thain * condition will clear DMA Mode. We can tell when this occurs because the 941cd400825SFinn Thain * the Busy Monitor interrupt is enabled together with DMA Mode. 9421da177e4SLinus Torvalds */ 9431da177e4SLinus Torvalds 944cd400825SFinn Thain static irqreturn_t NCR5380_intr(int irq, void *dev_id) 9451da177e4SLinus Torvalds { 946baa9aac6SJeff Garzik struct Scsi_Host *instance = dev_id; 947cd400825SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 948cd400825SFinn Thain int handled = 0; 9491da177e4SLinus Torvalds unsigned char basr; 9501da177e4SLinus Torvalds unsigned long flags; 9511da177e4SLinus Torvalds 95211d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 953cd400825SFinn Thain 9541da177e4SLinus Torvalds basr = NCR5380_read(BUS_AND_STATUS_REG); 9551da177e4SLinus Torvalds if (basr & BASR_IRQ) { 956cd400825SFinn Thain unsigned char mr = NCR5380_read(MODE_REG); 957cd400825SFinn Thain unsigned char sr = NCR5380_read(STATUS_REG); 958cd400825SFinn Thain 959b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n", 960b746545fSFinn Thain irq, basr, sr, mr); 961cd400825SFinn Thain 9628053b0eeSFinn Thain if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) { 9638053b0eeSFinn Thain /* Probably End of DMA, Phase Mismatch or Loss of BSY. 9648053b0eeSFinn Thain * We ack IRQ after clearing Mode Register. Workarounds 9658053b0eeSFinn Thain * for End of DMA errata need to happen in DMA Mode. 9668053b0eeSFinn Thain */ 9678053b0eeSFinn Thain 9688053b0eeSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n"); 9698053b0eeSFinn Thain 9708053b0eeSFinn Thain if (hostdata->connected) { 9718053b0eeSFinn Thain NCR5380_dma_complete(instance); 9728053b0eeSFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 9738053b0eeSFinn Thain } else { 9748053b0eeSFinn Thain NCR5380_write(MODE_REG, MR_BASE); 9758053b0eeSFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 9768053b0eeSFinn Thain } 9778053b0eeSFinn Thain } else if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) && 978cd400825SFinn Thain (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) { 979cd400825SFinn Thain /* Probably reselected */ 980cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 981cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 982cd400825SFinn Thain 983b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n"); 984cd400825SFinn Thain 985cd400825SFinn Thain if (!hostdata->connected) { 986cd400825SFinn Thain NCR5380_reselect(instance); 9878d8601a7SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 988cd400825SFinn Thain } 989cd400825SFinn Thain if (!hostdata->connected) 990cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 991cd400825SFinn Thain } else { 992cd400825SFinn Thain /* Probably Bus Reset */ 993cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 994cd400825SFinn Thain 995b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n"); 996e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 997e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 998e9db3198SFinn Thain #endif 999cd400825SFinn Thain } 1000cd400825SFinn Thain handled = 1; 1001cd400825SFinn Thain } else { 1002cd400825SFinn Thain shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n"); 1003e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1004e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 1005e9db3198SFinn Thain #endif 1006cd400825SFinn Thain } 1007cd400825SFinn Thain 100811d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 1009cd400825SFinn Thain 1010cd400825SFinn Thain return IRQ_RETVAL(handled); 10111da177e4SLinus Torvalds } 10121da177e4SLinus Torvalds 10131da177e4SLinus Torvalds #endif 10141da177e4SLinus Torvalds 10151da177e4SLinus Torvalds /* 1016710ddd0dSFinn Thain * Function : int NCR5380_select(struct Scsi_Host *instance, 1017710ddd0dSFinn Thain * struct scsi_cmnd *cmd) 10181da177e4SLinus Torvalds * 10191da177e4SLinus Torvalds * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, 10201da177e4SLinus Torvalds * including ARBITRATION, SELECTION, and initial message out for 10211da177e4SLinus Torvalds * IDENTIFY and queue messages. 10221da177e4SLinus Torvalds * 10231da177e4SLinus Torvalds * Inputs : instance - instantiation of the 5380 driver on which this 102476f13b93SFinn Thain * target lives, cmd - SCSI command to execute. 10251da177e4SLinus Torvalds * 1026707d62b3SFinn Thain * Returns cmd if selection failed but should be retried, 1027707d62b3SFinn Thain * NULL if selection failed and should not be retried, or 1028707d62b3SFinn Thain * NULL if selection succeeded (hostdata->connected == cmd). 10291da177e4SLinus Torvalds * 10301da177e4SLinus Torvalds * Side effects : 10311da177e4SLinus Torvalds * If bus busy, arbitration failed, etc, NCR5380_select() will exit 10321da177e4SLinus Torvalds * with registers as they should have been on entry - ie 10331da177e4SLinus Torvalds * SELECT_ENABLE will be set appropriately, the NCR5380 10341da177e4SLinus Torvalds * will cease to drive any SCSI bus signals. 10351da177e4SLinus Torvalds * 10361da177e4SLinus Torvalds * If successful : I_T_L or I_T_L_Q nexus will be established, 10371da177e4SLinus Torvalds * instance->connected will be set to cmd. 10381da177e4SLinus Torvalds * SELECT interrupt will be disabled. 10391da177e4SLinus Torvalds * 10401da177e4SLinus Torvalds * If failed (no target) : cmd->scsi_done() will be called, and the 10411da177e4SLinus Torvalds * cmd->result host byte set to DID_BAD_TARGET. 10421da177e4SLinus Torvalds */ 10431da177e4SLinus Torvalds 1044707d62b3SFinn Thain static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, 1045707d62b3SFinn Thain struct scsi_cmnd *cmd) 10461da177e4SLinus Torvalds { 1047e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 10481da177e4SLinus Torvalds unsigned char tmp[3], phase; 10491da177e4SLinus Torvalds unsigned char *data; 10501da177e4SLinus Torvalds int len; 10511da177e4SLinus Torvalds int err; 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_ARBITRATION, instance); 1054b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n", 1055b746545fSFinn Thain instance->this_id); 10561da177e4SLinus Torvalds 10571da177e4SLinus Torvalds /* 1058707d62b3SFinn Thain * Arbitration and selection phases are slow and involve dropping the 1059707d62b3SFinn Thain * lock, so we have to watch out for EH. An exception handler may 1060707d62b3SFinn Thain * change 'selecting' to NULL. This function will then return NULL 1061707d62b3SFinn Thain * so that the caller will forget about 'cmd'. (During information 1062707d62b3SFinn Thain * transfer phases, EH may change 'connected' to NULL.) 1063707d62b3SFinn Thain */ 1064707d62b3SFinn Thain hostdata->selecting = cmd; 1065707d62b3SFinn Thain 1066707d62b3SFinn Thain /* 10671da177e4SLinus Torvalds * Set the phase bits to 0, otherwise the NCR5380 won't drive the 10681da177e4SLinus Torvalds * data bus during SELECTION. 10691da177e4SLinus Torvalds */ 10701da177e4SLinus Torvalds 10711da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 10721da177e4SLinus Torvalds 10731da177e4SLinus Torvalds /* 10741da177e4SLinus Torvalds * Start arbitration. 10751da177e4SLinus Torvalds */ 10761da177e4SLinus Torvalds 10771da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); 10781da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_ARBITRATE); 10791da177e4SLinus Torvalds 108055500d9bSFinn Thain /* The chip now waits for BUS FREE phase. Then after the 800 ns 108155500d9bSFinn Thain * Bus Free Delay, arbitration will begin. 10821da177e4SLinus Torvalds */ 10831da177e4SLinus Torvalds 108411d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 1085b32ade12SFinn Thain err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0, 1086b32ade12SFinn Thain INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, 1087b32ade12SFinn Thain ICR_ARBITRATION_PROGRESS, HZ); 108811d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 108955500d9bSFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) { 109055500d9bSFinn Thain /* Reselection interrupt */ 1091707d62b3SFinn Thain goto out; 109255500d9bSFinn Thain } 1093ccf6efd7SFinn Thain if (!hostdata->selecting) { 1094ccf6efd7SFinn Thain /* Command was aborted */ 1095ccf6efd7SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1096ccf6efd7SFinn Thain goto out; 1097ccf6efd7SFinn Thain } 1098b32ade12SFinn Thain if (err < 0) { 1099b32ade12SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1100b32ade12SFinn Thain shost_printk(KERN_ERR, instance, 1101b32ade12SFinn Thain "select: arbitration timeout\n"); 1102707d62b3SFinn Thain goto out; 110355500d9bSFinn Thain } 110411d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 110555500d9bSFinn Thain 110655500d9bSFinn Thain /* The SCSI-2 arbitration delay is 2.4 us */ 11071da177e4SLinus Torvalds udelay(3); 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds /* Check for lost arbitration */ 11100d2cf867SFinn Thain if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || 11110d2cf867SFinn Thain (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || 11120d2cf867SFinn Thain (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { 11131da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 1114b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n"); 111511d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1116707d62b3SFinn Thain goto out; 11171da177e4SLinus Torvalds } 1118cf13b083SFinn Thain 1119cf13b083SFinn Thain /* After/during arbitration, BSY should be asserted. 1120cf13b083SFinn Thain * IBM DPES-31080 Version S31Q works now 1121cf13b083SFinn Thain * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) 1122cf13b083SFinn Thain */ 1123cf13b083SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, 1124cf13b083SFinn Thain ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY); 11251da177e4SLinus Torvalds 11261da177e4SLinus Torvalds /* 11271da177e4SLinus Torvalds * Again, bus clear + bus settle time is 1.2us, however, this is 11281da177e4SLinus Torvalds * a minimum so we'll udelay ceil(1.2) 11291da177e4SLinus Torvalds */ 11301da177e4SLinus Torvalds 11319c3f0e2bSFinn Thain if (hostdata->flags & FLAG_TOSHIBA_DELAY) 11329c3f0e2bSFinn Thain udelay(15); 11339c3f0e2bSFinn Thain else 11341da177e4SLinus Torvalds udelay(2); 11351da177e4SLinus Torvalds 113611d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 113711d2f63bSFinn Thain 113872064a78SFinn Thain /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */ 113972064a78SFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) 1140707d62b3SFinn Thain goto out; 1141707d62b3SFinn Thain 1142707d62b3SFinn Thain if (!hostdata->selecting) { 1143707d62b3SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1144707d62b3SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1145707d62b3SFinn Thain goto out; 1146707d62b3SFinn Thain } 114772064a78SFinn Thain 1148b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n"); 11491da177e4SLinus Torvalds 11501da177e4SLinus Torvalds /* 11511da177e4SLinus Torvalds * Now that we have won arbitration, start Selection process, asserting 11521da177e4SLinus Torvalds * the host and target ID's on the SCSI bus. 11531da177e4SLinus Torvalds */ 11541da177e4SLinus Torvalds 11553d07d22bSFinn Thain NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd))); 11561da177e4SLinus Torvalds 11571da177e4SLinus Torvalds /* 11581da177e4SLinus Torvalds * Raise ATN while SEL is true before BSY goes false from arbitration, 11591da177e4SLinus Torvalds * since this is the only way to guarantee that we'll get a MESSAGE OUT 11601da177e4SLinus Torvalds * phase immediately after selection. 11611da177e4SLinus Torvalds */ 11621da177e4SLinus Torvalds 11633d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY | 11643d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL); 11651da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds /* 11681da177e4SLinus Torvalds * Reselect interrupts must be turned off prior to the dropping of BSY, 11691da177e4SLinus Torvalds * otherwise we will trigger an interrupt. 11701da177e4SLinus Torvalds */ 11711da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 11721da177e4SLinus Torvalds 117311d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 117411d2f63bSFinn Thain 11751da177e4SLinus Torvalds /* 11761da177e4SLinus Torvalds * The initiator shall then wait at least two deskew delays and release 11771da177e4SLinus Torvalds * the BSY signal. 11781da177e4SLinus Torvalds */ 11791da177e4SLinus Torvalds udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds /* Reset BSY */ 11823d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | 11833d07d22bSFinn Thain ICR_ASSERT_ATN | ICR_ASSERT_SEL); 11841da177e4SLinus Torvalds 11851da177e4SLinus Torvalds /* 11861da177e4SLinus Torvalds * Something weird happens when we cease to drive BSY - looks 11871da177e4SLinus Torvalds * like the board/chip is letting us do another read before the 11881da177e4SLinus Torvalds * appropriate propagation delay has expired, and we're confusing 11891da177e4SLinus Torvalds * a BSY signal from ourselves as the target's response to SELECTION. 11901da177e4SLinus Torvalds * 11911da177e4SLinus Torvalds * A small delay (the 'C++' frontend breaks the pipeline with an 11921da177e4SLinus Torvalds * unnecessary jump, making it work on my 386-33/Trantor T128, the 11931da177e4SLinus Torvalds * tighter 'C' code breaks and requires this) solves the problem - 11941da177e4SLinus Torvalds * the 1 us delay is arbitrary, and only used because this delay will 11951da177e4SLinus Torvalds * be the same on other platforms and since it works here, it should 11961da177e4SLinus Torvalds * work there. 11971da177e4SLinus Torvalds * 11981da177e4SLinus Torvalds * wingel suggests that this could be due to failing to wait 11991da177e4SLinus Torvalds * one deskew delay. 12001da177e4SLinus Torvalds */ 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds udelay(1); 12031da177e4SLinus Torvalds 1204b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd)); 12051da177e4SLinus Torvalds 12061da177e4SLinus Torvalds /* 12071da177e4SLinus Torvalds * The SCSI specification calls for a 250 ms timeout for the actual 12081da177e4SLinus Torvalds * selection. 12091da177e4SLinus Torvalds */ 12101da177e4SLinus Torvalds 1211ae753a33SFinn Thain err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY, 1212ae753a33SFinn Thain msecs_to_jiffies(250)); 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { 121511d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 12161da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 12171da177e4SLinus Torvalds NCR5380_reselect(instance); 1218cd400825SFinn Thain if (!hostdata->connected) 12191da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 12206a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n"); 1221707d62b3SFinn Thain goto out; 12221da177e4SLinus Torvalds } 1223ae753a33SFinn Thain 1224ae753a33SFinn Thain if (err < 0) { 122511d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1226ae753a33SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1227707d62b3SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1228707d62b3SFinn Thain /* Can't touch cmd if it has been reclaimed by the scsi ML */ 1229707d62b3SFinn Thain if (hostdata->selecting) { 1230ae753a33SFinn Thain cmd->result = DID_BAD_TARGET << 16; 1231677e0194SFinn Thain complete_cmd(instance, cmd); 1232707d62b3SFinn Thain dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n"); 1233707d62b3SFinn Thain cmd = NULL; 1234707d62b3SFinn Thain } 1235707d62b3SFinn Thain goto out; 1236ae753a33SFinn Thain } 1237ae753a33SFinn Thain 12381da177e4SLinus Torvalds /* 12391da177e4SLinus Torvalds * No less than two deskew delays after the initiator detects the 12401da177e4SLinus Torvalds * BSY signal is true, it shall release the SEL signal and may 12411da177e4SLinus Torvalds * change the DATA BUS. -wingel 12421da177e4SLinus Torvalds */ 12431da177e4SLinus Torvalds 12441da177e4SLinus Torvalds udelay(1); 12451da177e4SLinus Torvalds 12461da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 12471da177e4SLinus Torvalds 12481da177e4SLinus Torvalds /* 12491da177e4SLinus Torvalds * Since we followed the SCSI spec, and raised ATN while SEL 12501da177e4SLinus Torvalds * was true but before BSY was false during selection, the information 12511da177e4SLinus Torvalds * transfer phase should be a MESSAGE OUT phase so that we can send the 12521da177e4SLinus Torvalds * IDENTIFY message. 12531da177e4SLinus Torvalds */ 12541da177e4SLinus Torvalds 12551da177e4SLinus Torvalds /* Wait for start of REQ/ACK handshake */ 12561da177e4SLinus Torvalds 12571da177e4SLinus Torvalds err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ); 125811d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 12591cc160e1SFinn Thain if (err < 0) { 126055500d9bSFinn Thain shost_printk(KERN_ERR, instance, "select: REQ timeout\n"); 126155500d9bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 12621da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1263707d62b3SFinn Thain goto out; 1264707d62b3SFinn Thain } 1265707d62b3SFinn Thain if (!hostdata->selecting) { 1266707d62b3SFinn Thain do_abort(instance); 1267707d62b3SFinn Thain goto out; 12681da177e4SLinus Torvalds } 12691da177e4SLinus Torvalds 1270b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n", 1271b746545fSFinn Thain scmd_id(cmd)); 127222f5f10dSFinn Thain tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun); 12731da177e4SLinus Torvalds 12741da177e4SLinus Torvalds len = 1; 12751da177e4SLinus Torvalds data = tmp; 12761da177e4SLinus Torvalds phase = PHASE_MSGOUT; 12771da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 1278b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n"); 12791da177e4SLinus Torvalds /* XXX need to handle errors here */ 128011d2f63bSFinn Thain 12811da177e4SLinus Torvalds hostdata->connected = cmd; 12823d07d22bSFinn Thain hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun; 12831da177e4SLinus Torvalds 1284e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1285e9db3198SFinn Thain dregs->csr |= CSR_INTR; 1286e9db3198SFinn Thain #endif 1287e9db3198SFinn Thain 12881da177e4SLinus Torvalds initialize_SCp(cmd); 12891da177e4SLinus Torvalds 1290707d62b3SFinn Thain cmd = NULL; 1291707d62b3SFinn Thain 1292707d62b3SFinn Thain out: 1293707d62b3SFinn Thain if (!hostdata->selecting) 1294707d62b3SFinn Thain return NULL; 1295707d62b3SFinn Thain hostdata->selecting = NULL; 1296707d62b3SFinn Thain return cmd; 12971da177e4SLinus Torvalds } 12981da177e4SLinus Torvalds 12991da177e4SLinus Torvalds /* 13001da177e4SLinus Torvalds * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 13011da177e4SLinus Torvalds * unsigned char *phase, int *count, unsigned char **data) 13021da177e4SLinus Torvalds * 13031da177e4SLinus Torvalds * Purpose : transfers data in given phase using polled I/O 13041da177e4SLinus Torvalds * 13051da177e4SLinus Torvalds * Inputs : instance - instance of driver, *phase - pointer to 13061da177e4SLinus Torvalds * what phase is expected, *count - pointer to number of 13071da177e4SLinus Torvalds * bytes to transfer, **data - pointer to data pointer. 13081da177e4SLinus Torvalds * 13091da177e4SLinus Torvalds * Returns : -1 when different phase is entered without transferring 13100d2cf867SFinn Thain * maximum number of bytes, 0 if all bytes are transferred or exit 13111da177e4SLinus Torvalds * is in same phase. 13121da177e4SLinus Torvalds * 13131da177e4SLinus Torvalds * Also, *phase, *count, *data are modified in place. 13141da177e4SLinus Torvalds * 13151da177e4SLinus Torvalds * XXX Note : handling for bus free may be useful. 13161da177e4SLinus Torvalds */ 13171da177e4SLinus Torvalds 13181da177e4SLinus Torvalds /* 13191da177e4SLinus Torvalds * Note : this code is not as quick as it could be, however it 13201da177e4SLinus Torvalds * IS 100% reliable, and for the actual data transfer where speed 13211da177e4SLinus Torvalds * counts, we will always do a pseudo DMA or DMA transfer. 13221da177e4SLinus Torvalds */ 13231da177e4SLinus Torvalds 13240d2cf867SFinn Thain static int NCR5380_transfer_pio(struct Scsi_Host *instance, 13250d2cf867SFinn Thain unsigned char *phase, int *count, 13260d2cf867SFinn Thain unsigned char **data) 13270d2cf867SFinn Thain { 13281da177e4SLinus Torvalds unsigned char p = *phase, tmp; 13291da177e4SLinus Torvalds int c = *count; 13301da177e4SLinus Torvalds unsigned char *d = *data; 13311da177e4SLinus Torvalds 13321da177e4SLinus Torvalds /* 13331da177e4SLinus Torvalds * The NCR5380 chip will only drive the SCSI bus when the 13341da177e4SLinus Torvalds * phase specified in the appropriate bits of the TARGET COMMAND 13351da177e4SLinus Torvalds * REGISTER match the STATUS REGISTER 13361da177e4SLinus Torvalds */ 13371da177e4SLinus Torvalds 13381da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 13391da177e4SLinus Torvalds 13401da177e4SLinus Torvalds do { 13411da177e4SLinus Torvalds /* 13421da177e4SLinus Torvalds * Wait for assertion of REQ, after which the phase bits will be 13431da177e4SLinus Torvalds * valid 13441da177e4SLinus Torvalds */ 13451da177e4SLinus Torvalds 1346686f3990SFinn Thain if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0) 13471da177e4SLinus Torvalds break; 13481da177e4SLinus Torvalds 1349b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n"); 13501da177e4SLinus Torvalds 13511da177e4SLinus Torvalds /* Check for phase mismatch */ 1352686f3990SFinn Thain if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) { 1353b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "phase mismatch\n"); 1354b746545fSFinn Thain NCR5380_dprint_phase(NDEBUG_PIO, instance); 13551da177e4SLinus Torvalds break; 13561da177e4SLinus Torvalds } 13570d2cf867SFinn Thain 13581da177e4SLinus Torvalds /* Do actual transfer from SCSI bus to / from memory */ 13591da177e4SLinus Torvalds if (!(p & SR_IO)) 13601da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, *d); 13611da177e4SLinus Torvalds else 13621da177e4SLinus Torvalds *d = NCR5380_read(CURRENT_SCSI_DATA_REG); 13631da177e4SLinus Torvalds 13641da177e4SLinus Torvalds ++d; 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds /* 13671da177e4SLinus Torvalds * The SCSI standard suggests that in MSGOUT phase, the initiator 13681da177e4SLinus Torvalds * should drop ATN on the last byte of the message phase 13691da177e4SLinus Torvalds * after REQ has been asserted for the handshake but before 13701da177e4SLinus Torvalds * the initiator raises ACK. 13711da177e4SLinus Torvalds */ 13721da177e4SLinus Torvalds 13731da177e4SLinus Torvalds if (!(p & SR_IO)) { 13741da177e4SLinus Torvalds if (!((p & SR_MSG) && c > 1)) { 13751da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 13761da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 13773d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 13783d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ACK); 13791da177e4SLinus Torvalds } else { 13803d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 13813d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ATN); 13821da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 13833d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 13843d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 13851da177e4SLinus Torvalds } 13861da177e4SLinus Torvalds } else { 13871da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 13881da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); 13891da177e4SLinus Torvalds } 13901da177e4SLinus Torvalds 1391a2edc4a6SFinn Thain if (NCR5380_poll_politely(instance, 1392a2edc4a6SFinn Thain STATUS_REG, SR_REQ, 0, 5 * HZ) < 0) 1393a2edc4a6SFinn Thain break; 1394a2edc4a6SFinn Thain 1395b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n"); 13961da177e4SLinus Torvalds 13971da177e4SLinus Torvalds /* 13981da177e4SLinus Torvalds * We have several special cases to consider during REQ/ACK handshaking : 13991da177e4SLinus Torvalds * 1. We were in MSGOUT phase, and we are on the last byte of the 14001da177e4SLinus Torvalds * message. ATN must be dropped as ACK is dropped. 14011da177e4SLinus Torvalds * 14021da177e4SLinus Torvalds * 2. We are in a MSGIN phase, and we are on the last byte of the 14031da177e4SLinus Torvalds * message. We must exit with ACK asserted, so that the calling 14041da177e4SLinus Torvalds * code may raise ATN before dropping ACK to reject the message. 14051da177e4SLinus Torvalds * 14061da177e4SLinus Torvalds * 3. ACK and ATN are clear and the target may proceed as normal. 14071da177e4SLinus Torvalds */ 14081da177e4SLinus Torvalds if (!(p == PHASE_MSGIN && c == 1)) { 14091da177e4SLinus Torvalds if (p == PHASE_MSGOUT && c > 1) 14101da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 14111da177e4SLinus Torvalds else 14121da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 14131da177e4SLinus Torvalds } 14141da177e4SLinus Torvalds } while (--c); 14151da177e4SLinus Torvalds 1416b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "residual %d\n", c); 14171da177e4SLinus Torvalds 14181da177e4SLinus Torvalds *count = c; 14191da177e4SLinus Torvalds *data = d; 14201da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 1421a2edc4a6SFinn Thain /* The phase read from the bus is valid if either REQ is (already) 1422a2edc4a6SFinn Thain * asserted or if ACK hasn't been released yet. The latter applies if 1423a2edc4a6SFinn Thain * we're in MSG IN, DATA IN or STATUS and all bytes have been received. 1424a2edc4a6SFinn Thain */ 1425a2edc4a6SFinn Thain if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0)) 14261da177e4SLinus Torvalds *phase = tmp & PHASE_MASK; 14271da177e4SLinus Torvalds else 14281da177e4SLinus Torvalds *phase = PHASE_UNKNOWN; 14291da177e4SLinus Torvalds 14301da177e4SLinus Torvalds if (!c || (*phase == p)) 14311da177e4SLinus Torvalds return 0; 14321da177e4SLinus Torvalds else 14331da177e4SLinus Torvalds return -1; 14341da177e4SLinus Torvalds } 14351da177e4SLinus Torvalds 14361da177e4SLinus Torvalds /** 14371da177e4SLinus Torvalds * do_reset - issue a reset command 1438636b1ec8SFinn Thain * @instance: adapter to reset 14391da177e4SLinus Torvalds * 14401da177e4SLinus Torvalds * Issue a reset sequence to the NCR5380 and try and get the bus 14411da177e4SLinus Torvalds * back into sane shape. 14421da177e4SLinus Torvalds * 1443636b1ec8SFinn Thain * This clears the reset interrupt flag because there may be no handler for 1444636b1ec8SFinn Thain * it. When the driver is initialized, the NCR5380_intr() handler has not yet 1445636b1ec8SFinn Thain * been installed. And when in EH we may have released the ST DMA interrupt. 14461da177e4SLinus Torvalds */ 14471da177e4SLinus Torvalds 144854d8fe44SFinn Thain static void do_reset(struct Scsi_Host *instance) 144954d8fe44SFinn Thain { 1450636b1ec8SFinn Thain unsigned long flags; 1451636b1ec8SFinn Thain 1452636b1ec8SFinn Thain local_irq_save(flags); 1453636b1ec8SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 1454636b1ec8SFinn Thain PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); 14551da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); 1456636b1ec8SFinn Thain udelay(50); 14571da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1458636b1ec8SFinn Thain (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); 1459636b1ec8SFinn Thain local_irq_restore(flags); 14601da177e4SLinus Torvalds } 14611da177e4SLinus Torvalds 146280d3eb6dSFinn Thain /** 146380d3eb6dSFinn Thain * do_abort - abort the currently established nexus by going to 146480d3eb6dSFinn Thain * MESSAGE OUT phase and sending an ABORT message. 146580d3eb6dSFinn Thain * @instance: relevant scsi host instance 14661da177e4SLinus Torvalds * 146780d3eb6dSFinn Thain * Returns 0 on success, -1 on failure. 14681da177e4SLinus Torvalds */ 14691da177e4SLinus Torvalds 147054d8fe44SFinn Thain static int do_abort(struct Scsi_Host *instance) 147154d8fe44SFinn Thain { 14721da177e4SLinus Torvalds unsigned char *msgptr, phase, tmp; 14731da177e4SLinus Torvalds int len; 14741da177e4SLinus Torvalds int rc; 14751da177e4SLinus Torvalds 14761da177e4SLinus Torvalds /* Request message out phase */ 14771da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 14781da177e4SLinus Torvalds 14791da177e4SLinus Torvalds /* 14801da177e4SLinus Torvalds * Wait for the target to indicate a valid phase by asserting 14811da177e4SLinus Torvalds * REQ. Once this happens, we'll have either a MSGOUT phase 14821da177e4SLinus Torvalds * and can immediately send the ABORT message, or we'll have some 14831da177e4SLinus Torvalds * other phase and will have to source/sink data. 14841da177e4SLinus Torvalds * 14851da177e4SLinus Torvalds * We really don't care what value was on the bus or what value 14861da177e4SLinus Torvalds * the target sees, so we just handshake. 14871da177e4SLinus Torvalds */ 14881da177e4SLinus Torvalds 148980d3eb6dSFinn Thain rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ); 14901da177e4SLinus Torvalds if (rc < 0) 149180d3eb6dSFinn Thain goto timeout; 14921da177e4SLinus Torvalds 1493f35d3474SFinn Thain tmp = NCR5380_read(STATUS_REG) & PHASE_MASK; 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 14961da177e4SLinus Torvalds 1497f35d3474SFinn Thain if (tmp != PHASE_MSGOUT) { 14980d2cf867SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, 14990d2cf867SFinn Thain ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 150054d8fe44SFinn Thain rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ); 15011cc160e1SFinn Thain if (rc < 0) 150280d3eb6dSFinn Thain goto timeout; 150380d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 15041da177e4SLinus Torvalds } 15050d2cf867SFinn Thain 15061da177e4SLinus Torvalds tmp = ABORT; 15071da177e4SLinus Torvalds msgptr = &tmp; 15081da177e4SLinus Torvalds len = 1; 15091da177e4SLinus Torvalds phase = PHASE_MSGOUT; 151054d8fe44SFinn Thain NCR5380_transfer_pio(instance, &phase, &len, &msgptr); 15111da177e4SLinus Torvalds 15121da177e4SLinus Torvalds /* 15131da177e4SLinus Torvalds * If we got here, and the command completed successfully, 15141da177e4SLinus Torvalds * we're about to go into bus free state. 15151da177e4SLinus Torvalds */ 15161da177e4SLinus Torvalds 15171da177e4SLinus Torvalds return len ? -1 : 0; 151880d3eb6dSFinn Thain 151980d3eb6dSFinn Thain timeout: 152080d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 152180d3eb6dSFinn Thain return -1; 15221da177e4SLinus Torvalds } 15231da177e4SLinus Torvalds 15241da177e4SLinus Torvalds /* 15251da177e4SLinus Torvalds * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 15261da177e4SLinus Torvalds * unsigned char *phase, int *count, unsigned char **data) 15271da177e4SLinus Torvalds * 15281da177e4SLinus Torvalds * Purpose : transfers data in given phase using either real 15291da177e4SLinus Torvalds * or pseudo DMA. 15301da177e4SLinus Torvalds * 15311da177e4SLinus Torvalds * Inputs : instance - instance of driver, *phase - pointer to 15321da177e4SLinus Torvalds * what phase is expected, *count - pointer to number of 15331da177e4SLinus Torvalds * bytes to transfer, **data - pointer to data pointer. 15341da177e4SLinus Torvalds * 15351da177e4SLinus Torvalds * Returns : -1 when different phase is entered without transferring 153625985edcSLucas De Marchi * maximum number of bytes, 0 if all bytes or transferred or exit 15371da177e4SLinus Torvalds * is in same phase. 15381da177e4SLinus Torvalds * 15391da177e4SLinus Torvalds * Also, *phase, *count, *data are modified in place. 15401da177e4SLinus Torvalds */ 15411da177e4SLinus Torvalds 15421da177e4SLinus Torvalds 15430d2cf867SFinn Thain static int NCR5380_transfer_dma(struct Scsi_Host *instance, 15440d2cf867SFinn Thain unsigned char *phase, int *count, 15450d2cf867SFinn Thain unsigned char **data) 15460d2cf867SFinn Thain { 15470d2cf867SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 15481da177e4SLinus Torvalds register int c = *count; 15491da177e4SLinus Torvalds register unsigned char p = *phase; 15501da177e4SLinus Torvalds register unsigned char *d = *data; 15511da177e4SLinus Torvalds unsigned char tmp; 15528053b0eeSFinn Thain int result = 0; 15531da177e4SLinus Torvalds 15541da177e4SLinus Torvalds if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { 15551da177e4SLinus Torvalds *phase = tmp; 15561da177e4SLinus Torvalds return -1; 15571da177e4SLinus Torvalds } 15581da177e4SLinus Torvalds 15598053b0eeSFinn Thain hostdata->connected->SCp.phase = p; 15608053b0eeSFinn Thain 15618053b0eeSFinn Thain if (p & SR_IO) { 15628053b0eeSFinn Thain if (hostdata->read_overruns) 15638053b0eeSFinn Thain c -= hostdata->read_overruns; 15648053b0eeSFinn Thain else if (hostdata->flags & FLAG_DMA_FIXUP) 15658053b0eeSFinn Thain --c; 15668053b0eeSFinn Thain } 15678053b0eeSFinn Thain 15688053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n", 15698053b0eeSFinn Thain (p & SR_IO) ? "receive" : "send", c, d); 15708053b0eeSFinn Thain 1571e9db3198SFinn Thain #ifdef CONFIG_SUN3 1572e9db3198SFinn Thain /* send start chain */ 1573e9db3198SFinn Thain sun3scsi_dma_start(c, *data); 1574e9db3198SFinn Thain #endif 1575e9db3198SFinn Thain 15761da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 1577cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY | 1578cd400825SFinn Thain MR_ENABLE_EOP_INTR); 15791da177e4SLinus Torvalds 15808053b0eeSFinn Thain if (!(hostdata->flags & FLAG_LATE_DMA_SETUP)) { 15818053b0eeSFinn Thain /* On the Medusa, it is a must to initialize the DMA before 15828053b0eeSFinn Thain * starting the NCR. This is also the cleaner way for the TT. 15838053b0eeSFinn Thain */ 15848053b0eeSFinn Thain if (p & SR_IO) 15858053b0eeSFinn Thain result = NCR5380_dma_recv_setup(instance, d, c); 15868053b0eeSFinn Thain else 15878053b0eeSFinn Thain result = NCR5380_dma_send_setup(instance, d, c); 15888053b0eeSFinn Thain } 15891da177e4SLinus Torvalds 15901da177e4SLinus Torvalds /* 15911da177e4SLinus Torvalds * On the PAS16 at least I/O recovery delays are not needed here. 15921da177e4SLinus Torvalds * Everyone else seems to want them. 15931da177e4SLinus Torvalds */ 15941da177e4SLinus Torvalds 15951da177e4SLinus Torvalds if (p & SR_IO) { 1596e9db3198SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1597e5d55d1aSFinn Thain NCR5380_io_delay(1); 15981da177e4SLinus Torvalds NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); 15991da177e4SLinus Torvalds } else { 1600e5d55d1aSFinn Thain NCR5380_io_delay(1); 16011da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 1602e5d55d1aSFinn Thain NCR5380_io_delay(1); 16031da177e4SLinus Torvalds NCR5380_write(START_DMA_SEND_REG, 0); 1604e5d55d1aSFinn Thain NCR5380_io_delay(1); 16051da177e4SLinus Torvalds } 16061da177e4SLinus Torvalds 1607e9db3198SFinn Thain #ifdef CONFIG_SUN3 1608e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1609e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 1610e9db3198SFinn Thain #endif 1611e9db3198SFinn Thain sun3_dma_active = 1; 1612e9db3198SFinn Thain #endif 1613e9db3198SFinn Thain 16148053b0eeSFinn Thain if (hostdata->flags & FLAG_LATE_DMA_SETUP) { 16158053b0eeSFinn Thain /* On the Falcon, the DMA setup must be done after the last 16168053b0eeSFinn Thain * NCR access, else the DMA setup gets trashed! 16178053b0eeSFinn Thain */ 16188053b0eeSFinn Thain if (p & SR_IO) 16198053b0eeSFinn Thain result = NCR5380_dma_recv_setup(instance, d, c); 16208053b0eeSFinn Thain else 16218053b0eeSFinn Thain result = NCR5380_dma_send_setup(instance, d, c); 16228053b0eeSFinn Thain } 16238053b0eeSFinn Thain 16248053b0eeSFinn Thain /* On failure, NCR5380_dma_xxxx_setup() returns a negative int. */ 16258053b0eeSFinn Thain if (result < 0) 16268053b0eeSFinn Thain return result; 16278053b0eeSFinn Thain 16288053b0eeSFinn Thain /* For real DMA, result is the byte count. DMA interrupt is expected. */ 16298053b0eeSFinn Thain if (result > 0) { 16308053b0eeSFinn Thain hostdata->dma_len = result; 16318053b0eeSFinn Thain return 0; 16328053b0eeSFinn Thain } 16338053b0eeSFinn Thain 16348053b0eeSFinn Thain /* The result is zero iff pseudo DMA send/receive was completed. */ 16358053b0eeSFinn Thain hostdata->dma_len = c; 16368053b0eeSFinn Thain 16371da177e4SLinus Torvalds /* 1638e4dec680SFinn Thain * A note regarding the DMA errata workarounds for early NMOS silicon. 1639c16df32eSFinn Thain * 1640c16df32eSFinn Thain * For DMA sends, we want to wait until the last byte has been 1641c16df32eSFinn Thain * transferred out over the bus before we turn off DMA mode. Alas, there 1642c16df32eSFinn Thain * seems to be no terribly good way of doing this on a 5380 under all 1643c16df32eSFinn Thain * conditions. For non-scatter-gather operations, we can wait until REQ 1644c16df32eSFinn Thain * and ACK both go false, or until a phase mismatch occurs. Gather-sends 1645c16df32eSFinn Thain * are nastier, since the device will be expecting more data than we 1646c16df32eSFinn Thain * are prepared to send it, and REQ will remain asserted. On a 53C8[01] we 1647c16df32eSFinn Thain * could test Last Byte Sent to assure transfer (I imagine this is precisely 1648c16df32eSFinn Thain * why this signal was added to the newer chips) but on the older 538[01] 1649c16df32eSFinn Thain * this signal does not exist. The workaround for this lack is a watchdog; 1650c16df32eSFinn Thain * we bail out of the wait-loop after a modest amount of wait-time if 1651c16df32eSFinn Thain * the usual exit conditions are not met. Not a terribly clean or 1652c16df32eSFinn Thain * correct solution :-% 1653c16df32eSFinn Thain * 1654c16df32eSFinn Thain * DMA receive is equally tricky due to a nasty characteristic of the NCR5380. 1655c16df32eSFinn Thain * If the chip is in DMA receive mode, it will respond to a target's 1656c16df32eSFinn Thain * REQ by latching the SCSI data into the INPUT DATA register and asserting 1657c16df32eSFinn Thain * ACK, even if it has _already_ been notified by the DMA controller that 1658c16df32eSFinn Thain * the current DMA transfer has completed! If the NCR5380 is then taken 1659c16df32eSFinn Thain * out of DMA mode, this already-acknowledged byte is lost. This is 1660c16df32eSFinn Thain * not a problem for "one DMA transfer per READ command", because 1661c16df32eSFinn Thain * the situation will never arise... either all of the data is DMA'ed 1662c16df32eSFinn Thain * properly, or the target switches to MESSAGE IN phase to signal a 1663c16df32eSFinn Thain * disconnection (either operation bringing the DMA to a clean halt). 1664c16df32eSFinn Thain * However, in order to handle scatter-receive, we must work around the 1665e4dec680SFinn Thain * problem. The chosen fix is to DMA fewer bytes, then check for the 1666c16df32eSFinn Thain * condition before taking the NCR5380 out of DMA mode. One or two extra 1667c16df32eSFinn Thain * bytes are transferred via PIO as necessary to fill out the original 1668c16df32eSFinn Thain * request. 16691da177e4SLinus Torvalds */ 16701da177e4SLinus Torvalds 16718053b0eeSFinn Thain if (hostdata->flags & FLAG_DMA_FIXUP) { 16721da177e4SLinus Torvalds if (p & SR_IO) { 16731da177e4SLinus Torvalds /* 1674e4dec680SFinn Thain * The workaround was to transfer fewer bytes than we 16751da177e4SLinus Torvalds * intended to with the pseudo-DMA read function, wait for 16761da177e4SLinus Torvalds * the chip to latch the last byte, read it, and then disable 16771da177e4SLinus Torvalds * pseudo-DMA mode. 16781da177e4SLinus Torvalds * 16791da177e4SLinus Torvalds * After REQ is asserted, the NCR5380 asserts DRQ and ACK. 16801da177e4SLinus Torvalds * REQ is deasserted when ACK is asserted, and not reasserted 16811da177e4SLinus Torvalds * until ACK goes false. Since the NCR5380 won't lower ACK 16821da177e4SLinus Torvalds * until DACK is asserted, which won't happen unless we twiddle 16831da177e4SLinus Torvalds * the DMA port or we take the NCR5380 out of DMA mode, we 16841da177e4SLinus Torvalds * can guarantee that we won't handshake another extra 16851da177e4SLinus Torvalds * byte. 16861da177e4SLinus Torvalds */ 16871da177e4SLinus Torvalds 168855181be8SFinn Thain if (NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, 168955181be8SFinn Thain BASR_DRQ, BASR_DRQ, HZ) < 0) { 1690438af51cSFinn Thain result = -1; 169155181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n"); 169255181be8SFinn Thain } 169355181be8SFinn Thain if (NCR5380_poll_politely(instance, STATUS_REG, 169455181be8SFinn Thain SR_REQ, 0, HZ) < 0) { 1695438af51cSFinn Thain result = -1; 169655181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n"); 169755181be8SFinn Thain } 16988053b0eeSFinn Thain d[*count - 1] = NCR5380_read(INPUT_DATA_REG); 16991da177e4SLinus Torvalds } else { 17001da177e4SLinus Torvalds /* 17011da177e4SLinus Torvalds * Wait for the last byte to be sent. If REQ is being asserted for 17021da177e4SLinus Torvalds * the byte we're interested, we'll ACK it and it will go false. 17031da177e4SLinus Torvalds */ 170455181be8SFinn Thain if (NCR5380_poll_politely2(instance, 170555181be8SFinn Thain BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ, 170655181be8SFinn Thain BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) { 1707438af51cSFinn Thain result = -1; 170855181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n"); 17091da177e4SLinus Torvalds } 17101da177e4SLinus Torvalds } 17111da177e4SLinus Torvalds } 17128053b0eeSFinn Thain 17138053b0eeSFinn Thain NCR5380_dma_complete(instance); 1714438af51cSFinn Thain return result; 17151da177e4SLinus Torvalds } 17161da177e4SLinus Torvalds 17171da177e4SLinus Torvalds /* 17181da177e4SLinus Torvalds * Function : NCR5380_information_transfer (struct Scsi_Host *instance) 17191da177e4SLinus Torvalds * 17201da177e4SLinus Torvalds * Purpose : run through the various SCSI phases and do as the target 17211da177e4SLinus Torvalds * directs us to. Operates on the currently connected command, 17221da177e4SLinus Torvalds * instance->connected. 17231da177e4SLinus Torvalds * 17241da177e4SLinus Torvalds * Inputs : instance, instance for which we are doing commands 17251da177e4SLinus Torvalds * 17261da177e4SLinus Torvalds * Side effects : SCSI things happen, the disconnected queue will be 17271da177e4SLinus Torvalds * modified if a command disconnects, *instance->connected will 17281da177e4SLinus Torvalds * change. 17291da177e4SLinus Torvalds * 17301da177e4SLinus Torvalds * XXX Note : we need to watch for bus free or a reset condition here 17311da177e4SLinus Torvalds * to recover from an unexpected bus free condition. 17321da177e4SLinus Torvalds */ 17331da177e4SLinus Torvalds 17340d2cf867SFinn Thain static void NCR5380_information_transfer(struct Scsi_Host *instance) 17350d2cf867SFinn Thain { 1736e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 17371da177e4SLinus Torvalds unsigned char msgout = NOP; 17381da177e4SLinus Torvalds int sink = 0; 17391da177e4SLinus Torvalds int len; 17401da177e4SLinus Torvalds int transfersize; 17411da177e4SLinus Torvalds unsigned char *data; 17421da177e4SLinus Torvalds unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; 174311d2f63bSFinn Thain struct scsi_cmnd *cmd; 17441da177e4SLinus Torvalds 1745e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1746e9db3198SFinn Thain dregs->csr |= CSR_INTR; 1747e9db3198SFinn Thain #endif 1748e9db3198SFinn Thain 174911d2f63bSFinn Thain while ((cmd = hostdata->connected)) { 175032b26a10SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 175132b26a10SFinn Thain 17521da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 17531da177e4SLinus Torvalds /* We only have a valid SCSI phase when REQ is asserted */ 17541da177e4SLinus Torvalds if (tmp & SR_REQ) { 17551da177e4SLinus Torvalds phase = (tmp & PHASE_MASK); 17561da177e4SLinus Torvalds if (phase != old_phase) { 17571da177e4SLinus Torvalds old_phase = phase; 17581da177e4SLinus Torvalds NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); 17591da177e4SLinus Torvalds } 1760e9db3198SFinn Thain #ifdef CONFIG_SUN3 1761e9db3198SFinn Thain if (phase == PHASE_CMDOUT) { 1762e9db3198SFinn Thain void *d; 1763e9db3198SFinn Thain unsigned long count; 1764e9db3198SFinn Thain 1765e9db3198SFinn Thain if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { 1766e9db3198SFinn Thain count = cmd->SCp.buffer->length; 1767e9db3198SFinn Thain d = sg_virt(cmd->SCp.buffer); 1768e9db3198SFinn Thain } else { 1769e9db3198SFinn Thain count = cmd->SCp.this_residual; 1770e9db3198SFinn Thain d = cmd->SCp.ptr; 1771e9db3198SFinn Thain } 1772e9db3198SFinn Thain 1773e9db3198SFinn Thain if (sun3_dma_setup_done != cmd && 1774e9db3198SFinn Thain sun3scsi_dma_xfer_len(count, cmd) > 0) { 1775e9db3198SFinn Thain sun3scsi_dma_setup(instance, d, count, 1776e9db3198SFinn Thain rq_data_dir(cmd->request)); 1777e9db3198SFinn Thain sun3_dma_setup_done = cmd; 1778e9db3198SFinn Thain } 1779e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1780e9db3198SFinn Thain dregs->csr |= CSR_INTR; 1781e9db3198SFinn Thain #endif 1782e9db3198SFinn Thain } 1783e9db3198SFinn Thain #endif /* CONFIG_SUN3 */ 1784e9db3198SFinn Thain 17851da177e4SLinus Torvalds if (sink && (phase != PHASE_MSGOUT)) { 17861da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 17871da177e4SLinus Torvalds 17883d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 17893d07d22bSFinn Thain ICR_ASSERT_ACK); 17900d2cf867SFinn Thain while (NCR5380_read(STATUS_REG) & SR_REQ) 17910d2cf867SFinn Thain ; 17923d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 17933d07d22bSFinn Thain ICR_ASSERT_ATN); 17941da177e4SLinus Torvalds sink = 0; 17951da177e4SLinus Torvalds continue; 17961da177e4SLinus Torvalds } 17970d2cf867SFinn Thain 17981da177e4SLinus Torvalds switch (phase) { 17991da177e4SLinus Torvalds case PHASE_DATAOUT: 18001da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_DATAOUT) 18016a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n"); 18021da177e4SLinus Torvalds sink = 1; 18031da177e4SLinus Torvalds do_abort(instance); 18041da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 1805677e0194SFinn Thain complete_cmd(instance, cmd); 1806dc183965SFinn Thain hostdata->connected = NULL; 18071da177e4SLinus Torvalds return; 18081da177e4SLinus Torvalds #endif 1809bf1a0c6fSFinn Thain case PHASE_DATAIN: 18101da177e4SLinus Torvalds /* 18111da177e4SLinus Torvalds * If there is no room left in the current buffer in the 18121da177e4SLinus Torvalds * scatter-gather list, move onto the next one. 18131da177e4SLinus Torvalds */ 18141da177e4SLinus Torvalds 18151da177e4SLinus Torvalds if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { 18161da177e4SLinus Torvalds ++cmd->SCp.buffer; 18171da177e4SLinus Torvalds --cmd->SCp.buffers_residual; 18181da177e4SLinus Torvalds cmd->SCp.this_residual = cmd->SCp.buffer->length; 181945711f1aSJens Axboe cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 1820b746545fSFinn Thain dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n", 1821b746545fSFinn Thain cmd->SCp.this_residual, 1822b746545fSFinn Thain cmd->SCp.buffers_residual); 18231da177e4SLinus Torvalds } 18240d2cf867SFinn Thain 18251da177e4SLinus Torvalds /* 18261da177e4SLinus Torvalds * The preferred transfer method is going to be 18271da177e4SLinus Torvalds * PSEUDO-DMA for systems that are strictly PIO, 18281da177e4SLinus Torvalds * since we can let the hardware do the handshaking. 18291da177e4SLinus Torvalds * 18301da177e4SLinus Torvalds * For this to work, we need to know the transfersize 18311da177e4SLinus Torvalds * ahead of time, since the pseudo-DMA code will sit 18321da177e4SLinus Torvalds * in an unconditional loop. 18331da177e4SLinus Torvalds */ 18341da177e4SLinus Torvalds 1835ff3d4578SFinn Thain transfersize = 0; 18367e9ec8d9SFinn Thain if (!cmd->device->borken) 1837ff3d4578SFinn Thain transfersize = NCR5380_dma_xfer_len(instance, cmd, phase); 18381da177e4SLinus Torvalds 1839438af51cSFinn Thain if (transfersize > 0) { 18401da177e4SLinus Torvalds len = transfersize; 18410d2cf867SFinn Thain if (NCR5380_transfer_dma(instance, &phase, 18420d2cf867SFinn Thain &len, (unsigned char **)&cmd->SCp.ptr)) { 18431da177e4SLinus Torvalds /* 18440d2cf867SFinn Thain * If the watchdog timer fires, all future 18450d2cf867SFinn Thain * accesses to this device will use the 18460d2cf867SFinn Thain * polled-IO. 18471da177e4SLinus Torvalds */ 1848017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 1849017560fcSJeff Garzik "switching to slow handshake\n"); 18501da177e4SLinus Torvalds cmd->device->borken = 1; 18511da177e4SLinus Torvalds sink = 1; 18521da177e4SLinus Torvalds do_abort(instance); 18531da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 18541da177e4SLinus Torvalds /* XXX - need to source or sink data here, as appropriate */ 18558053b0eeSFinn Thain } 1856f825e40bSFinn Thain } else { 18571678847eSFinn Thain /* Break up transfer into 3 ms chunks, 18581678847eSFinn Thain * presuming 6 accesses per handshake. 18591678847eSFinn Thain */ 18601678847eSFinn Thain transfersize = min((unsigned long)cmd->SCp.this_residual, 18611678847eSFinn Thain hostdata->accesses_per_ms / 2); 18621678847eSFinn Thain len = transfersize; 18631678847eSFinn Thain NCR5380_transfer_pio(instance, &phase, &len, 18643d07d22bSFinn Thain (unsigned char **)&cmd->SCp.ptr); 18651678847eSFinn Thain cmd->SCp.this_residual -= transfersize - len; 186611d2f63bSFinn Thain } 1867e9db3198SFinn Thain #ifdef CONFIG_SUN3 1868e9db3198SFinn Thain if (sun3_dma_setup_done == cmd) 1869e9db3198SFinn Thain sun3_dma_setup_done = NULL; 1870e9db3198SFinn Thain #endif 18711678847eSFinn Thain return; 18721da177e4SLinus Torvalds case PHASE_MSGIN: 18731da177e4SLinus Torvalds len = 1; 18741da177e4SLinus Torvalds data = &tmp; 18751da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 18761da177e4SLinus Torvalds cmd->SCp.Message = tmp; 18771da177e4SLinus Torvalds 18781da177e4SLinus Torvalds switch (tmp) { 18791da177e4SLinus Torvalds case ABORT: 18801da177e4SLinus Torvalds case COMMAND_COMPLETE: 18811da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18821da177e4SLinus Torvalds sink = 1; 18831da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18840d3d9a42SFinn Thain dsprintk(NDEBUG_QUEUES, instance, 18850d3d9a42SFinn Thain "COMMAND COMPLETE %p target %d lun %llu\n", 18860d3d9a42SFinn Thain cmd, scmd_id(cmd), cmd->device->lun); 18870d3d9a42SFinn Thain 18881da177e4SLinus Torvalds hostdata->connected = NULL; 18891da177e4SLinus Torvalds 1890f27db8ebSFinn Thain cmd->result &= ~0xffff; 1891f27db8ebSFinn Thain cmd->result |= cmd->SCp.Status; 1892f27db8ebSFinn Thain cmd->result |= cmd->SCp.Message << 8; 18931da177e4SLinus Torvalds 1894f27db8ebSFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 1895f27db8ebSFinn Thain complete_cmd(instance, cmd); 1896f27db8ebSFinn Thain else { 1897f27db8ebSFinn Thain if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION || 1898f27db8ebSFinn Thain cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) { 1899f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n", 1900dbb6b350SFinn Thain cmd); 1901f27db8ebSFinn Thain list_add_tail(&ncmd->list, 1902f27db8ebSFinn Thain &hostdata->autosense); 1903f27db8ebSFinn Thain } else 1904677e0194SFinn Thain complete_cmd(instance, cmd); 19051da177e4SLinus Torvalds } 19061da177e4SLinus Torvalds 19071da177e4SLinus Torvalds /* 19081da177e4SLinus Torvalds * Restore phase bits to 0 so an interrupted selection, 19091da177e4SLinus Torvalds * arbitration can resume. 19101da177e4SLinus Torvalds */ 19111da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 191272064a78SFinn Thain 191372064a78SFinn Thain /* Enable reselect interrupts */ 191472064a78SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 191552d3e561SFinn Thain 191652d3e561SFinn Thain maybe_release_dma_irq(instance); 19171da177e4SLinus Torvalds return; 19181da177e4SLinus Torvalds case MESSAGE_REJECT: 19191da177e4SLinus Torvalds /* Accept message by clearing ACK */ 19201da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 19211da177e4SLinus Torvalds switch (hostdata->last_message) { 19221da177e4SLinus Torvalds case HEAD_OF_QUEUE_TAG: 19231da177e4SLinus Torvalds case ORDERED_QUEUE_TAG: 19241da177e4SLinus Torvalds case SIMPLE_QUEUE_TAG: 19251da177e4SLinus Torvalds cmd->device->simple_tags = 0; 19269cb78c16SHannes Reinecke hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF)); 19271da177e4SLinus Torvalds break; 19281da177e4SLinus Torvalds default: 19291da177e4SLinus Torvalds break; 19301da177e4SLinus Torvalds } 1931340b9612SFinn Thain break; 19320d2cf867SFinn Thain case DISCONNECT: 19331da177e4SLinus Torvalds /* Accept message by clearing ACK */ 19341da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 19351da177e4SLinus Torvalds hostdata->connected = NULL; 193632b26a10SFinn Thain list_add(&ncmd->list, &hostdata->disconnected); 19370d3d9a42SFinn Thain dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES, 19380d3d9a42SFinn Thain instance, "connected command %p for target %d lun %llu moved to disconnected queue\n", 19390d3d9a42SFinn Thain cmd, scmd_id(cmd), cmd->device->lun); 19400d3d9a42SFinn Thain 19411da177e4SLinus Torvalds /* 19421da177e4SLinus Torvalds * Restore phase bits to 0 so an interrupted selection, 19431da177e4SLinus Torvalds * arbitration can resume. 19441da177e4SLinus Torvalds */ 19451da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 19461da177e4SLinus Torvalds 19471da177e4SLinus Torvalds /* Enable reselect interrupts */ 19481da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1949e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1950e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 1951e9db3198SFinn Thain #endif 19521da177e4SLinus Torvalds return; 19531da177e4SLinus Torvalds /* 19541da177e4SLinus Torvalds * The SCSI data pointer is *IMPLICITLY* saved on a disconnect 19551da177e4SLinus Torvalds * operation, in violation of the SCSI spec so we can safely 19561da177e4SLinus Torvalds * ignore SAVE/RESTORE pointers calls. 19571da177e4SLinus Torvalds * 19581da177e4SLinus Torvalds * Unfortunately, some disks violate the SCSI spec and 19591da177e4SLinus Torvalds * don't issue the required SAVE_POINTERS message before 19601da177e4SLinus Torvalds * disconnecting, and we have to break spec to remain 19611da177e4SLinus Torvalds * compatible. 19621da177e4SLinus Torvalds */ 19631da177e4SLinus Torvalds case SAVE_POINTERS: 19641da177e4SLinus Torvalds case RESTORE_POINTERS: 19651da177e4SLinus Torvalds /* Accept message by clearing ACK */ 19661da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 19671da177e4SLinus Torvalds break; 19681da177e4SLinus Torvalds case EXTENDED_MESSAGE: 19691da177e4SLinus Torvalds /* 1970c16df32eSFinn Thain * Start the message buffer with the EXTENDED_MESSAGE 19711abfd370SMatthew Wilcox * byte, since spi_print_msg() wants the whole thing. 19721da177e4SLinus Torvalds */ 19731da177e4SLinus Torvalds extended_msg[0] = EXTENDED_MESSAGE; 19741da177e4SLinus Torvalds /* Accept first byte by clearing ACK */ 19751da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 197611d2f63bSFinn Thain 197711d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 197811d2f63bSFinn Thain 1979b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n"); 19801da177e4SLinus Torvalds 19811da177e4SLinus Torvalds len = 2; 19821da177e4SLinus Torvalds data = extended_msg + 1; 19831da177e4SLinus Torvalds phase = PHASE_MSGIN; 19841da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 1985b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n", 1986b746545fSFinn Thain (int)extended_msg[1], 1987b746545fSFinn Thain (int)extended_msg[2]); 19881da177e4SLinus Torvalds 1989e0783ed3SFinn Thain if (!len && extended_msg[1] > 0 && 1990e0783ed3SFinn Thain extended_msg[1] <= sizeof(extended_msg) - 2) { 19911da177e4SLinus Torvalds /* Accept third byte by clearing ACK */ 19921da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 19931da177e4SLinus Torvalds len = extended_msg[1] - 1; 19941da177e4SLinus Torvalds data = extended_msg + 3; 19951da177e4SLinus Torvalds phase = PHASE_MSGIN; 19961da177e4SLinus Torvalds 19971da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 1998b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n", 1999b746545fSFinn Thain len); 20001da177e4SLinus Torvalds 20011da177e4SLinus Torvalds switch (extended_msg[2]) { 20021da177e4SLinus Torvalds case EXTENDED_SDTR: 20031da177e4SLinus Torvalds case EXTENDED_WDTR: 20041da177e4SLinus Torvalds case EXTENDED_MODIFY_DATA_POINTER: 20051da177e4SLinus Torvalds case EXTENDED_EXTENDED_IDENTIFY: 20061da177e4SLinus Torvalds tmp = 0; 20071da177e4SLinus Torvalds } 20081da177e4SLinus Torvalds } else if (len) { 20096a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "error receiving extended message\n"); 20101da177e4SLinus Torvalds tmp = 0; 20111da177e4SLinus Torvalds } else { 20126a6ff4acSFinn Thain shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n", 20136a6ff4acSFinn Thain extended_msg[2], extended_msg[1]); 20141da177e4SLinus Torvalds tmp = 0; 20151da177e4SLinus Torvalds } 201611d2f63bSFinn Thain 201711d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 201811d2f63bSFinn Thain if (!hostdata->connected) 201911d2f63bSFinn Thain return; 202011d2f63bSFinn Thain 20211da177e4SLinus Torvalds /* Fall through to reject message */ 20221da177e4SLinus Torvalds 20231da177e4SLinus Torvalds /* 20241da177e4SLinus Torvalds * If we get something weird that we aren't expecting, 20251da177e4SLinus Torvalds * reject it. 20261da177e4SLinus Torvalds */ 20271da177e4SLinus Torvalds default: 20281da177e4SLinus Torvalds if (!tmp) { 20296a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "rejecting message "); 20301abfd370SMatthew Wilcox spi_print_msg(extended_msg); 20311da177e4SLinus Torvalds printk("\n"); 20321da177e4SLinus Torvalds } else if (tmp != EXTENDED_MESSAGE) 2033017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 20340d2cf867SFinn Thain "rejecting unknown message %02x\n", 20350d2cf867SFinn Thain tmp); 20361da177e4SLinus Torvalds else 2037017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 20380d2cf867SFinn Thain "rejecting unknown extended message code %02x, length %d\n", 20390d2cf867SFinn Thain extended_msg[1], extended_msg[0]); 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds msgout = MESSAGE_REJECT; 20421da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 20431da177e4SLinus Torvalds break; 20441da177e4SLinus Torvalds } /* switch (tmp) */ 20451da177e4SLinus Torvalds break; 20461da177e4SLinus Torvalds case PHASE_MSGOUT: 20471da177e4SLinus Torvalds len = 1; 20481da177e4SLinus Torvalds data = &msgout; 20491da177e4SLinus Torvalds hostdata->last_message = msgout; 20501da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 20511da177e4SLinus Torvalds if (msgout == ABORT) { 20521da177e4SLinus Torvalds hostdata->connected = NULL; 20531da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 2054677e0194SFinn Thain complete_cmd(instance, cmd); 205552d3e561SFinn Thain maybe_release_dma_irq(instance); 20561da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 20571da177e4SLinus Torvalds return; 20581da177e4SLinus Torvalds } 20591da177e4SLinus Torvalds msgout = NOP; 20601da177e4SLinus Torvalds break; 20611da177e4SLinus Torvalds case PHASE_CMDOUT: 20621da177e4SLinus Torvalds len = cmd->cmd_len; 20631da177e4SLinus Torvalds data = cmd->cmnd; 20641da177e4SLinus Torvalds /* 20651da177e4SLinus Torvalds * XXX for performance reasons, on machines with a 20661da177e4SLinus Torvalds * PSEUDO-DMA architecture we should probably 20671da177e4SLinus Torvalds * use the dma transfer function. 20681da177e4SLinus Torvalds */ 20691da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 20701da177e4SLinus Torvalds break; 20711da177e4SLinus Torvalds case PHASE_STATIN: 20721da177e4SLinus Torvalds len = 1; 20731da177e4SLinus Torvalds data = &tmp; 20741da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 20751da177e4SLinus Torvalds cmd->SCp.Status = tmp; 20761da177e4SLinus Torvalds break; 20771da177e4SLinus Torvalds default: 20786a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "unknown phase\n"); 20794dde8f7dSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 20801da177e4SLinus Torvalds } /* switch(phase) */ 2081686f3990SFinn Thain } else { 208211d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 2083686f3990SFinn Thain NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ); 208411d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 20851da177e4SLinus Torvalds } 208611d2f63bSFinn Thain } 20871da177e4SLinus Torvalds } 20881da177e4SLinus Torvalds 20891da177e4SLinus Torvalds /* 20901da177e4SLinus Torvalds * Function : void NCR5380_reselect (struct Scsi_Host *instance) 20911da177e4SLinus Torvalds * 20921da177e4SLinus Torvalds * Purpose : does reselection, initializing the instance->connected 2093710ddd0dSFinn Thain * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q 20941da177e4SLinus Torvalds * nexus has been reestablished, 20951da177e4SLinus Torvalds * 20961da177e4SLinus Torvalds * Inputs : instance - this instance of the NCR5380. 20971da177e4SLinus Torvalds */ 20981da177e4SLinus Torvalds 20990d2cf867SFinn Thain static void NCR5380_reselect(struct Scsi_Host *instance) 21000d2cf867SFinn Thain { 2101e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 21021da177e4SLinus Torvalds unsigned char target_mask; 2103e9db3198SFinn Thain unsigned char lun; 21041da177e4SLinus Torvalds unsigned char msg[3]; 210532b26a10SFinn Thain struct NCR5380_cmd *ncmd; 210632b26a10SFinn Thain struct scsi_cmnd *tmp; 21071da177e4SLinus Torvalds 21081da177e4SLinus Torvalds /* 21091da177e4SLinus Torvalds * Disable arbitration, etc. since the host adapter obviously 21101da177e4SLinus Torvalds * lost, and tell an interrupted NCR5380_select() to restart. 21111da177e4SLinus Torvalds */ 21121da177e4SLinus Torvalds 21131da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 21141da177e4SLinus Torvalds 21151da177e4SLinus Torvalds target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); 2116b746545fSFinn Thain 2117b746545fSFinn Thain dsprintk(NDEBUG_RESELECTION, instance, "reselect\n"); 21181da177e4SLinus Torvalds 21191da177e4SLinus Torvalds /* 21201da177e4SLinus Torvalds * At this point, we have detected that our SCSI ID is on the bus, 21211da177e4SLinus Torvalds * SEL is true and BSY was false for at least one bus settle delay 21221da177e4SLinus Torvalds * (400 ns). 21231da177e4SLinus Torvalds * 21241da177e4SLinus Torvalds * We must assert BSY ourselves, until the target drops the SEL 21251da177e4SLinus Torvalds * signal. 21261da177e4SLinus Torvalds */ 21271da177e4SLinus Torvalds 21281da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); 212972064a78SFinn Thain if (NCR5380_poll_politely(instance, 213072064a78SFinn Thain STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) { 213172064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 213272064a78SFinn Thain return; 213372064a78SFinn Thain } 21341da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 21351da177e4SLinus Torvalds 21361da177e4SLinus Torvalds /* 21371da177e4SLinus Torvalds * Wait for target to go into MSGIN. 21381da177e4SLinus Torvalds */ 21391da177e4SLinus Torvalds 21401cc160e1SFinn Thain if (NCR5380_poll_politely(instance, 214172064a78SFinn Thain STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) { 214272064a78SFinn Thain do_abort(instance); 214372064a78SFinn Thain return; 214472064a78SFinn Thain } 21451da177e4SLinus Torvalds 2146e9db3198SFinn Thain #ifdef CONFIG_SUN3 2147e9db3198SFinn Thain /* acknowledge toggle to MSGIN */ 2148e9db3198SFinn Thain NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN)); 2149e9db3198SFinn Thain 2150e9db3198SFinn Thain /* peek at the byte without really hitting the bus */ 2151e9db3198SFinn Thain msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG); 2152e9db3198SFinn Thain #else 2153e9db3198SFinn Thain { 2154e9db3198SFinn Thain int len = 1; 2155e9db3198SFinn Thain unsigned char *data = msg; 2156e9db3198SFinn Thain unsigned char phase = PHASE_MSGIN; 2157e9db3198SFinn Thain 21581da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 21591da177e4SLinus Torvalds 216072064a78SFinn Thain if (len) { 216172064a78SFinn Thain do_abort(instance); 216272064a78SFinn Thain return; 216372064a78SFinn Thain } 2164e9db3198SFinn Thain } 2165e9db3198SFinn Thain #endif /* CONFIG_SUN3 */ 216672064a78SFinn Thain 21671da177e4SLinus Torvalds if (!(msg[0] & 0x80)) { 216872064a78SFinn Thain shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got "); 21691abfd370SMatthew Wilcox spi_print_msg(msg); 217072064a78SFinn Thain printk("\n"); 217172064a78SFinn Thain do_abort(instance); 217272064a78SFinn Thain return; 217372064a78SFinn Thain } 217472064a78SFinn Thain lun = msg[0] & 0x07; 21751da177e4SLinus Torvalds 21761da177e4SLinus Torvalds /* 21771da177e4SLinus Torvalds * We need to add code for SCSI-II to track which devices have 21781da177e4SLinus Torvalds * I_T_L_Q nexuses established, and which have simple I_T_L 21791da177e4SLinus Torvalds * nexuses so we can chose to do additional data transfer. 21801da177e4SLinus Torvalds */ 21811da177e4SLinus Torvalds 21821da177e4SLinus Torvalds /* 21831da177e4SLinus Torvalds * Find the command corresponding to the I_T_L or I_T_L_Q nexus we 21841da177e4SLinus Torvalds * just reestablished, and remove it from the disconnected queue. 21851da177e4SLinus Torvalds */ 21861da177e4SLinus Torvalds 218732b26a10SFinn Thain tmp = NULL; 218832b26a10SFinn Thain list_for_each_entry(ncmd, &hostdata->disconnected, list) { 218932b26a10SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 219032b26a10SFinn Thain 219132b26a10SFinn Thain if (target_mask == (1 << scmd_id(cmd)) && 219232b26a10SFinn Thain lun == (u8)cmd->device->lun) { 219332b26a10SFinn Thain list_del(&ncmd->list); 219432b26a10SFinn Thain tmp = cmd; 21951da177e4SLinus Torvalds break; 21961da177e4SLinus Torvalds } 219772064a78SFinn Thain } 21980d3d9a42SFinn Thain 21990d3d9a42SFinn Thain if (tmp) { 22000d3d9a42SFinn Thain dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance, 22010d3d9a42SFinn Thain "reselect: removed %p from disconnected queue\n", tmp); 22020d3d9a42SFinn Thain } else { 220372064a78SFinn Thain shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n", 220472064a78SFinn Thain target_mask, lun); 22051da177e4SLinus Torvalds /* 22060d2cf867SFinn Thain * Since we have an established nexus that we can't do anything 22070d2cf867SFinn Thain * with, we must abort it. 22081da177e4SLinus Torvalds */ 220972064a78SFinn Thain do_abort(instance); 221072064a78SFinn Thain return; 22111da177e4SLinus Torvalds } 22121da177e4SLinus Torvalds 2213e9db3198SFinn Thain #ifdef CONFIG_SUN3 2214e9db3198SFinn Thain { 2215e9db3198SFinn Thain void *d; 2216e9db3198SFinn Thain unsigned long count; 2217e9db3198SFinn Thain 2218e9db3198SFinn Thain if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) { 2219e9db3198SFinn Thain count = tmp->SCp.buffer->length; 2220e9db3198SFinn Thain d = sg_virt(tmp->SCp.buffer); 2221e9db3198SFinn Thain } else { 2222e9db3198SFinn Thain count = tmp->SCp.this_residual; 2223e9db3198SFinn Thain d = tmp->SCp.ptr; 2224e9db3198SFinn Thain } 2225e9db3198SFinn Thain 2226e9db3198SFinn Thain if (sun3_dma_setup_done != tmp && 2227e9db3198SFinn Thain sun3scsi_dma_xfer_len(count, tmp) > 0) { 2228e9db3198SFinn Thain sun3scsi_dma_setup(instance, d, count, 2229e9db3198SFinn Thain rq_data_dir(tmp->request)); 2230e9db3198SFinn Thain sun3_dma_setup_done = tmp; 2231e9db3198SFinn Thain } 2232e9db3198SFinn Thain } 2233e9db3198SFinn Thain 2234e9db3198SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); 2235e9db3198SFinn Thain #endif /* CONFIG_SUN3 */ 2236e9db3198SFinn Thain 223772064a78SFinn Thain /* Accept message by clearing ACK */ 223872064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 223972064a78SFinn Thain 22401da177e4SLinus Torvalds hostdata->connected = tmp; 2241*c4ec6f92SFinn Thain dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu\n", 2242*c4ec6f92SFinn Thain scmd_id(tmp), tmp->device->lun); 22431da177e4SLinus Torvalds } 22441da177e4SLinus Torvalds 22458b00c3d5SFinn Thain /** 22468b00c3d5SFinn Thain * list_find_cmd - test for presence of a command in a linked list 22478b00c3d5SFinn Thain * @haystack: list of commands 22488b00c3d5SFinn Thain * @needle: command to search for 22498b00c3d5SFinn Thain */ 22508b00c3d5SFinn Thain 22518b00c3d5SFinn Thain static bool list_find_cmd(struct list_head *haystack, 22528b00c3d5SFinn Thain struct scsi_cmnd *needle) 22538b00c3d5SFinn Thain { 22548b00c3d5SFinn Thain struct NCR5380_cmd *ncmd; 22558b00c3d5SFinn Thain 22568b00c3d5SFinn Thain list_for_each_entry(ncmd, haystack, list) 22578b00c3d5SFinn Thain if (NCR5380_to_scmd(ncmd) == needle) 22588b00c3d5SFinn Thain return true; 22598b00c3d5SFinn Thain return false; 22608b00c3d5SFinn Thain } 22618b00c3d5SFinn Thain 22628b00c3d5SFinn Thain /** 22638b00c3d5SFinn Thain * list_remove_cmd - remove a command from linked list 22648b00c3d5SFinn Thain * @haystack: list of commands 22658b00c3d5SFinn Thain * @needle: command to remove 22668b00c3d5SFinn Thain */ 22678b00c3d5SFinn Thain 22688b00c3d5SFinn Thain static bool list_del_cmd(struct list_head *haystack, 22698b00c3d5SFinn Thain struct scsi_cmnd *needle) 22708b00c3d5SFinn Thain { 22718b00c3d5SFinn Thain if (list_find_cmd(haystack, needle)) { 22728b00c3d5SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle); 22738b00c3d5SFinn Thain 22748b00c3d5SFinn Thain list_del(&ncmd->list); 22758b00c3d5SFinn Thain return true; 22768b00c3d5SFinn Thain } 22778b00c3d5SFinn Thain return false; 22788b00c3d5SFinn Thain } 22798b00c3d5SFinn Thain 22808b00c3d5SFinn Thain /** 22818b00c3d5SFinn Thain * NCR5380_abort - scsi host eh_abort_handler() method 22828b00c3d5SFinn Thain * @cmd: the command to be aborted 22831da177e4SLinus Torvalds * 22848b00c3d5SFinn Thain * Try to abort a given command by removing it from queues and/or sending 22858b00c3d5SFinn Thain * the target an abort message. This may not succeed in causing a target 22868b00c3d5SFinn Thain * to abort the command. Nonetheless, the low-level driver must forget about 22878b00c3d5SFinn Thain * the command because the mid-layer reclaims it and it may be re-issued. 22881da177e4SLinus Torvalds * 22898b00c3d5SFinn Thain * The normal path taken by a command is as follows. For EH we trace this 22908b00c3d5SFinn Thain * same path to locate and abort the command. 22911da177e4SLinus Torvalds * 22928b00c3d5SFinn Thain * unissued -> selecting -> [unissued -> selecting ->]... connected -> 22938b00c3d5SFinn Thain * [disconnected -> connected ->]... 22948b00c3d5SFinn Thain * [autosense -> connected ->] done 22951da177e4SLinus Torvalds * 22968b00c3d5SFinn Thain * If cmd was not found at all then presumably it has already been completed, 22978b00c3d5SFinn Thain * in which case return SUCCESS to try to avoid further EH measures. 2298dc183965SFinn Thain * 22998b00c3d5SFinn Thain * If the command has not completed yet, we must not fail to find it. 2300dc183965SFinn Thain * We have no option but to forget the aborted command (even if it still 2301dc183965SFinn Thain * lacks sense data). The mid-layer may re-issue a command that is in error 2302dc183965SFinn Thain * recovery (see scsi_send_eh_cmnd), but the logic and data structures in 2303dc183965SFinn Thain * this driver are such that a command can appear on one queue only. 230471a00593SFinn Thain * 230571a00593SFinn Thain * The lock protects driver data structures, but EH handlers also use it 230671a00593SFinn Thain * to serialize their own execution and prevent their own re-entry. 23071da177e4SLinus Torvalds */ 23081da177e4SLinus Torvalds 2309710ddd0dSFinn Thain static int NCR5380_abort(struct scsi_cmnd *cmd) 2310710ddd0dSFinn Thain { 23111da177e4SLinus Torvalds struct Scsi_Host *instance = cmd->device->host; 2312e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 231311d2f63bSFinn Thain unsigned long flags; 23148b00c3d5SFinn Thain int result = SUCCESS; 23151da177e4SLinus Torvalds 231611d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 231711d2f63bSFinn Thain 231832b26a10SFinn Thain #if (NDEBUG & NDEBUG_ANY) 23198b00c3d5SFinn Thain scmd_printk(KERN_INFO, cmd, __func__); 232032b26a10SFinn Thain #endif 2321e5c3fddfSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 2322e5c3fddfSFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 23231da177e4SLinus Torvalds 23248b00c3d5SFinn Thain if (list_del_cmd(&hostdata->unissued, cmd)) { 23258b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 23268b00c3d5SFinn Thain "abort: removed %p from issue queue\n", cmd); 23278b00c3d5SFinn Thain cmd->result = DID_ABORT << 16; 23288b00c3d5SFinn Thain cmd->scsi_done(cmd); /* No tag or busy flag to worry about */ 2329dc183965SFinn Thain goto out; 23308b00c3d5SFinn Thain } 23318b00c3d5SFinn Thain 2332707d62b3SFinn Thain if (hostdata->selecting == cmd) { 2333707d62b3SFinn Thain dsprintk(NDEBUG_ABORT, instance, 2334707d62b3SFinn Thain "abort: cmd %p == selecting\n", cmd); 2335707d62b3SFinn Thain hostdata->selecting = NULL; 2336707d62b3SFinn Thain cmd->result = DID_ABORT << 16; 2337707d62b3SFinn Thain complete_cmd(instance, cmd); 2338707d62b3SFinn Thain goto out; 2339707d62b3SFinn Thain } 2340707d62b3SFinn Thain 23418b00c3d5SFinn Thain if (list_del_cmd(&hostdata->disconnected, cmd)) { 23428b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 23438b00c3d5SFinn Thain "abort: removed %p from disconnected list\n", cmd); 234471a00593SFinn Thain /* Can't call NCR5380_select() and send ABORT because that 234571a00593SFinn Thain * means releasing the lock. Need a bus reset. 234671a00593SFinn Thain */ 2347dc183965SFinn Thain set_host_byte(cmd, DID_ERROR); 2348dc183965SFinn Thain complete_cmd(instance, cmd); 23498b00c3d5SFinn Thain result = FAILED; 23508b00c3d5SFinn Thain goto out; 23518b00c3d5SFinn Thain } 23528b00c3d5SFinn Thain 23538b00c3d5SFinn Thain if (hostdata->connected == cmd) { 23548b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); 23558b00c3d5SFinn Thain hostdata->connected = NULL; 2356dc183965SFinn Thain hostdata->dma_len = 0; 23578b00c3d5SFinn Thain if (do_abort(instance)) { 23588b00c3d5SFinn Thain set_host_byte(cmd, DID_ERROR); 23598b00c3d5SFinn Thain complete_cmd(instance, cmd); 23608b00c3d5SFinn Thain result = FAILED; 23618b00c3d5SFinn Thain goto out; 23628b00c3d5SFinn Thain } 23638b00c3d5SFinn Thain set_host_byte(cmd, DID_ABORT); 23648b00c3d5SFinn Thain complete_cmd(instance, cmd); 2365dc183965SFinn Thain goto out; 23668b00c3d5SFinn Thain } 23678b00c3d5SFinn Thain 23688b00c3d5SFinn Thain if (list_del_cmd(&hostdata->autosense, cmd)) { 23698b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 23708b00c3d5SFinn Thain "abort: removed %p from sense queue\n", cmd); 23718b00c3d5SFinn Thain set_host_byte(cmd, DID_ERROR); 23728b00c3d5SFinn Thain complete_cmd(instance, cmd); 23738b00c3d5SFinn Thain } 23748b00c3d5SFinn Thain 23758b00c3d5SFinn Thain out: 23768b00c3d5SFinn Thain if (result == FAILED) 23778b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd); 23788b00c3d5SFinn Thain else 23798b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd); 23808b00c3d5SFinn Thain 23818b00c3d5SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 238252d3e561SFinn Thain maybe_release_dma_irq(instance); 238311d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 23841da177e4SLinus Torvalds 23858b00c3d5SFinn Thain return result; 23861da177e4SLinus Torvalds } 23871da177e4SLinus Torvalds 23881da177e4SLinus Torvalds 23893be1b3eaSFinn Thain /** 23903be1b3eaSFinn Thain * NCR5380_bus_reset - reset the SCSI bus 23913be1b3eaSFinn Thain * @cmd: SCSI command undergoing EH 23921da177e4SLinus Torvalds * 23933be1b3eaSFinn Thain * Returns SUCCESS 23941da177e4SLinus Torvalds */ 23951da177e4SLinus Torvalds 2396710ddd0dSFinn Thain static int NCR5380_bus_reset(struct scsi_cmnd *cmd) 239768b3aa7cSJeff Garzik { 239868b3aa7cSJeff Garzik struct Scsi_Host *instance = cmd->device->host; 239911d2f63bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 240062717f53SFinn Thain int i; 240111d2f63bSFinn Thain unsigned long flags; 240262717f53SFinn Thain struct NCR5380_cmd *ncmd; 24031da177e4SLinus Torvalds 240411d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 24053be1b3eaSFinn Thain 24063be1b3eaSFinn Thain #if (NDEBUG & NDEBUG_ANY) 240762717f53SFinn Thain scmd_printk(KERN_INFO, cmd, __func__); 24083be1b3eaSFinn Thain #endif 2409e5c3fddfSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 2410e5c3fddfSFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 24113be1b3eaSFinn Thain 241268b3aa7cSJeff Garzik do_reset(instance); 24133be1b3eaSFinn Thain 241462717f53SFinn Thain /* reset NCR registers */ 241562717f53SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 241662717f53SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 0); 241762717f53SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 241862717f53SFinn Thain 241962717f53SFinn Thain /* After the reset, there are no more connected or disconnected commands 242062717f53SFinn Thain * and no busy units; so clear the low-level status here to avoid 242162717f53SFinn Thain * conflicts when the mid-level code tries to wake up the affected 242262717f53SFinn Thain * commands! 242362717f53SFinn Thain */ 242462717f53SFinn Thain 24251884c283SFinn Thain if (list_del_cmd(&hostdata->unissued, cmd)) { 24261884c283SFinn Thain cmd->result = DID_RESET << 16; 24271884c283SFinn Thain cmd->scsi_done(cmd); 24281884c283SFinn Thain } 24291884c283SFinn Thain 24301884c283SFinn Thain if (hostdata->selecting) { 24311884c283SFinn Thain hostdata->selecting->result = DID_RESET << 16; 24321884c283SFinn Thain complete_cmd(instance, hostdata->selecting); 243362717f53SFinn Thain hostdata->selecting = NULL; 24341884c283SFinn Thain } 243562717f53SFinn Thain 243662717f53SFinn Thain list_for_each_entry(ncmd, &hostdata->disconnected, list) { 243762717f53SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 243862717f53SFinn Thain 243962717f53SFinn Thain set_host_byte(cmd, DID_RESET); 244062717f53SFinn Thain cmd->scsi_done(cmd); 244162717f53SFinn Thain } 24421884c283SFinn Thain INIT_LIST_HEAD(&hostdata->disconnected); 244362717f53SFinn Thain 244462717f53SFinn Thain list_for_each_entry(ncmd, &hostdata->autosense, list) { 244562717f53SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 244662717f53SFinn Thain 244762717f53SFinn Thain set_host_byte(cmd, DID_RESET); 244862717f53SFinn Thain cmd->scsi_done(cmd); 244962717f53SFinn Thain } 24501884c283SFinn Thain INIT_LIST_HEAD(&hostdata->autosense); 245162717f53SFinn Thain 245262717f53SFinn Thain if (hostdata->connected) { 245362717f53SFinn Thain set_host_byte(hostdata->connected, DID_RESET); 245462717f53SFinn Thain complete_cmd(instance, hostdata->connected); 245562717f53SFinn Thain hostdata->connected = NULL; 245662717f53SFinn Thain } 245762717f53SFinn Thain 245862717f53SFinn Thain for (i = 0; i < 8; ++i) 245962717f53SFinn Thain hostdata->busy[i] = 0; 246062717f53SFinn Thain hostdata->dma_len = 0; 246162717f53SFinn Thain 246262717f53SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 246352d3e561SFinn Thain maybe_release_dma_irq(instance); 246411d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 246568b3aa7cSJeff Garzik 24661da177e4SLinus Torvalds return SUCCESS; 24671da177e4SLinus Torvalds } 2468