1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * NCR 5380 generic driver routines. These should make it *trivial* 41da177e4SLinus Torvalds * to implement 5380 SCSI drivers under Linux with a non-trantor 51da177e4SLinus Torvalds * architecture. 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Note that these routines also work with NR53c400 family chips. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Copyright 1993, Drew Eckhardt 101da177e4SLinus Torvalds * Visionary Computing 111da177e4SLinus Torvalds * (Unix and Linux consulting and custom programming) 121da177e4SLinus Torvalds * drew@colorado.edu 131da177e4SLinus Torvalds * +1 (303) 666-5836 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * For more information, please consult 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * NCR 5380 Family 181da177e4SLinus Torvalds * SCSI Protocol Controller 191da177e4SLinus Torvalds * Databook 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * NCR Microelectronics 221da177e4SLinus Torvalds * 1635 Aeroplaza Drive 231da177e4SLinus Torvalds * Colorado Springs, CO 80916 241da177e4SLinus Torvalds * 1+ (719) 578-3400 251da177e4SLinus Torvalds * 1+ (800) 334-5454 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* 29c16df32eSFinn Thain * With contributions from Ray Van Tassle, Ingmar Baumgart, 30c16df32eSFinn Thain * Ronald van Cuijlenborg, Alan Cox and others. 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds 3352d3e561SFinn Thain /* Ported to Atari by Roman Hodek and others. */ 3452d3e561SFinn Thain 35e9db3198SFinn Thain /* Adapted for the Sun 3 by Sam Creasey. */ 36e9db3198SFinn Thain 371da177e4SLinus Torvalds /* 381da177e4SLinus Torvalds * Design 391da177e4SLinus Torvalds * 401da177e4SLinus Torvalds * This is a generic 5380 driver. To use it on a different platform, 411da177e4SLinus Torvalds * one simply writes appropriate system specific macros (ie, data 421da177e4SLinus Torvalds * transfer - some PC's will use the I/O bus, 68K's must use 431da177e4SLinus Torvalds * memory mapped) and drops this file in their 'C' wrapper. 441da177e4SLinus Torvalds * 451da177e4SLinus Torvalds * As far as command queueing, two queues are maintained for 461da177e4SLinus Torvalds * each 5380 in the system - commands that haven't been issued yet, 471da177e4SLinus Torvalds * and commands that are currently executing. This means that an 481da177e4SLinus Torvalds * unlimited number of commands may be queued, letting 491da177e4SLinus Torvalds * more commands propagate from the higher driver levels giving higher 501da177e4SLinus Torvalds * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, 511da177e4SLinus Torvalds * allowing multiple commands to propagate all the way to a SCSI-II device 521da177e4SLinus Torvalds * while a command is already executing. 531da177e4SLinus Torvalds * 541da177e4SLinus Torvalds * 551da177e4SLinus Torvalds * Issues specific to the NCR5380 : 561da177e4SLinus Torvalds * 571da177e4SLinus Torvalds * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 581da177e4SLinus Torvalds * piece of hardware that requires you to sit in a loop polling for 591da177e4SLinus Torvalds * the REQ signal as long as you are connected. Some devices are 601da177e4SLinus Torvalds * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 61686f3990SFinn Thain * while doing long seek operations. [...] These 621da177e4SLinus Torvalds * broken devices are the exception rather than the rule and I'd rather 631da177e4SLinus Torvalds * spend my time optimizing for the normal case. 641da177e4SLinus Torvalds * 651da177e4SLinus Torvalds * Architecture : 661da177e4SLinus Torvalds * 671da177e4SLinus Torvalds * At the heart of the design is a coroutine, NCR5380_main, 681da177e4SLinus Torvalds * which is started from a workqueue for each NCR5380 host in the 691da177e4SLinus Torvalds * system. It attempts to establish I_T_L or I_T_L_Q nexuses by 701da177e4SLinus Torvalds * removing the commands from the issue queue and calling 711da177e4SLinus Torvalds * NCR5380_select() if a nexus is not established. 721da177e4SLinus Torvalds * 731da177e4SLinus Torvalds * Once a nexus is established, the NCR5380_information_transfer() 741da177e4SLinus Torvalds * phase goes through the various phases as instructed by the target. 751da177e4SLinus Torvalds * if the target goes into MSG IN and sends a DISCONNECT message, 761da177e4SLinus Torvalds * the command structure is placed into the per instance disconnected 771da177e4SLinus Torvalds * queue, and NCR5380_main tries to find more work. If the target is 781da177e4SLinus Torvalds * idle for too long, the system will try to sleep. 791da177e4SLinus Torvalds * 801da177e4SLinus Torvalds * If a command has disconnected, eventually an interrupt will trigger, 811da177e4SLinus Torvalds * calling NCR5380_intr() which will in turn call NCR5380_reselect 821da177e4SLinus Torvalds * to reestablish a nexus. This will run main if necessary. 831da177e4SLinus Torvalds * 841da177e4SLinus Torvalds * On command termination, the done function will be called as 851da177e4SLinus Torvalds * appropriate. 861da177e4SLinus Torvalds * 87ff1269cbSFinn Thain * The command data pointer is 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 MUST be defined : 1001da177e4SLinus Torvalds * 1011da177e4SLinus Torvalds * NCR5380_read(register) - read from the specified register 1021da177e4SLinus Torvalds * 1031da177e4SLinus Torvalds * NCR5380_write(register, value) - write to the specific register 1041da177e4SLinus Torvalds * 1051da177e4SLinus Torvalds * NCR5380_implementation_fields - additional fields needed for this 1061da177e4SLinus Torvalds * specific implementation of the NCR5380 1071da177e4SLinus Torvalds * 1081da177e4SLinus Torvalds * Either real DMA *or* pseudo DMA may be implemented 1091da177e4SLinus Torvalds * 1104a98f896SFinn Thain * NCR5380_dma_xfer_len - determine size of DMA/PDMA transfer 1114a98f896SFinn Thain * NCR5380_dma_send_setup - execute DMA/PDMA from memory to 5380 1124a98f896SFinn Thain * NCR5380_dma_recv_setup - execute DMA/PDMA from 5380 to memory 1134a98f896SFinn Thain * NCR5380_dma_residual - residual byte count 1141da177e4SLinus Torvalds * 1151da177e4SLinus Torvalds * The generic driver is initialized by calling NCR5380_init(instance), 116906e4a3cSOndrej Zary * after setting the appropriate host specific fields and ID. 1171da177e4SLinus Torvalds */ 1181da177e4SLinus Torvalds 119e5d55d1aSFinn Thain #ifndef NCR5380_io_delay 120e5d55d1aSFinn Thain #define NCR5380_io_delay(x) 121e5d55d1aSFinn Thain #endif 122e5d55d1aSFinn Thain 12352d3e561SFinn Thain #ifndef NCR5380_acquire_dma_irq 12452d3e561SFinn Thain #define NCR5380_acquire_dma_irq(x) (1) 12552d3e561SFinn Thain #endif 12652d3e561SFinn Thain 12752d3e561SFinn Thain #ifndef NCR5380_release_dma_irq 12852d3e561SFinn Thain #define NCR5380_release_dma_irq(x) 12952d3e561SFinn Thain #endif 13052d3e561SFinn Thain 1310b7a2235SFinn Thain static unsigned int disconnect_mask = ~0; 1320b7a2235SFinn Thain module_param(disconnect_mask, int, 0444); 1330b7a2235SFinn Thain 134e7734ef1SAhmed S. Darwish static int do_abort(struct Scsi_Host *, unsigned int); 13554d8fe44SFinn Thain static void do_reset(struct Scsi_Host *); 1366b0e87a6SFinn Thain static void bus_reset_cleanup(struct Scsi_Host *); 1371da177e4SLinus Torvalds 138c16df32eSFinn Thain /** 1391da177e4SLinus Torvalds * initialize_SCp - init the scsi pointer field 1401da177e4SLinus Torvalds * @cmd: command block to set up 1411da177e4SLinus Torvalds * 1421da177e4SLinus Torvalds * Set up the internal fields in the SCSI command. 1431da177e4SLinus Torvalds */ 1441da177e4SLinus Torvalds 145710ddd0dSFinn Thain static inline void initialize_SCp(struct scsi_cmnd *cmd) 1461da177e4SLinus Torvalds { 147ff1269cbSFinn Thain struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd); 1481da177e4SLinus Torvalds 1499e0fe44dSBoaz Harrosh if (scsi_bufflen(cmd)) { 150ff1269cbSFinn Thain ncmd->buffer = scsi_sglist(cmd); 151ff1269cbSFinn Thain ncmd->ptr = sg_virt(ncmd->buffer); 152ff1269cbSFinn Thain ncmd->this_residual = ncmd->buffer->length; 1531da177e4SLinus Torvalds } else { 154ff1269cbSFinn Thain ncmd->buffer = NULL; 155ff1269cbSFinn Thain ncmd->ptr = NULL; 156ff1269cbSFinn Thain ncmd->this_residual = 0; 1571da177e4SLinus Torvalds } 158f27db8ebSFinn Thain 159ff1269cbSFinn Thain ncmd->status = 0; 1601da177e4SLinus Torvalds } 1611da177e4SLinus Torvalds 162ff1269cbSFinn Thain static inline void advance_sg_buffer(struct NCR5380_cmd *ncmd) 1630e9fdd2bSFinn Thain { 164ff1269cbSFinn Thain struct scatterlist *s = ncmd->buffer; 1650e9fdd2bSFinn Thain 166ff1269cbSFinn Thain if (!ncmd->this_residual && s && !sg_is_last(s)) { 167ff1269cbSFinn Thain ncmd->buffer = sg_next(s); 168ff1269cbSFinn Thain ncmd->ptr = sg_virt(ncmd->buffer); 169ff1269cbSFinn Thain ncmd->this_residual = ncmd->buffer->length; 1700e9fdd2bSFinn Thain } 1710e9fdd2bSFinn Thain } 1720e9fdd2bSFinn Thain 173350767f2SFinn Thain static inline void set_resid_from_SCp(struct scsi_cmnd *cmd) 174350767f2SFinn Thain { 175ff1269cbSFinn Thain struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd); 176ff1269cbSFinn Thain int resid = ncmd->this_residual; 177ff1269cbSFinn Thain struct scatterlist *s = ncmd->buffer; 178350767f2SFinn Thain 179350767f2SFinn Thain if (s) 180350767f2SFinn Thain while (!sg_is_last(s)) { 181350767f2SFinn Thain s = sg_next(s); 182350767f2SFinn Thain resid += s->length; 183350767f2SFinn Thain } 184350767f2SFinn Thain scsi_set_resid(cmd, resid); 185350767f2SFinn Thain } 186350767f2SFinn Thain 1871da177e4SLinus Torvalds /** 188b32ade12SFinn Thain * NCR5380_poll_politely2 - wait for two chip register values 189d5d37a0aSFinn Thain * @hostdata: host private data 190b32ade12SFinn Thain * @reg1: 5380 register to poll 191b32ade12SFinn Thain * @bit1: Bitmask to check 192b32ade12SFinn Thain * @val1: Expected value 193b32ade12SFinn Thain * @reg2: Second 5380 register to poll 194b32ade12SFinn Thain * @bit2: Second bitmask to check 195b32ade12SFinn Thain * @val2: Second expected value 196e7734ef1SAhmed S. Darwish * @wait: Time-out in jiffies, 0 if sleeping is not allowed 1971da177e4SLinus Torvalds * 1982f854b82SFinn Thain * Polls the chip in a reasonably efficient manner waiting for an 1992f854b82SFinn Thain * event to occur. After a short quick poll we begin to yield the CPU 2002f854b82SFinn Thain * (if possible). In irq contexts the time-out is arbitrarily limited. 2011da177e4SLinus Torvalds * 202b32ade12SFinn Thain * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT. 2031da177e4SLinus Torvalds */ 2041da177e4SLinus Torvalds 205d5d37a0aSFinn Thain static int NCR5380_poll_politely2(struct NCR5380_hostdata *hostdata, 20661e1ce58SFinn Thain unsigned int reg1, u8 bit1, u8 val1, 20761e1ce58SFinn Thain unsigned int reg2, u8 bit2, u8 val2, 20861e1ce58SFinn Thain unsigned long wait) 2091da177e4SLinus Torvalds { 210d4408dd7SFinn Thain unsigned long n = hostdata->poll_loops; 2112f854b82SFinn Thain unsigned long deadline = jiffies + wait; 2121da177e4SLinus Torvalds 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 221e7734ef1SAhmed S. Darwish if (!wait) 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 236185a7a1cSviro@ZenIV.linux.org.uk #if NDEBUG 2371da177e4SLinus Torvalds static struct { 2381da177e4SLinus Torvalds unsigned char mask; 2391da177e4SLinus Torvalds const char *name; 2401da177e4SLinus Torvalds } signals[] = { 2411da177e4SLinus Torvalds {SR_DBP, "PARITY"}, 2421da177e4SLinus Torvalds {SR_RST, "RST"}, 2431da177e4SLinus Torvalds {SR_BSY, "BSY"}, 2441da177e4SLinus Torvalds {SR_REQ, "REQ"}, 2451da177e4SLinus Torvalds {SR_MSG, "MSG"}, 2461da177e4SLinus Torvalds {SR_CD, "CD"}, 2471da177e4SLinus Torvalds {SR_IO, "IO"}, 2481da177e4SLinus Torvalds {SR_SEL, "SEL"}, 2491da177e4SLinus Torvalds {0, NULL} 2501da177e4SLinus Torvalds }, 2511da177e4SLinus Torvalds basrs[] = { 25212866b99SFinn Thain {BASR_END_DMA_TRANSFER, "END OF DMA"}, 25312866b99SFinn Thain {BASR_DRQ, "DRQ"}, 25412866b99SFinn Thain {BASR_PARITY_ERROR, "PARITY ERROR"}, 25512866b99SFinn Thain {BASR_IRQ, "IRQ"}, 25612866b99SFinn Thain {BASR_PHASE_MATCH, "PHASE MATCH"}, 25712866b99SFinn Thain {BASR_BUSY_ERROR, "BUSY ERROR"}, 2581da177e4SLinus Torvalds {BASR_ATN, "ATN"}, 2591da177e4SLinus Torvalds {BASR_ACK, "ACK"}, 2601da177e4SLinus Torvalds {0, NULL} 2611da177e4SLinus Torvalds }, 2621da177e4SLinus Torvalds icrs[] = { 2631da177e4SLinus Torvalds {ICR_ASSERT_RST, "ASSERT RST"}, 26412866b99SFinn Thain {ICR_ARBITRATION_PROGRESS, "ARB. IN PROGRESS"}, 26512866b99SFinn Thain {ICR_ARBITRATION_LOST, "LOST ARB."}, 2661da177e4SLinus Torvalds {ICR_ASSERT_ACK, "ASSERT ACK"}, 2671da177e4SLinus Torvalds {ICR_ASSERT_BSY, "ASSERT BSY"}, 2681da177e4SLinus Torvalds {ICR_ASSERT_SEL, "ASSERT SEL"}, 2691da177e4SLinus Torvalds {ICR_ASSERT_ATN, "ASSERT ATN"}, 2701da177e4SLinus Torvalds {ICR_ASSERT_DATA, "ASSERT DATA"}, 2711da177e4SLinus Torvalds {0, NULL} 2721da177e4SLinus Torvalds }, 2731da177e4SLinus Torvalds mrs[] = { 27412866b99SFinn Thain {MR_BLOCK_DMA_MODE, "BLOCK DMA MODE"}, 27512866b99SFinn Thain {MR_TARGET, "TARGET"}, 27612866b99SFinn Thain {MR_ENABLE_PAR_CHECK, "PARITY CHECK"}, 27712866b99SFinn Thain {MR_ENABLE_PAR_INTR, "PARITY INTR"}, 27812866b99SFinn Thain {MR_ENABLE_EOP_INTR, "EOP INTR"}, 27912866b99SFinn Thain {MR_MONITOR_BSY, "MONITOR BSY"}, 28012866b99SFinn Thain {MR_DMA_MODE, "DMA MODE"}, 28112866b99SFinn Thain {MR_ARBITRATE, "ARBITRATE"}, 2821da177e4SLinus Torvalds {0, NULL} 2831da177e4SLinus Torvalds }; 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds /** 2861da177e4SLinus Torvalds * NCR5380_print - print scsi bus signals 2871da177e4SLinus Torvalds * @instance: adapter state to dump 2881da177e4SLinus Torvalds * 2891da177e4SLinus Torvalds * Print the SCSI bus signals for debugging purposes 2901da177e4SLinus Torvalds */ 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds static void NCR5380_print(struct Scsi_Host *instance) 2931da177e4SLinus Torvalds { 29461e1ce58SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 2958cee3e16SFinn Thain unsigned char status, basr, mr, icr, i; 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds status = NCR5380_read(STATUS_REG); 2981da177e4SLinus Torvalds mr = NCR5380_read(MODE_REG); 2991da177e4SLinus Torvalds icr = NCR5380_read(INITIATOR_COMMAND_REG); 3001da177e4SLinus Torvalds basr = NCR5380_read(BUS_AND_STATUS_REG); 3011da177e4SLinus Torvalds 30212866b99SFinn Thain printk(KERN_DEBUG "SR = 0x%02x : ", status); 3031da177e4SLinus Torvalds for (i = 0; signals[i].mask; ++i) 3041da177e4SLinus Torvalds if (status & signals[i].mask) 30512866b99SFinn Thain printk(KERN_CONT "%s, ", signals[i].name); 30612866b99SFinn Thain printk(KERN_CONT "\nBASR = 0x%02x : ", basr); 3071da177e4SLinus Torvalds for (i = 0; basrs[i].mask; ++i) 3081da177e4SLinus Torvalds if (basr & basrs[i].mask) 30912866b99SFinn Thain printk(KERN_CONT "%s, ", basrs[i].name); 31012866b99SFinn Thain printk(KERN_CONT "\nICR = 0x%02x : ", icr); 3111da177e4SLinus Torvalds for (i = 0; icrs[i].mask; ++i) 3121da177e4SLinus Torvalds if (icr & icrs[i].mask) 31312866b99SFinn Thain printk(KERN_CONT "%s, ", icrs[i].name); 31412866b99SFinn Thain printk(KERN_CONT "\nMR = 0x%02x : ", mr); 3151da177e4SLinus Torvalds for (i = 0; mrs[i].mask; ++i) 3161da177e4SLinus Torvalds if (mr & mrs[i].mask) 31712866b99SFinn Thain printk(KERN_CONT "%s, ", mrs[i].name); 31812866b99SFinn Thain printk(KERN_CONT "\n"); 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3210d2cf867SFinn Thain static struct { 3220d2cf867SFinn Thain unsigned char value; 3230d2cf867SFinn Thain const char *name; 3240d2cf867SFinn Thain } phases[] = { 3250d2cf867SFinn Thain {PHASE_DATAOUT, "DATAOUT"}, 3260d2cf867SFinn Thain {PHASE_DATAIN, "DATAIN"}, 3270d2cf867SFinn Thain {PHASE_CMDOUT, "CMDOUT"}, 3280d2cf867SFinn Thain {PHASE_STATIN, "STATIN"}, 3290d2cf867SFinn Thain {PHASE_MSGOUT, "MSGOUT"}, 3300d2cf867SFinn Thain {PHASE_MSGIN, "MSGIN"}, 3310d2cf867SFinn Thain {PHASE_UNKNOWN, "UNKNOWN"} 3320d2cf867SFinn Thain }; 3331da177e4SLinus Torvalds 334c16df32eSFinn Thain /** 3351da177e4SLinus Torvalds * NCR5380_print_phase - show SCSI phase 3361da177e4SLinus Torvalds * @instance: adapter to dump 3371da177e4SLinus Torvalds * 3381da177e4SLinus Torvalds * Print the current SCSI phase for debugging purposes 3391da177e4SLinus Torvalds */ 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds static void NCR5380_print_phase(struct Scsi_Host *instance) 3421da177e4SLinus Torvalds { 34361e1ce58SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 3441da177e4SLinus Torvalds unsigned char status; 3451da177e4SLinus Torvalds int i; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds status = NCR5380_read(STATUS_REG); 3481da177e4SLinus Torvalds if (!(status & SR_REQ)) 3496a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n"); 3501da177e4SLinus Torvalds else { 3510d2cf867SFinn Thain for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 3520d2cf867SFinn Thain (phases[i].value != (status & PHASE_MASK)); ++i) 3530d2cf867SFinn Thain ; 3546a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name); 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds #endif 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds /** 36009028461SFinn Thain * NCR5380_info - report driver and host information 3618c32513bSFinn Thain * @instance: relevant scsi host instance 3621da177e4SLinus Torvalds * 3638c32513bSFinn Thain * For use as the host template info() handler. 3641da177e4SLinus Torvalds */ 3651da177e4SLinus Torvalds 3668c32513bSFinn Thain static const char *NCR5380_info(struct Scsi_Host *instance) 3671da177e4SLinus Torvalds { 3688c32513bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 3698c32513bSFinn Thain 3708c32513bSFinn Thain return hostdata->info; 3718c32513bSFinn Thain } 3728c32513bSFinn Thain 3731da177e4SLinus Torvalds /** 3741da177e4SLinus Torvalds * NCR5380_init - initialise an NCR5380 3751da177e4SLinus Torvalds * @instance: adapter to configure 3761da177e4SLinus Torvalds * @flags: control flags 3771da177e4SLinus Torvalds * 3781da177e4SLinus Torvalds * Initializes *instance and corresponding 5380 chip, 3791da177e4SLinus Torvalds * with flags OR'd into the initial flags value. 3801da177e4SLinus Torvalds * 3811da177e4SLinus Torvalds * Notes : I assume that the host, hostno, and id bits have been 3821da177e4SLinus Torvalds * set correctly. I don't care about the irq and other fields. 3831da177e4SLinus Torvalds * 3841da177e4SLinus Torvalds * Returns 0 for success 3851da177e4SLinus Torvalds */ 3861da177e4SLinus Torvalds 3876f039790SGreg Kroah-Hartman static int NCR5380_init(struct Scsi_Host *instance, int flags) 3881da177e4SLinus Torvalds { 389e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 390b6488f97SFinn Thain int i; 3912f854b82SFinn Thain unsigned long deadline; 392d4408dd7SFinn Thain unsigned long accesses_per_ms; 3931da177e4SLinus Torvalds 394ae5e33afSFinn Thain instance->max_lun = 7; 395ae5e33afSFinn Thain 3960d2cf867SFinn Thain hostdata->host = instance; 3971da177e4SLinus Torvalds hostdata->id_mask = 1 << instance->this_id; 3980d2cf867SFinn Thain hostdata->id_higher_mask = 0; 3991da177e4SLinus Torvalds for (i = hostdata->id_mask; i <= 0x80; i <<= 1) 4001da177e4SLinus Torvalds if (i > hostdata->id_mask) 4011da177e4SLinus Torvalds hostdata->id_higher_mask |= i; 4021da177e4SLinus Torvalds for (i = 0; i < 8; ++i) 4031da177e4SLinus Torvalds hostdata->busy[i] = 0; 404e4dec680SFinn Thain hostdata->dma_len = 0; 405e4dec680SFinn Thain 40611d2f63bSFinn Thain spin_lock_init(&hostdata->lock); 4071da177e4SLinus Torvalds hostdata->connected = NULL; 408f27db8ebSFinn Thain hostdata->sensing = NULL; 409f27db8ebSFinn Thain INIT_LIST_HEAD(&hostdata->autosense); 41032b26a10SFinn Thain INIT_LIST_HEAD(&hostdata->unissued); 41132b26a10SFinn Thain INIT_LIST_HEAD(&hostdata->disconnected); 41232b26a10SFinn Thain 41355181be8SFinn Thain hostdata->flags = flags; 4141da177e4SLinus Torvalds 4158d8601a7SFinn Thain INIT_WORK(&hostdata->main_task, NCR5380_main); 4160ad0eff9SFinn Thain hostdata->work_q = alloc_workqueue("ncr5380_%d", 4170ad0eff9SFinn Thain WQ_UNBOUND | WQ_MEM_RECLAIM, 4186f640df1STejun Heo 0, instance->host_no); 4190ad0eff9SFinn Thain if (!hostdata->work_q) 4200ad0eff9SFinn Thain return -ENOMEM; 4211da177e4SLinus Torvalds 42209028461SFinn Thain snprintf(hostdata->info, sizeof(hostdata->info), 42309028461SFinn Thain "%s, irq %d, io_port 0x%lx, base 0x%lx, can_queue %d, cmd_per_lun %d, sg_tablesize %d, this_id %d, flags { %s%s%s}", 42409028461SFinn Thain instance->hostt->name, instance->irq, hostdata->io_port, 42509028461SFinn Thain hostdata->base, instance->can_queue, instance->cmd_per_lun, 42609028461SFinn Thain instance->sg_tablesize, instance->this_id, 42709028461SFinn Thain hostdata->flags & FLAG_DMA_FIXUP ? "DMA_FIXUP " : "", 42809028461SFinn Thain hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "", 42909028461SFinn Thain hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : ""); 4308c32513bSFinn Thain 4311da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 4321da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 4331da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 4341da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 4352f854b82SFinn Thain 4362f854b82SFinn Thain /* Calibrate register polling loop */ 4372f854b82SFinn Thain i = 0; 4382f854b82SFinn Thain deadline = jiffies + 1; 4392f854b82SFinn Thain do { 4402f854b82SFinn Thain cpu_relax(); 4412f854b82SFinn Thain } while (time_is_after_jiffies(deadline)); 4422f854b82SFinn Thain deadline += msecs_to_jiffies(256); 4432f854b82SFinn Thain do { 4442f854b82SFinn Thain NCR5380_read(STATUS_REG); 4452f854b82SFinn Thain ++i; 4462f854b82SFinn Thain cpu_relax(); 4472f854b82SFinn Thain } while (time_is_after_jiffies(deadline)); 448d4408dd7SFinn Thain accesses_per_ms = i / 256; 449d4408dd7SFinn Thain hostdata->poll_loops = NCR5380_REG_POLL_TIME * accesses_per_ms / 2; 4502f854b82SFinn Thain 451b6488f97SFinn Thain return 0; 452b6488f97SFinn Thain } 4531da177e4SLinus Torvalds 454b6488f97SFinn Thain /** 455b6488f97SFinn Thain * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems. 456b6488f97SFinn Thain * @instance: adapter to check 4571da177e4SLinus Torvalds * 458b6488f97SFinn Thain * If the system crashed, it may have crashed with a connected target and 459b6488f97SFinn Thain * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the 460b6488f97SFinn Thain * currently established nexus, which we know nothing about. Failing that 461b6488f97SFinn Thain * do a bus reset. 4621da177e4SLinus Torvalds * 463b6488f97SFinn Thain * Note that a bus reset will cause the chip to assert IRQ. 464b6488f97SFinn Thain * 465b6488f97SFinn Thain * Returns 0 if successful, otherwise -ENXIO. 4661da177e4SLinus Torvalds */ 4671da177e4SLinus Torvalds 468b6488f97SFinn Thain static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance) 469b6488f97SFinn Thain { 4709c3f0e2bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 471b6488f97SFinn Thain int pass; 472b6488f97SFinn Thain 4731da177e4SLinus Torvalds for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) { 4741da177e4SLinus Torvalds switch (pass) { 4751da177e4SLinus Torvalds case 1: 4761da177e4SLinus Torvalds case 3: 4771da177e4SLinus Torvalds case 5: 478636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n"); 479d5d37a0aSFinn Thain NCR5380_poll_politely(hostdata, 480636b1ec8SFinn Thain STATUS_REG, SR_BSY, 0, 5 * HZ); 4811da177e4SLinus Torvalds break; 4821da177e4SLinus Torvalds case 2: 483636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n"); 484e7734ef1SAhmed S. Darwish do_abort(instance, 1); 4851da177e4SLinus Torvalds break; 4861da177e4SLinus Torvalds case 4: 487636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n"); 4881da177e4SLinus Torvalds do_reset(instance); 4899c3f0e2bSFinn Thain /* Wait after a reset; the SCSI standard calls for 4909c3f0e2bSFinn Thain * 250ms, we wait 500ms to be on the safe side. 4919c3f0e2bSFinn Thain * But some Toshiba CD-ROMs need ten times that. 4929c3f0e2bSFinn Thain */ 4939c3f0e2bSFinn Thain if (hostdata->flags & FLAG_TOSHIBA_DELAY) 4949c3f0e2bSFinn Thain msleep(2500); 4959c3f0e2bSFinn Thain else 4969c3f0e2bSFinn Thain msleep(500); 4971da177e4SLinus Torvalds break; 4981da177e4SLinus Torvalds case 6: 499636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus locked solid\n"); 5001da177e4SLinus Torvalds return -ENXIO; 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds return 0; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds /** 5071da177e4SLinus Torvalds * NCR5380_exit - remove an NCR5380 5081da177e4SLinus Torvalds * @instance: adapter to remove 5090d2cf867SFinn Thain * 5100d2cf867SFinn Thain * Assumes that no more work can be queued (e.g. by NCR5380_intr). 5111da177e4SLinus Torvalds */ 5121da177e4SLinus Torvalds 513a43cf0f3SRandy Dunlap static void NCR5380_exit(struct Scsi_Host *instance) 5141da177e4SLinus Torvalds { 515e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 5161da177e4SLinus Torvalds 5178d8601a7SFinn Thain cancel_work_sync(&hostdata->main_task); 5180ad0eff9SFinn Thain destroy_workqueue(hostdata->work_q); 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds /** 522677e0194SFinn Thain * complete_cmd - finish processing a command and return it to the SCSI ML 523677e0194SFinn Thain * @instance: the host instance 524677e0194SFinn Thain * @cmd: command to complete 525677e0194SFinn Thain */ 526677e0194SFinn Thain 527677e0194SFinn Thain static void complete_cmd(struct Scsi_Host *instance, 528677e0194SFinn Thain struct scsi_cmnd *cmd) 529677e0194SFinn Thain { 530677e0194SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 531677e0194SFinn Thain 532677e0194SFinn Thain dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd); 533677e0194SFinn Thain 534f27db8ebSFinn Thain if (hostdata->sensing == cmd) { 535f27db8ebSFinn Thain /* Autosense processing ends here */ 5363d45cefcSHannes Reinecke if (get_status_byte(cmd) != SAM_STAT_GOOD) { 537f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 53807035651SFinn Thain } else { 539f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 540464a00c9SHannes Reinecke set_status_byte(cmd, SAM_STAT_CHECK_CONDITION); 54107035651SFinn Thain } 542f27db8ebSFinn Thain hostdata->sensing = NULL; 543f27db8ebSFinn Thain } 544f27db8ebSFinn Thain 545117cd238SBart Van Assche scsi_done(cmd); 546677e0194SFinn Thain } 547677e0194SFinn Thain 548677e0194SFinn Thain /** 5491da177e4SLinus Torvalds * NCR5380_queue_command - queue a command 5501bb40589SFinn Thain * @instance: the relevant SCSI adapter 5511da177e4SLinus Torvalds * @cmd: SCSI command 5521da177e4SLinus Torvalds * 5531bb40589SFinn Thain * cmd is added to the per-instance issue queue, with minor 5541da177e4SLinus Torvalds * twiddling done to the host specific fields of cmd. If the 5551da177e4SLinus Torvalds * main coroutine is not running, it is restarted. 5561da177e4SLinus Torvalds */ 5571da177e4SLinus Torvalds 5581bb40589SFinn Thain static int NCR5380_queue_command(struct Scsi_Host *instance, 5591bb40589SFinn Thain struct scsi_cmnd *cmd) 5601da177e4SLinus Torvalds { 5611bb40589SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 562ff1269cbSFinn Thain struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd); 5631bb40589SFinn Thain unsigned long flags; 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_WRITE) 5661da177e4SLinus Torvalds switch (cmd->cmnd[0]) { 5671da177e4SLinus Torvalds case WRITE_6: 5681da177e4SLinus Torvalds case WRITE_10: 569dbb6b350SFinn Thain shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n"); 5701da177e4SLinus Torvalds cmd->result = (DID_ERROR << 16); 571117cd238SBart Van Assche scsi_done(cmd); 5721da177e4SLinus Torvalds return 0; 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds cmd->result = 0; 5771da177e4SLinus Torvalds 57811d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 5791bb40589SFinn Thain 58003fe6a64SFinn Thain if (!NCR5380_acquire_dma_irq(instance)) { 58103fe6a64SFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 58203fe6a64SFinn Thain 58303fe6a64SFinn Thain return SCSI_MLQUEUE_HOST_BUSY; 58403fe6a64SFinn Thain } 58503fe6a64SFinn Thain 5861da177e4SLinus Torvalds /* 5871da177e4SLinus Torvalds * Insert the cmd into the issue queue. Note that REQUEST SENSE 5881da177e4SLinus Torvalds * commands are added to the head of the queue since any command will 5891da177e4SLinus Torvalds * clear the contingent allegiance condition that exists and the 5901da177e4SLinus Torvalds * sense data is only guaranteed to be valid while the condition exists. 5911da177e4SLinus Torvalds */ 5921da177e4SLinus Torvalds 59332b26a10SFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 59432b26a10SFinn Thain list_add(&ncmd->list, &hostdata->unissued); 59532b26a10SFinn Thain else 59632b26a10SFinn Thain list_add_tail(&ncmd->list, &hostdata->unissued); 59732b26a10SFinn Thain 59811d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 5991bb40589SFinn Thain 600dbb6b350SFinn Thain dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n", 601dbb6b350SFinn Thain cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds /* Kick off command processing */ 6048d8601a7SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 6051da177e4SLinus Torvalds return 0; 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds 60852d3e561SFinn Thain static inline void maybe_release_dma_irq(struct Scsi_Host *instance) 60952d3e561SFinn Thain { 61052d3e561SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 61152d3e561SFinn Thain 61252d3e561SFinn Thain /* Caller does the locking needed to set & test these data atomically */ 61352d3e561SFinn Thain if (list_empty(&hostdata->disconnected) && 61452d3e561SFinn Thain list_empty(&hostdata->unissued) && 61552d3e561SFinn Thain list_empty(&hostdata->autosense) && 61652d3e561SFinn Thain !hostdata->connected && 6174ab2a787SFinn Thain !hostdata->selecting) { 61852d3e561SFinn Thain NCR5380_release_dma_irq(instance); 61952d3e561SFinn Thain } 6204ab2a787SFinn Thain } 62152d3e561SFinn Thain 6221da177e4SLinus Torvalds /** 623f27db8ebSFinn Thain * dequeue_next_cmd - dequeue a command for processing 624f27db8ebSFinn Thain * @instance: the scsi host instance 625f27db8ebSFinn Thain * 626f27db8ebSFinn Thain * Priority is given to commands on the autosense queue. These commands 627f27db8ebSFinn Thain * need autosense because of a CHECK CONDITION result. 628f27db8ebSFinn Thain * 629f27db8ebSFinn Thain * Returns a command pointer if a command is found for a target that is 630f27db8ebSFinn Thain * not already busy. Otherwise returns NULL. 631f27db8ebSFinn Thain */ 632f27db8ebSFinn Thain 633f27db8ebSFinn Thain static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance) 634f27db8ebSFinn Thain { 635f27db8ebSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 636f27db8ebSFinn Thain struct NCR5380_cmd *ncmd; 637f27db8ebSFinn Thain struct scsi_cmnd *cmd; 638f27db8ebSFinn Thain 6398d5dbec3SFinn Thain if (hostdata->sensing || list_empty(&hostdata->autosense)) { 640f27db8ebSFinn Thain list_for_each_entry(ncmd, &hostdata->unissued, list) { 641f27db8ebSFinn Thain cmd = NCR5380_to_scmd(ncmd); 642f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n", 643f27db8ebSFinn Thain cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun); 644f27db8ebSFinn Thain 645f27db8ebSFinn Thain if (!(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))) { 646f27db8ebSFinn Thain list_del(&ncmd->list); 647f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, 648f27db8ebSFinn Thain "dequeue: removed %p from issue queue\n", cmd); 649f27db8ebSFinn Thain return cmd; 650f27db8ebSFinn Thain } 651f27db8ebSFinn Thain } 652f27db8ebSFinn Thain } else { 653f27db8ebSFinn Thain /* Autosense processing begins here */ 654f27db8ebSFinn Thain ncmd = list_first_entry(&hostdata->autosense, 655f27db8ebSFinn Thain struct NCR5380_cmd, list); 656f27db8ebSFinn Thain list_del(&ncmd->list); 657f27db8ebSFinn Thain cmd = NCR5380_to_scmd(ncmd); 658f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, 659f27db8ebSFinn Thain "dequeue: removed %p from autosense queue\n", cmd); 660f27db8ebSFinn Thain scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); 661f27db8ebSFinn Thain hostdata->sensing = cmd; 662f27db8ebSFinn Thain return cmd; 663f27db8ebSFinn Thain } 664f27db8ebSFinn Thain return NULL; 665f27db8ebSFinn Thain } 666f27db8ebSFinn Thain 667f27db8ebSFinn Thain static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd) 668f27db8ebSFinn Thain { 669f27db8ebSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 670ff1269cbSFinn Thain struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd); 671f27db8ebSFinn Thain 6728d5dbec3SFinn Thain if (hostdata->sensing == cmd) { 673f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 674f27db8ebSFinn Thain list_add(&ncmd->list, &hostdata->autosense); 675f27db8ebSFinn Thain hostdata->sensing = NULL; 676f27db8ebSFinn Thain } else 677f27db8ebSFinn Thain list_add(&ncmd->list, &hostdata->unissued); 678f27db8ebSFinn Thain } 679f27db8ebSFinn Thain 680f27db8ebSFinn Thain /** 6811da177e4SLinus Torvalds * NCR5380_main - NCR state machines 6821da177e4SLinus Torvalds * 6831da177e4SLinus Torvalds * NCR5380_main is a coroutine that runs as long as more work can 6841da177e4SLinus Torvalds * be done on the NCR5380 host adapters in a system. Both 6851da177e4SLinus Torvalds * NCR5380_queue_command() and NCR5380_intr() will try to start it 6861da177e4SLinus Torvalds * in case it is not running. 6871da177e4SLinus Torvalds */ 6881da177e4SLinus Torvalds 689c4028958SDavid Howells static void NCR5380_main(struct work_struct *work) 6901da177e4SLinus Torvalds { 691c4028958SDavid Howells struct NCR5380_hostdata *hostdata = 6928d8601a7SFinn Thain container_of(work, struct NCR5380_hostdata, main_task); 6931da177e4SLinus Torvalds struct Scsi_Host *instance = hostdata->host; 6941da177e4SLinus Torvalds int done; 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds do { 6971da177e4SLinus Torvalds done = 1; 69811d2f63bSFinn Thain 6990a4e3612SFinn Thain spin_lock_irq(&hostdata->lock); 700ccf6efd7SFinn Thain while (!hostdata->connected && !hostdata->selecting) { 701ccf6efd7SFinn Thain struct scsi_cmnd *cmd = dequeue_next_cmd(instance); 702ccf6efd7SFinn Thain 703ccf6efd7SFinn Thain if (!cmd) 704ccf6efd7SFinn Thain break; 70532b26a10SFinn Thain 706f27db8ebSFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd); 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds /* 7091da177e4SLinus Torvalds * Attempt to establish an I_T_L nexus here. 7101da177e4SLinus Torvalds * On success, instance->hostdata->connected is set. 7111da177e4SLinus Torvalds * On failure, we must add the command back to the 7121da177e4SLinus Torvalds * issue queue so we can keep trying. 7131da177e4SLinus Torvalds */ 7141da177e4SLinus Torvalds /* 7151da177e4SLinus Torvalds * REQUEST SENSE commands are issued without tagged 7161da177e4SLinus Torvalds * queueing, even on SCSI-II devices because the 7171da177e4SLinus Torvalds * contingent allegiance condition exists for the 7181da177e4SLinus Torvalds * entire unit. 7191da177e4SLinus Torvalds */ 72076f13b93SFinn Thain 721ccf6efd7SFinn Thain if (!NCR5380_select(instance, cmd)) { 722707d62b3SFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: select complete\n"); 7231da177e4SLinus Torvalds } else { 724f27db8ebSFinn Thain dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance, 725f27db8ebSFinn Thain "main: select failed, returning %p to queue\n", cmd); 726f27db8ebSFinn Thain requeue_cmd(instance, cmd); 7271da177e4SLinus Torvalds } 728f27db8ebSFinn Thain } 729e4dec680SFinn Thain if (hostdata->connected && !hostdata->dma_len) { 730b746545fSFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n"); 7311da177e4SLinus Torvalds NCR5380_information_transfer(instance); 7321da177e4SLinus Torvalds done = 0; 7331d3db59dSFinn Thain } 734bdd1cc03SFinn Thain if (!hostdata->connected) { 73557f31326SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 736bdd1cc03SFinn Thain maybe_release_dma_irq(instance); 737bdd1cc03SFinn Thain } 73811d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 7390a4e3612SFinn Thain if (!done) 7400a4e3612SFinn Thain cond_resched(); 7410a4e3612SFinn Thain } while (!done); 7421da177e4SLinus Torvalds } 7431da177e4SLinus Torvalds 7448053b0eeSFinn Thain /* 7458053b0eeSFinn Thain * NCR5380_dma_complete - finish DMA transfer 7468053b0eeSFinn Thain * @instance: the scsi host instance 7478053b0eeSFinn Thain * 7488053b0eeSFinn Thain * Called by the interrupt handler when DMA finishes or a phase 7498053b0eeSFinn Thain * mismatch occurs (which would end the DMA transfer). 7508053b0eeSFinn Thain */ 7518053b0eeSFinn Thain 7528053b0eeSFinn Thain static void NCR5380_dma_complete(struct Scsi_Host *instance) 7538053b0eeSFinn Thain { 7548053b0eeSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 755ff1269cbSFinn Thain struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(hostdata->connected); 7568053b0eeSFinn Thain int transferred; 7578053b0eeSFinn Thain unsigned char **data; 7588053b0eeSFinn Thain int *count; 7598053b0eeSFinn Thain int saved_data = 0, overrun = 0; 7608053b0eeSFinn Thain unsigned char p; 7618053b0eeSFinn Thain 7628053b0eeSFinn Thain if (hostdata->read_overruns) { 763ff1269cbSFinn Thain p = ncmd->phase; 7648053b0eeSFinn Thain if (p & SR_IO) { 7658053b0eeSFinn Thain udelay(10); 7668053b0eeSFinn Thain if ((NCR5380_read(BUS_AND_STATUS_REG) & 7678053b0eeSFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) == 7688053b0eeSFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) { 7698053b0eeSFinn Thain saved_data = NCR5380_read(INPUT_DATA_REG); 7708053b0eeSFinn Thain overrun = 1; 7718053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, "read overrun handled\n"); 7728053b0eeSFinn Thain } 7738053b0eeSFinn Thain } 7748053b0eeSFinn Thain } 7758053b0eeSFinn Thain 776e9db3198SFinn Thain #ifdef CONFIG_SUN3 7772e4b231aSBart Van Assche if (sun3scsi_dma_finish(hostdata->connected->sc_data_direction)) { 778e9db3198SFinn Thain pr_err("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", 779e9db3198SFinn Thain instance->host_no); 780e9db3198SFinn Thain BUG(); 781e9db3198SFinn Thain } 782e9db3198SFinn Thain 783e9db3198SFinn Thain if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == 784e9db3198SFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) { 785e9db3198SFinn Thain pr_err("scsi%d: BASR %02x\n", instance->host_no, 786e9db3198SFinn Thain NCR5380_read(BUS_AND_STATUS_REG)); 787e9db3198SFinn Thain pr_err("scsi%d: bus stuck in data phase -- probably a single byte overrun!\n", 788e9db3198SFinn Thain instance->host_no); 789e9db3198SFinn Thain BUG(); 790e9db3198SFinn Thain } 791e9db3198SFinn Thain #endif 792e9db3198SFinn Thain 7938053b0eeSFinn Thain NCR5380_write(MODE_REG, MR_BASE); 7948053b0eeSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 7958053b0eeSFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 7968053b0eeSFinn Thain 7974a98f896SFinn Thain transferred = hostdata->dma_len - NCR5380_dma_residual(hostdata); 7988053b0eeSFinn Thain hostdata->dma_len = 0; 7998053b0eeSFinn Thain 800ff1269cbSFinn Thain data = (unsigned char **)&ncmd->ptr; 801ff1269cbSFinn Thain count = &ncmd->this_residual; 8028053b0eeSFinn Thain *data += transferred; 8038053b0eeSFinn Thain *count -= transferred; 8048053b0eeSFinn Thain 8058053b0eeSFinn Thain if (hostdata->read_overruns) { 8068053b0eeSFinn Thain int cnt, toPIO; 8078053b0eeSFinn Thain 8088053b0eeSFinn Thain if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { 8098053b0eeSFinn Thain cnt = toPIO = hostdata->read_overruns; 8108053b0eeSFinn Thain if (overrun) { 8118053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, 8128053b0eeSFinn Thain "Got an input overrun, using saved byte\n"); 8138053b0eeSFinn Thain *(*data)++ = saved_data; 8148053b0eeSFinn Thain (*count)--; 8158053b0eeSFinn Thain cnt--; 8168053b0eeSFinn Thain toPIO--; 8178053b0eeSFinn Thain } 8188053b0eeSFinn Thain if (toPIO > 0) { 8198053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, 8208053b0eeSFinn Thain "Doing %d byte PIO to 0x%p\n", cnt, *data); 821e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &p, &cnt, data, 0); 8228053b0eeSFinn Thain *count -= toPIO - cnt; 8238053b0eeSFinn Thain } 8248053b0eeSFinn Thain } 8258053b0eeSFinn Thain } 8268053b0eeSFinn Thain } 8278053b0eeSFinn Thain 8281da177e4SLinus Torvalds /** 8291da177e4SLinus Torvalds * NCR5380_intr - generic NCR5380 irq handler 8301da177e4SLinus Torvalds * @irq: interrupt number 8311da177e4SLinus Torvalds * @dev_id: device info 8321da177e4SLinus Torvalds * 8331da177e4SLinus Torvalds * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses 8341da177e4SLinus Torvalds * from the disconnected queue, and restarting NCR5380_main() 8351da177e4SLinus Torvalds * as required. 8361da177e4SLinus Torvalds * 837cd400825SFinn Thain * The chip can assert IRQ in any of six different conditions. The IRQ flag 838cd400825SFinn Thain * is then cleared by reading the Reset Parity/Interrupt Register (RPIR). 839cd400825SFinn Thain * Three of these six conditions are latched in the Bus and Status Register: 840cd400825SFinn Thain * - End of DMA (cleared by ending DMA Mode) 841cd400825SFinn Thain * - Parity error (cleared by reading RPIR) 842cd400825SFinn Thain * - Loss of BSY (cleared by reading RPIR) 843cd400825SFinn Thain * Two conditions have flag bits that are not latched: 844cd400825SFinn Thain * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode) 845cd400825SFinn Thain * - Bus reset (non-maskable) 846cd400825SFinn Thain * The remaining condition has no flag bit at all: 847cd400825SFinn Thain * - Selection/reselection 848cd400825SFinn Thain * 849cd400825SFinn Thain * Hence, establishing the cause(s) of any interrupt is partly guesswork. 850cd400825SFinn Thain * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor 851cd400825SFinn Thain * claimed that "the design of the [DP8490] interrupt logic ensures 852cd400825SFinn Thain * interrupts will not be lost (they can be on the DP5380)." 853cd400825SFinn Thain * The L5380/53C80 datasheet from LOGIC Devices has more details. 854cd400825SFinn Thain * 855cd400825SFinn Thain * Checking for bus reset by reading RST is futile because of interrupt 856cd400825SFinn Thain * latency, but a bus reset will reset chip logic. Checking for parity error 857cd400825SFinn Thain * is unnecessary because that interrupt is never enabled. A Loss of BSY 858cd400825SFinn Thain * condition will clear DMA Mode. We can tell when this occurs because the 859e47c4921SJilin Yuan * Busy Monitor interrupt is enabled together with DMA Mode. 8601da177e4SLinus Torvalds */ 8611da177e4SLinus Torvalds 862a46865dcSFinn Thain static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id) 8631da177e4SLinus Torvalds { 864baa9aac6SJeff Garzik struct Scsi_Host *instance = dev_id; 865cd400825SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 866cd400825SFinn Thain int handled = 0; 8671da177e4SLinus Torvalds unsigned char basr; 8681da177e4SLinus Torvalds unsigned long flags; 8691da177e4SLinus Torvalds 87011d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 871cd400825SFinn Thain 8721da177e4SLinus Torvalds basr = NCR5380_read(BUS_AND_STATUS_REG); 8731da177e4SLinus Torvalds if (basr & BASR_IRQ) { 874cd400825SFinn Thain unsigned char mr = NCR5380_read(MODE_REG); 875cd400825SFinn Thain unsigned char sr = NCR5380_read(STATUS_REG); 876cd400825SFinn Thain 877b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n", 878b746545fSFinn Thain irq, basr, sr, mr); 879cd400825SFinn Thain 8808053b0eeSFinn Thain if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) { 8818053b0eeSFinn Thain /* Probably End of DMA, Phase Mismatch or Loss of BSY. 8828053b0eeSFinn Thain * We ack IRQ after clearing Mode Register. Workarounds 8838053b0eeSFinn Thain * for End of DMA errata need to happen in DMA Mode. 8848053b0eeSFinn Thain */ 8858053b0eeSFinn Thain 8868053b0eeSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n"); 8878053b0eeSFinn Thain 8888053b0eeSFinn Thain if (hostdata->connected) { 8898053b0eeSFinn Thain NCR5380_dma_complete(instance); 8908053b0eeSFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 8918053b0eeSFinn Thain } else { 8928053b0eeSFinn Thain NCR5380_write(MODE_REG, MR_BASE); 8938053b0eeSFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 8948053b0eeSFinn Thain } 8958053b0eeSFinn Thain } else if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) && 896cd400825SFinn Thain (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) { 897cd400825SFinn Thain /* Probably reselected */ 898cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 899cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 900cd400825SFinn Thain 901b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n"); 902cd400825SFinn Thain 903cd400825SFinn Thain if (!hostdata->connected) { 904cd400825SFinn Thain NCR5380_reselect(instance); 9058d8601a7SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 906cd400825SFinn Thain } 907cd400825SFinn Thain if (!hostdata->connected) 908cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 909cd400825SFinn Thain } else { 910cd400825SFinn Thain /* Probably Bus Reset */ 911cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 912cd400825SFinn Thain 9136b0e87a6SFinn Thain if (sr & SR_RST) { 9146b0e87a6SFinn Thain /* Certainly Bus Reset */ 9156b0e87a6SFinn Thain shost_printk(KERN_WARNING, instance, 9166b0e87a6SFinn Thain "bus reset interrupt\n"); 9176b0e87a6SFinn Thain bus_reset_cleanup(instance); 9186b0e87a6SFinn Thain } else { 919b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n"); 9206b0e87a6SFinn Thain } 921e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 922e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 923e9db3198SFinn Thain #endif 924cd400825SFinn Thain } 925cd400825SFinn Thain handled = 1; 926cd400825SFinn Thain } else { 9279af9fecbSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt without IRQ bit\n"); 928e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 929e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 930e9db3198SFinn Thain #endif 931cd400825SFinn Thain } 932cd400825SFinn Thain 93311d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 934cd400825SFinn Thain 935cd400825SFinn Thain return IRQ_RETVAL(handled); 9361da177e4SLinus Torvalds } 9371da177e4SLinus Torvalds 938dad8261eSFinn Thain /** 939dad8261eSFinn Thain * NCR5380_select - attempt arbitration and selection for a given command 940dad8261eSFinn Thain * @instance: the Scsi_Host instance 941dad8261eSFinn Thain * @cmd: the scsi_cmnd to execute 9421da177e4SLinus Torvalds * 943dad8261eSFinn Thain * This routine establishes an I_T_L nexus for a SCSI command. This involves 944dad8261eSFinn Thain * ARBITRATION, SELECTION and MESSAGE OUT phases and an IDENTIFY message. 9451da177e4SLinus Torvalds * 946dad8261eSFinn Thain * Returns true if the operation should be retried. 947dad8261eSFinn Thain * Returns false if it should not be retried. 9481da177e4SLinus Torvalds * 9491da177e4SLinus Torvalds * Side effects : 9501da177e4SLinus Torvalds * If bus busy, arbitration failed, etc, NCR5380_select() will exit 9511da177e4SLinus Torvalds * with registers as they should have been on entry - ie 9521da177e4SLinus Torvalds * SELECT_ENABLE will be set appropriately, the NCR5380 9531da177e4SLinus Torvalds * will cease to drive any SCSI bus signals. 9541da177e4SLinus Torvalds * 955dad8261eSFinn Thain * If successful : the I_T_L nexus will be established, and 956dad8261eSFinn Thain * hostdata->connected will be set to cmd. 9571da177e4SLinus Torvalds * SELECT interrupt will be disabled. 9581da177e4SLinus Torvalds * 959117cd238SBart Van Assche * If failed (no target) : scsi_done() will be called, and the 9601da177e4SLinus Torvalds * cmd->result host byte set to DID_BAD_TARGET. 9611da177e4SLinus Torvalds */ 9621da177e4SLinus Torvalds 963dad8261eSFinn Thain static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) 9644ab2a787SFinn Thain __releases(&hostdata->lock) __acquires(&hostdata->lock) 9651da177e4SLinus Torvalds { 966e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 9671da177e4SLinus Torvalds unsigned char tmp[3], phase; 9681da177e4SLinus Torvalds unsigned char *data; 9691da177e4SLinus Torvalds int len; 9701da177e4SLinus Torvalds int err; 971dad8261eSFinn Thain bool ret = true; 9727c8ed783SFinn Thain bool can_disconnect = instance->irq != NO_IRQ && 9730b7a2235SFinn Thain cmd->cmnd[0] != REQUEST_SENSE && 9740b7a2235SFinn Thain (disconnect_mask & BIT(scmd_id(cmd))); 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_ARBITRATION, instance); 977b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n", 978b746545fSFinn Thain instance->this_id); 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds /* 981707d62b3SFinn Thain * Arbitration and selection phases are slow and involve dropping the 982707d62b3SFinn Thain * lock, so we have to watch out for EH. An exception handler may 983dad8261eSFinn Thain * change 'selecting' to NULL. This function will then return false 984707d62b3SFinn Thain * so that the caller will forget about 'cmd'. (During information 985707d62b3SFinn Thain * transfer phases, EH may change 'connected' to NULL.) 986707d62b3SFinn Thain */ 987707d62b3SFinn Thain hostdata->selecting = cmd; 988707d62b3SFinn Thain 989707d62b3SFinn Thain /* 9901da177e4SLinus Torvalds * Set the phase bits to 0, otherwise the NCR5380 won't drive the 9911da177e4SLinus Torvalds * data bus during SELECTION. 9921da177e4SLinus Torvalds */ 9931da177e4SLinus Torvalds 9941da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 9951da177e4SLinus Torvalds 9961da177e4SLinus Torvalds /* 9971da177e4SLinus Torvalds * Start arbitration. 9981da177e4SLinus Torvalds */ 9991da177e4SLinus Torvalds 10001da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); 10011da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_ARBITRATE); 10021da177e4SLinus Torvalds 100355500d9bSFinn Thain /* The chip now waits for BUS FREE phase. Then after the 800 ns 100455500d9bSFinn Thain * Bus Free Delay, arbitration will begin. 10051da177e4SLinus Torvalds */ 10061da177e4SLinus Torvalds 100711d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 1008d5d37a0aSFinn Thain err = NCR5380_poll_politely2(hostdata, MODE_REG, MR_ARBITRATE, 0, 1009b32ade12SFinn Thain INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, 1010b32ade12SFinn Thain ICR_ARBITRATION_PROGRESS, HZ); 101111d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 101255500d9bSFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) { 101355500d9bSFinn Thain /* Reselection interrupt */ 1014707d62b3SFinn Thain goto out; 101555500d9bSFinn Thain } 1016ccf6efd7SFinn Thain if (!hostdata->selecting) { 1017ccf6efd7SFinn Thain /* Command was aborted */ 1018ccf6efd7SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1019dad8261eSFinn Thain return false; 1020ccf6efd7SFinn Thain } 1021b32ade12SFinn Thain if (err < 0) { 1022b32ade12SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1023b32ade12SFinn Thain shost_printk(KERN_ERR, instance, 1024b32ade12SFinn Thain "select: arbitration timeout\n"); 1025707d62b3SFinn Thain goto out; 102655500d9bSFinn Thain } 102711d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 102855500d9bSFinn Thain 102955500d9bSFinn Thain /* The SCSI-2 arbitration delay is 2.4 us */ 10301da177e4SLinus Torvalds udelay(3); 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds /* Check for lost arbitration */ 10330d2cf867SFinn Thain if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || 10340d2cf867SFinn Thain (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || 10350d2cf867SFinn Thain (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { 10361da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 1037b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n"); 103811d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1039707d62b3SFinn Thain goto out; 10401da177e4SLinus Torvalds } 1041cf13b083SFinn Thain 1042cf13b083SFinn Thain /* After/during arbitration, BSY should be asserted. 1043cf13b083SFinn Thain * IBM DPES-31080 Version S31Q works now 1044cf13b083SFinn Thain * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) 1045cf13b083SFinn Thain */ 1046cf13b083SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, 1047cf13b083SFinn Thain ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY); 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds /* 10501da177e4SLinus Torvalds * Again, bus clear + bus settle time is 1.2us, however, this is 10511da177e4SLinus Torvalds * a minimum so we'll udelay ceil(1.2) 10521da177e4SLinus Torvalds */ 10531da177e4SLinus Torvalds 10549c3f0e2bSFinn Thain if (hostdata->flags & FLAG_TOSHIBA_DELAY) 10559c3f0e2bSFinn Thain udelay(15); 10569c3f0e2bSFinn Thain else 10571da177e4SLinus Torvalds udelay(2); 10581da177e4SLinus Torvalds 105911d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 106011d2f63bSFinn Thain 106172064a78SFinn Thain /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */ 106272064a78SFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) 1063707d62b3SFinn Thain goto out; 1064707d62b3SFinn Thain 1065707d62b3SFinn Thain if (!hostdata->selecting) { 1066707d62b3SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1067707d62b3SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1068dad8261eSFinn Thain return false; 1069707d62b3SFinn Thain } 107072064a78SFinn Thain 1071b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n"); 10721da177e4SLinus Torvalds 10731da177e4SLinus Torvalds /* 10741da177e4SLinus Torvalds * Now that we have won arbitration, start Selection process, asserting 10751da177e4SLinus Torvalds * the host and target ID's on the SCSI bus. 10761da177e4SLinus Torvalds */ 10771da177e4SLinus Torvalds 10783d07d22bSFinn Thain NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd))); 10791da177e4SLinus Torvalds 10801da177e4SLinus Torvalds /* 10811da177e4SLinus Torvalds * Raise ATN while SEL is true before BSY goes false from arbitration, 10821da177e4SLinus Torvalds * since this is the only way to guarantee that we'll get a MESSAGE OUT 10831da177e4SLinus Torvalds * phase immediately after selection. 10841da177e4SLinus Torvalds */ 10851da177e4SLinus Torvalds 10863d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY | 10873d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL); 10881da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 10891da177e4SLinus Torvalds 10901da177e4SLinus Torvalds /* 10911da177e4SLinus Torvalds * Reselect interrupts must be turned off prior to the dropping of BSY, 10921da177e4SLinus Torvalds * otherwise we will trigger an interrupt. 10931da177e4SLinus Torvalds */ 10941da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 10951da177e4SLinus Torvalds 109611d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 109711d2f63bSFinn Thain 10981da177e4SLinus Torvalds /* 10991da177e4SLinus Torvalds * The initiator shall then wait at least two deskew delays and release 11001da177e4SLinus Torvalds * the BSY signal. 11011da177e4SLinus Torvalds */ 11021da177e4SLinus Torvalds udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ 11031da177e4SLinus Torvalds 11041da177e4SLinus Torvalds /* Reset BSY */ 11053d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | 11063d07d22bSFinn Thain ICR_ASSERT_ATN | ICR_ASSERT_SEL); 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds /* 11091da177e4SLinus Torvalds * Something weird happens when we cease to drive BSY - looks 11101da177e4SLinus Torvalds * like the board/chip is letting us do another read before the 11111da177e4SLinus Torvalds * appropriate propagation delay has expired, and we're confusing 11121da177e4SLinus Torvalds * a BSY signal from ourselves as the target's response to SELECTION. 11131da177e4SLinus Torvalds * 11141da177e4SLinus Torvalds * A small delay (the 'C++' frontend breaks the pipeline with an 11151da177e4SLinus Torvalds * unnecessary jump, making it work on my 386-33/Trantor T128, the 11161da177e4SLinus Torvalds * tighter 'C' code breaks and requires this) solves the problem - 11171da177e4SLinus Torvalds * the 1 us delay is arbitrary, and only used because this delay will 11181da177e4SLinus Torvalds * be the same on other platforms and since it works here, it should 11191da177e4SLinus Torvalds * work there. 11201da177e4SLinus Torvalds * 11211da177e4SLinus Torvalds * wingel suggests that this could be due to failing to wait 11221da177e4SLinus Torvalds * one deskew delay. 11231da177e4SLinus Torvalds */ 11241da177e4SLinus Torvalds 11251da177e4SLinus Torvalds udelay(1); 11261da177e4SLinus Torvalds 1127b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd)); 11281da177e4SLinus Torvalds 11291da177e4SLinus Torvalds /* 11301da177e4SLinus Torvalds * The SCSI specification calls for a 250 ms timeout for the actual 11311da177e4SLinus Torvalds * selection. 11321da177e4SLinus Torvalds */ 11331da177e4SLinus Torvalds 1134d5d37a0aSFinn Thain err = NCR5380_poll_politely(hostdata, STATUS_REG, SR_BSY, SR_BSY, 1135ae753a33SFinn Thain msecs_to_jiffies(250)); 11361da177e4SLinus Torvalds 11371da177e4SLinus Torvalds if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { 113811d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 11391da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 11401da177e4SLinus Torvalds NCR5380_reselect(instance); 11416a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n"); 1142707d62b3SFinn Thain goto out; 11431da177e4SLinus Torvalds } 1144ae753a33SFinn Thain 1145ae753a33SFinn Thain if (err < 0) { 114611d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1147ae753a33SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 11486a162836SFinn Thain 1149707d62b3SFinn Thain /* Can't touch cmd if it has been reclaimed by the scsi ML */ 11506a162836SFinn Thain if (!hostdata->selecting) 1151dad8261eSFinn Thain return false; 11526a162836SFinn Thain 1153ae753a33SFinn Thain cmd->result = DID_BAD_TARGET << 16; 1154677e0194SFinn Thain complete_cmd(instance, cmd); 11556a162836SFinn Thain dsprintk(NDEBUG_SELECTION, instance, 11566a162836SFinn Thain "target did not respond within 250ms\n"); 1157dad8261eSFinn Thain ret = false; 1158707d62b3SFinn Thain goto out; 1159ae753a33SFinn Thain } 1160ae753a33SFinn Thain 11611da177e4SLinus Torvalds /* 11621da177e4SLinus Torvalds * No less than two deskew delays after the initiator detects the 11631da177e4SLinus Torvalds * BSY signal is true, it shall release the SEL signal and may 11641da177e4SLinus Torvalds * change the DATA BUS. -wingel 11651da177e4SLinus Torvalds */ 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds udelay(1); 11681da177e4SLinus Torvalds 11691da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds /* 11721da177e4SLinus Torvalds * Since we followed the SCSI spec, and raised ATN while SEL 11731da177e4SLinus Torvalds * was true but before BSY was false during selection, the information 11741da177e4SLinus Torvalds * transfer phase should be a MESSAGE OUT phase so that we can send the 11751da177e4SLinus Torvalds * IDENTIFY message. 11761da177e4SLinus Torvalds */ 11771da177e4SLinus Torvalds 11781da177e4SLinus Torvalds /* Wait for start of REQ/ACK handshake */ 11791da177e4SLinus Torvalds 1180d5d37a0aSFinn Thain err = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, HZ); 118111d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 11821cc160e1SFinn Thain if (err < 0) { 118355500d9bSFinn Thain shost_printk(KERN_ERR, instance, "select: REQ timeout\n"); 118455500d9bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1185707d62b3SFinn Thain goto out; 1186707d62b3SFinn Thain } 1187707d62b3SFinn Thain if (!hostdata->selecting) { 1188e7734ef1SAhmed S. Darwish do_abort(instance, 0); 1189dad8261eSFinn Thain return false; 11901da177e4SLinus Torvalds } 11911da177e4SLinus Torvalds 1192b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n", 1193b746545fSFinn Thain scmd_id(cmd)); 11947c8ed783SFinn Thain tmp[0] = IDENTIFY(can_disconnect, cmd->device->lun); 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds len = 1; 11971da177e4SLinus Torvalds data = tmp; 11981da177e4SLinus Torvalds phase = PHASE_MSGOUT; 1199e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &phase, &len, &data, 0); 1200b15e791dSFinn Thain if (len) { 1201b15e791dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1202b15e791dSFinn Thain cmd->result = DID_ERROR << 16; 1203b15e791dSFinn Thain complete_cmd(instance, cmd); 1204b15e791dSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "IDENTIFY message transfer failed\n"); 1205dad8261eSFinn Thain ret = false; 1206b15e791dSFinn Thain goto out; 1207b15e791dSFinn Thain } 1208b15e791dSFinn Thain 1209b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n"); 121011d2f63bSFinn Thain 12111da177e4SLinus Torvalds hostdata->connected = cmd; 12123d07d22bSFinn Thain hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun; 12131da177e4SLinus Torvalds 1214e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1215e9db3198SFinn Thain dregs->csr |= CSR_INTR; 1216e9db3198SFinn Thain #endif 1217e9db3198SFinn Thain 12181da177e4SLinus Torvalds initialize_SCp(cmd); 12191da177e4SLinus Torvalds 1220dad8261eSFinn Thain ret = false; 1221707d62b3SFinn Thain 1222707d62b3SFinn Thain out: 1223707d62b3SFinn Thain if (!hostdata->selecting) 122496edebd6SFinn Thain return false; 1225707d62b3SFinn Thain hostdata->selecting = NULL; 1226dad8261eSFinn Thain return ret; 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds 12298663cadeSFinn Thain /** 12308663cadeSFinn Thain * NCR5380_transfer_pio() - transfers data in given phase using polled I/O 12318663cadeSFinn Thain * @instance: instance of driver 12328663cadeSFinn Thain * @phase: pointer to what phase is expected 12338663cadeSFinn Thain * @count: pointer to number of bytes to transfer 12348663cadeSFinn Thain * @data: pointer to data pointer 12358663cadeSFinn Thain * @can_sleep: 1 or 0 when sleeping is permitted or not, respectively 12361da177e4SLinus Torvalds * 12378663cadeSFinn Thain * Returns: void. *phase, *count, *data are modified in place. 12381da177e4SLinus Torvalds */ 12391da177e4SLinus Torvalds 12401da177e4SLinus Torvalds /* 12411da177e4SLinus Torvalds * Note : this code is not as quick as it could be, however it 12421da177e4SLinus Torvalds * IS 100% reliable, and for the actual data transfer where speed 12431da177e4SLinus Torvalds * counts, we will always do a pseudo DMA or DMA transfer. 12441da177e4SLinus Torvalds */ 12451da177e4SLinus Torvalds 12468663cadeSFinn Thain static void NCR5380_transfer_pio(struct Scsi_Host *instance, 12470d2cf867SFinn Thain unsigned char *phase, int *count, 1248e7734ef1SAhmed S. Darwish unsigned char **data, unsigned int can_sleep) 12490d2cf867SFinn Thain { 125061e1ce58SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 12511da177e4SLinus Torvalds unsigned char p = *phase, tmp; 12521da177e4SLinus Torvalds int c = *count; 12531da177e4SLinus Torvalds unsigned char *d = *data; 12541da177e4SLinus Torvalds 12551da177e4SLinus Torvalds /* 12561da177e4SLinus Torvalds * The NCR5380 chip will only drive the SCSI bus when the 12571da177e4SLinus Torvalds * phase specified in the appropriate bits of the TARGET COMMAND 12581da177e4SLinus Torvalds * REGISTER match the STATUS REGISTER 12591da177e4SLinus Torvalds */ 12601da177e4SLinus Torvalds 12611da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 12621da177e4SLinus Torvalds 12631da177e4SLinus Torvalds do { 12641da177e4SLinus Torvalds /* 12651da177e4SLinus Torvalds * Wait for assertion of REQ, after which the phase bits will be 12661da177e4SLinus Torvalds * valid 12671da177e4SLinus Torvalds */ 12681da177e4SLinus Torvalds 1269086c4802SFinn Thain if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ | SR_BSY, 1270086c4802SFinn Thain SR_REQ | SR_BSY, HZ * can_sleep) < 0) 12711da177e4SLinus Torvalds break; 12721da177e4SLinus Torvalds 1273b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n"); 12741da177e4SLinus Torvalds 12751da177e4SLinus Torvalds /* Check for phase mismatch */ 1276686f3990SFinn Thain if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) { 1277b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "phase mismatch\n"); 1278b746545fSFinn Thain NCR5380_dprint_phase(NDEBUG_PIO, instance); 12791da177e4SLinus Torvalds break; 12801da177e4SLinus Torvalds } 12810d2cf867SFinn Thain 12821da177e4SLinus Torvalds /* Do actual transfer from SCSI bus to / from memory */ 12831da177e4SLinus Torvalds if (!(p & SR_IO)) 12841da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, *d); 12851da177e4SLinus Torvalds else 12861da177e4SLinus Torvalds *d = NCR5380_read(CURRENT_SCSI_DATA_REG); 12871da177e4SLinus Torvalds 12881da177e4SLinus Torvalds ++d; 12891da177e4SLinus Torvalds 12901da177e4SLinus Torvalds /* 12911da177e4SLinus Torvalds * The SCSI standard suggests that in MSGOUT phase, the initiator 12921da177e4SLinus Torvalds * should drop ATN on the last byte of the message phase 12931da177e4SLinus Torvalds * after REQ has been asserted for the handshake but before 12941da177e4SLinus Torvalds * the initiator raises ACK. 12951da177e4SLinus Torvalds */ 12961da177e4SLinus Torvalds 12971da177e4SLinus Torvalds if (!(p & SR_IO)) { 12981da177e4SLinus Torvalds if (!((p & SR_MSG) && c > 1)) { 12991da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 13001da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 13013d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 13023d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ACK); 13031da177e4SLinus Torvalds } else { 13043d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 13053d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ATN); 13061da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 13073d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 13083d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 13091da177e4SLinus Torvalds } 13101da177e4SLinus Torvalds } else { 13111da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 13121da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); 13131da177e4SLinus Torvalds } 13141da177e4SLinus Torvalds 1315d5d37a0aSFinn Thain if (NCR5380_poll_politely(hostdata, 1316e7734ef1SAhmed S. Darwish STATUS_REG, SR_REQ, 0, 5 * HZ * can_sleep) < 0) 1317a2edc4a6SFinn Thain break; 1318a2edc4a6SFinn Thain 1319b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n"); 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds /* 1322*a8ebca90SFinn Thain * We have several special cases to consider during REQ/ACK 1323*a8ebca90SFinn Thain * handshaking: 13241da177e4SLinus Torvalds * 1325*a8ebca90SFinn Thain * 1. We were in MSGOUT phase, and we are on the last byte of 1326*a8ebca90SFinn Thain * the message. ATN must be dropped as ACK is dropped. 1327*a8ebca90SFinn Thain * 1328*a8ebca90SFinn Thain * 2. We are in MSGIN phase, and we are on the last byte of the 13291da177e4SLinus Torvalds * message. We must exit with ACK asserted, so that the calling 13301da177e4SLinus Torvalds * code may raise ATN before dropping ACK to reject the message. 13311da177e4SLinus Torvalds * 1332*a8ebca90SFinn Thain * 3. ACK and ATN are clear & the target may proceed as normal. 13331da177e4SLinus Torvalds */ 13341da177e4SLinus Torvalds if (!(p == PHASE_MSGIN && c == 1)) { 13351da177e4SLinus Torvalds if (p == PHASE_MSGOUT && c > 1) 13361da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 13371da177e4SLinus Torvalds else 13381da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 13391da177e4SLinus Torvalds } 13401da177e4SLinus Torvalds } while (--c); 13411da177e4SLinus Torvalds 1342b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "residual %d\n", c); 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds *count = c; 13451da177e4SLinus Torvalds *data = d; 13461da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 1347a2edc4a6SFinn Thain /* The phase read from the bus is valid if either REQ is (already) 1348a2edc4a6SFinn Thain * asserted or if ACK hasn't been released yet. The latter applies if 1349a2edc4a6SFinn Thain * we're in MSG IN, DATA IN or STATUS and all bytes have been received. 1350a2edc4a6SFinn Thain */ 1351a2edc4a6SFinn Thain if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0)) 13521da177e4SLinus Torvalds *phase = tmp & PHASE_MASK; 13531da177e4SLinus Torvalds else 13541da177e4SLinus Torvalds *phase = PHASE_UNKNOWN; 13551da177e4SLinus Torvalds } 13561da177e4SLinus Torvalds 13571da177e4SLinus Torvalds /** 13581da177e4SLinus Torvalds * do_reset - issue a reset command 1359636b1ec8SFinn Thain * @instance: adapter to reset 13601da177e4SLinus Torvalds * 13611da177e4SLinus Torvalds * Issue a reset sequence to the NCR5380 and try and get the bus 13621da177e4SLinus Torvalds * back into sane shape. 13631da177e4SLinus Torvalds * 1364636b1ec8SFinn Thain * This clears the reset interrupt flag because there may be no handler for 1365636b1ec8SFinn Thain * it. When the driver is initialized, the NCR5380_intr() handler has not yet 1366636b1ec8SFinn Thain * been installed. And when in EH we may have released the ST DMA interrupt. 13671da177e4SLinus Torvalds */ 13681da177e4SLinus Torvalds 136954d8fe44SFinn Thain static void do_reset(struct Scsi_Host *instance) 137054d8fe44SFinn Thain { 137161e1ce58SFinn Thain struct NCR5380_hostdata __maybe_unused *hostdata = shost_priv(instance); 1372636b1ec8SFinn Thain unsigned long flags; 1373636b1ec8SFinn Thain 1374636b1ec8SFinn Thain local_irq_save(flags); 1375636b1ec8SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 1376636b1ec8SFinn Thain PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); 13771da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); 1378636b1ec8SFinn Thain udelay(50); 13791da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1380636b1ec8SFinn Thain (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); 1381636b1ec8SFinn Thain local_irq_restore(flags); 13821da177e4SLinus Torvalds } 13831da177e4SLinus Torvalds 138480d3eb6dSFinn Thain /** 138580d3eb6dSFinn Thain * do_abort - abort the currently established nexus by going to 138680d3eb6dSFinn Thain * MESSAGE OUT phase and sending an ABORT message. 138780d3eb6dSFinn Thain * @instance: relevant scsi host instance 1388e7734ef1SAhmed S. Darwish * @can_sleep: 1 or 0 when sleeping is permitted or not, respectively 13891da177e4SLinus Torvalds * 1390d04fc41aSFinn Thain * Returns 0 on success, negative error code on failure. 13911da177e4SLinus Torvalds */ 13921da177e4SLinus Torvalds 1393e7734ef1SAhmed S. Darwish static int do_abort(struct Scsi_Host *instance, unsigned int can_sleep) 139454d8fe44SFinn Thain { 139561e1ce58SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 13961da177e4SLinus Torvalds unsigned char *msgptr, phase, tmp; 13971da177e4SLinus Torvalds int len; 13981da177e4SLinus Torvalds int rc; 13991da177e4SLinus Torvalds 14001da177e4SLinus Torvalds /* Request message out phase */ 14011da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 14021da177e4SLinus Torvalds 14031da177e4SLinus Torvalds /* 14041da177e4SLinus Torvalds * Wait for the target to indicate a valid phase by asserting 14051da177e4SLinus Torvalds * REQ. Once this happens, we'll have either a MSGOUT phase 14061da177e4SLinus Torvalds * and can immediately send the ABORT message, or we'll have some 14071da177e4SLinus Torvalds * other phase and will have to source/sink data. 14081da177e4SLinus Torvalds * 14091da177e4SLinus Torvalds * We really don't care what value was on the bus or what value 14101da177e4SLinus Torvalds * the target sees, so we just handshake. 14111da177e4SLinus Torvalds */ 14121da177e4SLinus Torvalds 1413e7734ef1SAhmed S. Darwish rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, 1414e7734ef1SAhmed S. Darwish 10 * HZ * can_sleep); 14151da177e4SLinus Torvalds if (rc < 0) 1416d04fc41aSFinn Thain goto out; 14171da177e4SLinus Torvalds 1418f35d3474SFinn Thain tmp = NCR5380_read(STATUS_REG) & PHASE_MASK; 14191da177e4SLinus Torvalds 14201da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 14211da177e4SLinus Torvalds 1422f35d3474SFinn Thain if (tmp != PHASE_MSGOUT) { 14230d2cf867SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, 14240d2cf867SFinn Thain ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 1425e7734ef1SAhmed S. Darwish rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, 0, 1426e7734ef1SAhmed S. Darwish 3 * HZ * can_sleep); 14271cc160e1SFinn Thain if (rc < 0) 1428d04fc41aSFinn Thain goto out; 142980d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 14301da177e4SLinus Torvalds } 14310d2cf867SFinn Thain 14321da177e4SLinus Torvalds tmp = ABORT; 14331da177e4SLinus Torvalds msgptr = &tmp; 14341da177e4SLinus Torvalds len = 1; 14351da177e4SLinus Torvalds phase = PHASE_MSGOUT; 1436e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &phase, &len, &msgptr, can_sleep); 1437d04fc41aSFinn Thain if (len) 1438d04fc41aSFinn Thain rc = -ENXIO; 14391da177e4SLinus Torvalds 14401da177e4SLinus Torvalds /* 14411da177e4SLinus Torvalds * If we got here, and the command completed successfully, 14421da177e4SLinus Torvalds * we're about to go into bus free state. 14431da177e4SLinus Torvalds */ 14441da177e4SLinus Torvalds 1445d04fc41aSFinn Thain out: 144680d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1447d04fc41aSFinn Thain return rc; 14481da177e4SLinus Torvalds } 14491da177e4SLinus Torvalds 14501da177e4SLinus Torvalds /* 14511da177e4SLinus Torvalds * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 14521da177e4SLinus Torvalds * unsigned char *phase, int *count, unsigned char **data) 14531da177e4SLinus Torvalds * 14541da177e4SLinus Torvalds * Purpose : transfers data in given phase using either real 14551da177e4SLinus Torvalds * or pseudo DMA. 14561da177e4SLinus Torvalds * 14571da177e4SLinus Torvalds * Inputs : instance - instance of driver, *phase - pointer to 14581da177e4SLinus Torvalds * what phase is expected, *count - pointer to number of 14591da177e4SLinus Torvalds * bytes to transfer, **data - pointer to data pointer. 14601da177e4SLinus Torvalds * 14611da177e4SLinus Torvalds * Returns : -1 when different phase is entered without transferring 146225985edcSLucas De Marchi * maximum number of bytes, 0 if all bytes or transferred or exit 14631da177e4SLinus Torvalds * is in same phase. 14641da177e4SLinus Torvalds * 14651da177e4SLinus Torvalds * Also, *phase, *count, *data are modified in place. 14661da177e4SLinus Torvalds */ 14671da177e4SLinus Torvalds 14681da177e4SLinus Torvalds 14690d2cf867SFinn Thain static int NCR5380_transfer_dma(struct Scsi_Host *instance, 14700d2cf867SFinn Thain unsigned char *phase, int *count, 14710d2cf867SFinn Thain unsigned char **data) 14720d2cf867SFinn Thain { 14730d2cf867SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 14745768718dSFinn Thain struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(hostdata->connected); 1475f0ea73a4SFinn Thain int c = *count; 1476f0ea73a4SFinn Thain unsigned char p = *phase; 1477f0ea73a4SFinn Thain unsigned char *d = *data; 14781da177e4SLinus Torvalds unsigned char tmp; 14798053b0eeSFinn Thain int result = 0; 14801da177e4SLinus Torvalds 14811da177e4SLinus Torvalds if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { 14821da177e4SLinus Torvalds *phase = tmp; 14831da177e4SLinus Torvalds return -1; 14841da177e4SLinus Torvalds } 14851da177e4SLinus Torvalds 14865768718dSFinn Thain ncmd->phase = p; 14878053b0eeSFinn Thain 14888053b0eeSFinn Thain if (p & SR_IO) { 14898053b0eeSFinn Thain if (hostdata->read_overruns) 14908053b0eeSFinn Thain c -= hostdata->read_overruns; 14918053b0eeSFinn Thain else if (hostdata->flags & FLAG_DMA_FIXUP) 14928053b0eeSFinn Thain --c; 14938053b0eeSFinn Thain } 14948053b0eeSFinn Thain 14958053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n", 14968053b0eeSFinn Thain (p & SR_IO) ? "receive" : "send", c, d); 14978053b0eeSFinn Thain 1498e9db3198SFinn Thain #ifdef CONFIG_SUN3 1499e9db3198SFinn Thain /* send start chain */ 1500e9db3198SFinn Thain sun3scsi_dma_start(c, *data); 1501e9db3198SFinn Thain #endif 1502e9db3198SFinn Thain 15031da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 1504cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY | 1505cd400825SFinn Thain MR_ENABLE_EOP_INTR); 15061da177e4SLinus Torvalds 15078053b0eeSFinn Thain if (!(hostdata->flags & FLAG_LATE_DMA_SETUP)) { 15088053b0eeSFinn Thain /* On the Medusa, it is a must to initialize the DMA before 15098053b0eeSFinn Thain * starting the NCR. This is also the cleaner way for the TT. 15108053b0eeSFinn Thain */ 15118053b0eeSFinn Thain if (p & SR_IO) 15124a98f896SFinn Thain result = NCR5380_dma_recv_setup(hostdata, d, c); 15138053b0eeSFinn Thain else 15144a98f896SFinn Thain result = NCR5380_dma_send_setup(hostdata, d, c); 15158053b0eeSFinn Thain } 15161da177e4SLinus Torvalds 15171da177e4SLinus Torvalds /* 15181da177e4SLinus Torvalds * On the PAS16 at least I/O recovery delays are not needed here. 15191da177e4SLinus Torvalds * Everyone else seems to want them. 15201da177e4SLinus Torvalds */ 15211da177e4SLinus Torvalds 15221da177e4SLinus Torvalds if (p & SR_IO) { 1523e9db3198SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1524e5d55d1aSFinn Thain NCR5380_io_delay(1); 15251da177e4SLinus Torvalds NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); 15261da177e4SLinus Torvalds } else { 1527e5d55d1aSFinn Thain NCR5380_io_delay(1); 15281da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 1529e5d55d1aSFinn Thain NCR5380_io_delay(1); 15301da177e4SLinus Torvalds NCR5380_write(START_DMA_SEND_REG, 0); 1531e5d55d1aSFinn Thain NCR5380_io_delay(1); 15321da177e4SLinus Torvalds } 15331da177e4SLinus Torvalds 1534e9db3198SFinn Thain #ifdef CONFIG_SUN3 1535e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1536e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 1537e9db3198SFinn Thain #endif 1538e9db3198SFinn Thain sun3_dma_active = 1; 1539e9db3198SFinn Thain #endif 1540e9db3198SFinn Thain 15418053b0eeSFinn Thain if (hostdata->flags & FLAG_LATE_DMA_SETUP) { 15428053b0eeSFinn Thain /* On the Falcon, the DMA setup must be done after the last 15438053b0eeSFinn Thain * NCR access, else the DMA setup gets trashed! 15448053b0eeSFinn Thain */ 15458053b0eeSFinn Thain if (p & SR_IO) 15464a98f896SFinn Thain result = NCR5380_dma_recv_setup(hostdata, d, c); 15478053b0eeSFinn Thain else 15484a98f896SFinn Thain result = NCR5380_dma_send_setup(hostdata, d, c); 15498053b0eeSFinn Thain } 15508053b0eeSFinn Thain 15518053b0eeSFinn Thain /* On failure, NCR5380_dma_xxxx_setup() returns a negative int. */ 15528053b0eeSFinn Thain if (result < 0) 15538053b0eeSFinn Thain return result; 15548053b0eeSFinn Thain 15558053b0eeSFinn Thain /* For real DMA, result is the byte count. DMA interrupt is expected. */ 15568053b0eeSFinn Thain if (result > 0) { 15578053b0eeSFinn Thain hostdata->dma_len = result; 15588053b0eeSFinn Thain return 0; 15598053b0eeSFinn Thain } 15608053b0eeSFinn Thain 15618053b0eeSFinn Thain /* The result is zero iff pseudo DMA send/receive was completed. */ 15628053b0eeSFinn Thain hostdata->dma_len = c; 15638053b0eeSFinn Thain 15641da177e4SLinus Torvalds /* 1565e4dec680SFinn Thain * A note regarding the DMA errata workarounds for early NMOS silicon. 1566c16df32eSFinn Thain * 1567c16df32eSFinn Thain * For DMA sends, we want to wait until the last byte has been 1568c16df32eSFinn Thain * transferred out over the bus before we turn off DMA mode. Alas, there 1569c16df32eSFinn Thain * seems to be no terribly good way of doing this on a 5380 under all 1570c16df32eSFinn Thain * conditions. For non-scatter-gather operations, we can wait until REQ 1571c16df32eSFinn Thain * and ACK both go false, or until a phase mismatch occurs. Gather-sends 1572c16df32eSFinn Thain * are nastier, since the device will be expecting more data than we 1573*a8ebca90SFinn Thain * are prepared to send it, and REQ will remain asserted. On a 53C8[01] 1574*a8ebca90SFinn Thain * we could test Last Byte Sent to assure transfer (I imagine this is 1575*a8ebca90SFinn Thain * precisely why this signal was added to the newer chips) but on the 1576*a8ebca90SFinn Thain * older 538[01] this signal does not exist. The workaround for this 1577*a8ebca90SFinn Thain * lack is a watchdog; we bail out of the wait-loop after a modest 1578*a8ebca90SFinn Thain * amount of wait-time if the usual exit conditions are not met. 1579*a8ebca90SFinn Thain * Not a terribly clean or correct solution :-% 1580c16df32eSFinn Thain * 1581*a8ebca90SFinn Thain * DMA receive is equally tricky due to a nasty characteristic of the 1582*a8ebca90SFinn Thain * NCR5380. If the chip is in DMA receive mode, it will respond to a 1583*a8ebca90SFinn Thain * target's REQ by latching the SCSI data into the INPUT DATA register 1584*a8ebca90SFinn Thain * and asserting ACK, even if it has _already_ been notified by the 1585*a8ebca90SFinn Thain * DMA controller that the current DMA transfer has completed! If the 1586*a8ebca90SFinn Thain * NCR5380 is then taken out of DMA mode, this already-acknowledged 1587*a8ebca90SFinn Thain * byte is lost. 1588*a8ebca90SFinn Thain * 1589*a8ebca90SFinn Thain * This is not a problem for "one DMA transfer per READ 1590*a8ebca90SFinn Thain * command", because the situation will never arise... either all of 1591*a8ebca90SFinn Thain * the data is DMA'ed properly, or the target switches to MESSAGE IN 1592*a8ebca90SFinn Thain * phase to signal a disconnection (either operation bringing the DMA 1593*a8ebca90SFinn Thain * to a clean halt). However, in order to handle scatter-receive, we 1594*a8ebca90SFinn Thain * must work around the problem. The chosen fix is to DMA fewer bytes, 1595*a8ebca90SFinn Thain * then check for the condition before taking the NCR5380 out of DMA 1596*a8ebca90SFinn Thain * mode. One or two extra bytes are transferred via PIO as necessary 1597*a8ebca90SFinn Thain * to fill out the original request. 15981da177e4SLinus Torvalds */ 15991da177e4SLinus Torvalds 16005768718dSFinn Thain if ((hostdata->flags & FLAG_DMA_FIXUP) && 16015768718dSFinn Thain (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) { 16021da177e4SLinus Torvalds /* 1603e4dec680SFinn Thain * The workaround was to transfer fewer bytes than we 16045768718dSFinn Thain * intended to with the pseudo-DMA receive function, wait for 16051da177e4SLinus Torvalds * the chip to latch the last byte, read it, and then disable 16065768718dSFinn Thain * DMA mode. 16071da177e4SLinus Torvalds * 16081da177e4SLinus Torvalds * After REQ is asserted, the NCR5380 asserts DRQ and ACK. 16091da177e4SLinus Torvalds * REQ is deasserted when ACK is asserted, and not reasserted 16101da177e4SLinus Torvalds * until ACK goes false. Since the NCR5380 won't lower ACK 16111da177e4SLinus Torvalds * until DACK is asserted, which won't happen unless we twiddle 16121da177e4SLinus Torvalds * the DMA port or we take the NCR5380 out of DMA mode, we 16131da177e4SLinus Torvalds * can guarantee that we won't handshake another extra 16141da177e4SLinus Torvalds * byte. 16155768718dSFinn Thain * 16165768718dSFinn Thain * If sending, wait for the last byte to be sent. If REQ is 16175768718dSFinn Thain * being asserted for the byte we're interested, we'll ACK it 16185768718dSFinn Thain * and it will go false. 16191da177e4SLinus Torvalds */ 16205768718dSFinn Thain if (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, 16215768718dSFinn Thain BASR_DRQ, BASR_DRQ, 0)) { 16225768718dSFinn Thain if ((p & SR_IO) && 16235768718dSFinn Thain (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) { 16245768718dSFinn Thain if (!NCR5380_poll_politely(hostdata, STATUS_REG, 16255768718dSFinn Thain SR_REQ, 0, 0)) { 16265768718dSFinn Thain d[c] = NCR5380_read(INPUT_DATA_REG); 16275768718dSFinn Thain --ncmd->this_residual; 16281da177e4SLinus Torvalds } else { 1629438af51cSFinn Thain result = -1; 16305768718dSFinn Thain scmd_printk(KERN_ERR, hostdata->connected, 16315768718dSFinn Thain "PDMA fixup: !REQ timeout\n"); 16321da177e4SLinus Torvalds } 16331da177e4SLinus Torvalds } 16345768718dSFinn Thain } else if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH) { 16355768718dSFinn Thain result = -1; 16365768718dSFinn Thain scmd_printk(KERN_ERR, hostdata->connected, 16375768718dSFinn Thain "PDMA fixup: DRQ timeout\n"); 16385768718dSFinn Thain } 16391da177e4SLinus Torvalds } 16408053b0eeSFinn Thain 16418053b0eeSFinn Thain NCR5380_dma_complete(instance); 1642438af51cSFinn Thain return result; 16431da177e4SLinus Torvalds } 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds /* 16461da177e4SLinus Torvalds * Function : NCR5380_information_transfer (struct Scsi_Host *instance) 16471da177e4SLinus Torvalds * 16481da177e4SLinus Torvalds * Purpose : run through the various SCSI phases and do as the target 16491da177e4SLinus Torvalds * directs us to. Operates on the currently connected command, 16501da177e4SLinus Torvalds * instance->connected. 16511da177e4SLinus Torvalds * 16521da177e4SLinus Torvalds * Inputs : instance, instance for which we are doing commands 16531da177e4SLinus Torvalds * 16541da177e4SLinus Torvalds * Side effects : SCSI things happen, the disconnected queue will be 16551da177e4SLinus Torvalds * modified if a command disconnects, *instance->connected will 16561da177e4SLinus Torvalds * change. 16571da177e4SLinus Torvalds */ 16581da177e4SLinus Torvalds 16590d2cf867SFinn Thain static void NCR5380_information_transfer(struct Scsi_Host *instance) 16604ab2a787SFinn Thain __releases(&hostdata->lock) __acquires(&hostdata->lock) 16610d2cf867SFinn Thain { 1662e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 16631da177e4SLinus Torvalds unsigned char msgout = NOP; 16641da177e4SLinus Torvalds int sink = 0; 16651da177e4SLinus Torvalds int len; 16661da177e4SLinus Torvalds int transfersize; 16671da177e4SLinus Torvalds unsigned char *data; 16681da177e4SLinus Torvalds unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; 166911d2f63bSFinn Thain struct scsi_cmnd *cmd; 16701da177e4SLinus Torvalds 1671e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1672e9db3198SFinn Thain dregs->csr |= CSR_INTR; 1673e9db3198SFinn Thain #endif 1674e9db3198SFinn Thain 167511d2f63bSFinn Thain while ((cmd = hostdata->connected)) { 1676ff1269cbSFinn Thain struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd); 167732b26a10SFinn Thain 16781da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 16791da177e4SLinus Torvalds /* We only have a valid SCSI phase when REQ is asserted */ 16801da177e4SLinus Torvalds if (tmp & SR_REQ) { 16811da177e4SLinus Torvalds phase = (tmp & PHASE_MASK); 16821da177e4SLinus Torvalds if (phase != old_phase) { 16831da177e4SLinus Torvalds old_phase = phase; 16841da177e4SLinus Torvalds NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); 16851da177e4SLinus Torvalds } 1686e9db3198SFinn Thain #ifdef CONFIG_SUN3 16874a98f896SFinn Thain if (phase == PHASE_CMDOUT && 16884a98f896SFinn Thain sun3_dma_setup_done != cmd) { 16894a98f896SFinn Thain int count; 1690e9db3198SFinn Thain 1691ff1269cbSFinn Thain advance_sg_buffer(ncmd); 1692e9db3198SFinn Thain 16934a98f896SFinn Thain count = sun3scsi_dma_xfer_len(hostdata, cmd); 16944a98f896SFinn Thain 16954a98f896SFinn Thain if (count > 0) { 16962e4b231aSBart Van Assche if (cmd->sc_data_direction == DMA_TO_DEVICE) 16974a98f896SFinn Thain sun3scsi_dma_send_setup(hostdata, 1698ff1269cbSFinn Thain ncmd->ptr, count); 16994a98f896SFinn Thain else 17004a98f896SFinn Thain sun3scsi_dma_recv_setup(hostdata, 1701ff1269cbSFinn Thain ncmd->ptr, count); 1702e9db3198SFinn Thain sun3_dma_setup_done = cmd; 1703e9db3198SFinn Thain } 1704e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1705e9db3198SFinn Thain dregs->csr |= CSR_INTR; 1706e9db3198SFinn Thain #endif 1707e9db3198SFinn Thain } 1708e9db3198SFinn Thain #endif /* CONFIG_SUN3 */ 1709e9db3198SFinn Thain 17101da177e4SLinus Torvalds if (sink && (phase != PHASE_MSGOUT)) { 17111da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 17121da177e4SLinus Torvalds 17133d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 17143d07d22bSFinn Thain ICR_ASSERT_ACK); 17150d2cf867SFinn Thain while (NCR5380_read(STATUS_REG) & SR_REQ) 17160d2cf867SFinn Thain ; 17173d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 17183d07d22bSFinn Thain ICR_ASSERT_ATN); 17191da177e4SLinus Torvalds sink = 0; 17201da177e4SLinus Torvalds continue; 17211da177e4SLinus Torvalds } 17220d2cf867SFinn Thain 17231da177e4SLinus Torvalds switch (phase) { 17241da177e4SLinus Torvalds case PHASE_DATAOUT: 17251da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_DATAOUT) 17266a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n"); 17271da177e4SLinus Torvalds sink = 1; 1728e7734ef1SAhmed S. Darwish do_abort(instance, 0); 17291da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 1730677e0194SFinn Thain complete_cmd(instance, cmd); 1731dc183965SFinn Thain hostdata->connected = NULL; 173245ddc1b2SFinn Thain hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); 17331da177e4SLinus Torvalds return; 17341da177e4SLinus Torvalds #endif 1735bf1a0c6fSFinn Thain case PHASE_DATAIN: 17361da177e4SLinus Torvalds /* 17371da177e4SLinus Torvalds * If there is no room left in the current buffer in the 17381da177e4SLinus Torvalds * scatter-gather list, move onto the next one. 17391da177e4SLinus Torvalds */ 17401da177e4SLinus Torvalds 1741ff1269cbSFinn Thain advance_sg_buffer(ncmd); 17420e9fdd2bSFinn Thain dsprintk(NDEBUG_INFORMATION, instance, 17430e9fdd2bSFinn Thain "this residual %d, sg ents %d\n", 1744ff1269cbSFinn Thain ncmd->this_residual, 1745ff1269cbSFinn Thain sg_nents(ncmd->buffer)); 17460d2cf867SFinn Thain 17471da177e4SLinus Torvalds /* 17481da177e4SLinus Torvalds * The preferred transfer method is going to be 17491da177e4SLinus Torvalds * PSEUDO-DMA for systems that are strictly PIO, 17501da177e4SLinus Torvalds * since we can let the hardware do the handshaking. 17511da177e4SLinus Torvalds * 17521da177e4SLinus Torvalds * For this to work, we need to know the transfersize 17531da177e4SLinus Torvalds * ahead of time, since the pseudo-DMA code will sit 17541da177e4SLinus Torvalds * in an unconditional loop. 17551da177e4SLinus Torvalds */ 17561da177e4SLinus Torvalds 1757ff3d4578SFinn Thain transfersize = 0; 17587e9ec8d9SFinn Thain if (!cmd->device->borken) 17594a98f896SFinn Thain transfersize = NCR5380_dma_xfer_len(hostdata, cmd); 17601da177e4SLinus Torvalds 1761438af51cSFinn Thain if (transfersize > 0) { 17621da177e4SLinus Torvalds len = transfersize; 17630d2cf867SFinn Thain if (NCR5380_transfer_dma(instance, &phase, 1764ff1269cbSFinn Thain &len, (unsigned char **)&ncmd->ptr)) { 17651da177e4SLinus Torvalds /* 17660d2cf867SFinn Thain * If the watchdog timer fires, all future 17670d2cf867SFinn Thain * accesses to this device will use the 17680d2cf867SFinn Thain * polled-IO. 17691da177e4SLinus Torvalds */ 1770017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 1771017560fcSJeff Garzik "switching to slow handshake\n"); 17721da177e4SLinus Torvalds cmd->device->borken = 1; 1773f9dfed1cSFinn Thain do_reset(instance); 1774f9dfed1cSFinn Thain bus_reset_cleanup(instance); 17758053b0eeSFinn Thain } 1776f825e40bSFinn Thain } else { 177708348b1cSFinn Thain /* Transfer a small chunk so that the 177808348b1cSFinn Thain * irq mode lock is not held too long. 17791678847eSFinn Thain */ 1780ff1269cbSFinn Thain transfersize = min(ncmd->this_residual, 178108348b1cSFinn Thain NCR5380_PIO_CHUNK_SIZE); 17821678847eSFinn Thain len = transfersize; 17831678847eSFinn Thain NCR5380_transfer_pio(instance, &phase, &len, 1784ff1269cbSFinn Thain (unsigned char **)&ncmd->ptr, 1785e7734ef1SAhmed S. Darwish 0); 1786ff1269cbSFinn Thain ncmd->this_residual -= transfersize - len; 178711d2f63bSFinn Thain } 1788e9db3198SFinn Thain #ifdef CONFIG_SUN3 1789e9db3198SFinn Thain if (sun3_dma_setup_done == cmd) 1790e9db3198SFinn Thain sun3_dma_setup_done = NULL; 1791e9db3198SFinn Thain #endif 17921678847eSFinn Thain return; 17931da177e4SLinus Torvalds case PHASE_MSGIN: 17941da177e4SLinus Torvalds len = 1; 17951c71065dSFinn Thain tmp = 0xff; 17961da177e4SLinus Torvalds data = &tmp; 1797e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &phase, &len, &data, 0); 17981c71065dSFinn Thain if (tmp == 0xff) 17991c71065dSFinn Thain break; 18001da177e4SLinus Torvalds 18011da177e4SLinus Torvalds switch (tmp) { 18021da177e4SLinus Torvalds case ABORT: 18037b25bdb1SHannes Reinecke set_host_byte(cmd, DID_ABORT); 180461f4f11bSGustavo A. R. Silva fallthrough; 18051da177e4SLinus Torvalds case COMMAND_COMPLETE: 18061da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18071da177e4SLinus Torvalds sink = 1; 18081da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18090d3d9a42SFinn Thain dsprintk(NDEBUG_QUEUES, instance, 18100d3d9a42SFinn Thain "COMMAND COMPLETE %p target %d lun %llu\n", 18110d3d9a42SFinn Thain cmd, scmd_id(cmd), cmd->device->lun); 18120d3d9a42SFinn Thain 18131da177e4SLinus Torvalds hostdata->connected = NULL; 181445ddc1b2SFinn Thain hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); 18151da177e4SLinus Torvalds 1816ff1269cbSFinn Thain set_status_byte(cmd, ncmd->status); 18171da177e4SLinus Torvalds 1818350767f2SFinn Thain set_resid_from_SCp(cmd); 1819350767f2SFinn Thain 1820f27db8ebSFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 1821f27db8ebSFinn Thain complete_cmd(instance, cmd); 1822f27db8ebSFinn Thain else { 1823ff1269cbSFinn Thain if (ncmd->status == SAM_STAT_CHECK_CONDITION || 1824ff1269cbSFinn Thain ncmd->status == SAM_STAT_COMMAND_TERMINATED) { 1825f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n", 1826dbb6b350SFinn Thain cmd); 1827f27db8ebSFinn Thain list_add_tail(&ncmd->list, 1828f27db8ebSFinn Thain &hostdata->autosense); 1829f27db8ebSFinn Thain } else 1830677e0194SFinn Thain complete_cmd(instance, cmd); 18311da177e4SLinus Torvalds } 18321da177e4SLinus Torvalds 18331da177e4SLinus Torvalds /* 18341da177e4SLinus Torvalds * Restore phase bits to 0 so an interrupted selection, 18351da177e4SLinus Torvalds * arbitration can resume. 18361da177e4SLinus Torvalds */ 18371da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 183872064a78SFinn Thain 18391da177e4SLinus Torvalds return; 18401da177e4SLinus Torvalds case MESSAGE_REJECT: 18411da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18421da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18431da177e4SLinus Torvalds switch (hostdata->last_message) { 18441da177e4SLinus Torvalds case HEAD_OF_QUEUE_TAG: 18451da177e4SLinus Torvalds case ORDERED_QUEUE_TAG: 18461da177e4SLinus Torvalds case SIMPLE_QUEUE_TAG: 18471da177e4SLinus Torvalds cmd->device->simple_tags = 0; 18489cb78c16SHannes Reinecke hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF)); 18491da177e4SLinus Torvalds break; 18501da177e4SLinus Torvalds default: 18511da177e4SLinus Torvalds break; 18521da177e4SLinus Torvalds } 1853340b9612SFinn Thain break; 18540d2cf867SFinn Thain case DISCONNECT: 18551da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18561da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18571da177e4SLinus Torvalds hostdata->connected = NULL; 185832b26a10SFinn Thain list_add(&ncmd->list, &hostdata->disconnected); 18590d3d9a42SFinn Thain dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES, 18600d3d9a42SFinn Thain instance, "connected command %p for target %d lun %llu moved to disconnected queue\n", 18610d3d9a42SFinn Thain cmd, scmd_id(cmd), cmd->device->lun); 18620d3d9a42SFinn Thain 18631da177e4SLinus Torvalds /* 18641da177e4SLinus Torvalds * Restore phase bits to 0 so an interrupted selection, 18651da177e4SLinus Torvalds * arbitration can resume. 18661da177e4SLinus Torvalds */ 18671da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 18681da177e4SLinus Torvalds 1869e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1870e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 1871e9db3198SFinn Thain #endif 18721da177e4SLinus Torvalds return; 18731da177e4SLinus Torvalds /* 18741da177e4SLinus Torvalds * The SCSI data pointer is *IMPLICITLY* saved on a disconnect 18751da177e4SLinus Torvalds * operation, in violation of the SCSI spec so we can safely 18761da177e4SLinus Torvalds * ignore SAVE/RESTORE pointers calls. 18771da177e4SLinus Torvalds * 18781da177e4SLinus Torvalds * Unfortunately, some disks violate the SCSI spec and 18791da177e4SLinus Torvalds * don't issue the required SAVE_POINTERS message before 18801da177e4SLinus Torvalds * disconnecting, and we have to break spec to remain 18811da177e4SLinus Torvalds * compatible. 18821da177e4SLinus Torvalds */ 18831da177e4SLinus Torvalds case SAVE_POINTERS: 18841da177e4SLinus Torvalds case RESTORE_POINTERS: 18851da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18861da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18871da177e4SLinus Torvalds break; 18881da177e4SLinus Torvalds case EXTENDED_MESSAGE: 18891da177e4SLinus Torvalds /* 1890c16df32eSFinn Thain * Start the message buffer with the EXTENDED_MESSAGE 18911abfd370SMatthew Wilcox * byte, since spi_print_msg() wants the whole thing. 18921da177e4SLinus Torvalds */ 18931da177e4SLinus Torvalds extended_msg[0] = EXTENDED_MESSAGE; 18941da177e4SLinus Torvalds /* Accept first byte by clearing ACK */ 18951da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 189611d2f63bSFinn Thain 189711d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 189811d2f63bSFinn Thain 1899b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n"); 19001da177e4SLinus Torvalds 19011da177e4SLinus Torvalds len = 2; 19021da177e4SLinus Torvalds data = extended_msg + 1; 19031da177e4SLinus Torvalds phase = PHASE_MSGIN; 1904e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &phase, &len, &data, 1); 1905b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n", 1906b746545fSFinn Thain (int)extended_msg[1], 1907b746545fSFinn Thain (int)extended_msg[2]); 19081da177e4SLinus Torvalds 1909e0783ed3SFinn Thain if (!len && extended_msg[1] > 0 && 1910e0783ed3SFinn Thain extended_msg[1] <= sizeof(extended_msg) - 2) { 19111da177e4SLinus Torvalds /* Accept third byte by clearing ACK */ 19121da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 19131da177e4SLinus Torvalds len = extended_msg[1] - 1; 19141da177e4SLinus Torvalds data = extended_msg + 3; 19151da177e4SLinus Torvalds phase = PHASE_MSGIN; 19161da177e4SLinus Torvalds 1917e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &phase, &len, &data, 1); 1918b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n", 1919b746545fSFinn Thain len); 19201da177e4SLinus Torvalds 19211da177e4SLinus Torvalds switch (extended_msg[2]) { 19221da177e4SLinus Torvalds case EXTENDED_SDTR: 19231da177e4SLinus Torvalds case EXTENDED_WDTR: 19241da177e4SLinus Torvalds tmp = 0; 19251da177e4SLinus Torvalds } 19261da177e4SLinus Torvalds } else if (len) { 19276a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "error receiving extended message\n"); 19281da177e4SLinus Torvalds tmp = 0; 19291da177e4SLinus Torvalds } else { 19306a6ff4acSFinn Thain shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n", 19316a6ff4acSFinn Thain extended_msg[2], extended_msg[1]); 19321da177e4SLinus Torvalds tmp = 0; 19331da177e4SLinus Torvalds } 193411d2f63bSFinn Thain 193511d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 193611d2f63bSFinn Thain if (!hostdata->connected) 193711d2f63bSFinn Thain return; 193811d2f63bSFinn Thain 1939df135e32SFinn Thain /* Reject message */ 1940df561f66SGustavo A. R. Silva fallthrough; 1941df135e32SFinn Thain default: 19421da177e4SLinus Torvalds /* 19431da177e4SLinus Torvalds * If we get something weird that we aren't expecting, 1944df135e32SFinn Thain * log it. 19451da177e4SLinus Torvalds */ 194639bef87cSFinn Thain if (tmp == EXTENDED_MESSAGE) 1947017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 19480d2cf867SFinn Thain "rejecting unknown extended message code %02x, length %d\n", 194939bef87cSFinn Thain extended_msg[2], extended_msg[1]); 195039bef87cSFinn Thain else if (tmp) 195139bef87cSFinn Thain scmd_printk(KERN_INFO, cmd, 195239bef87cSFinn Thain "rejecting unknown message code %02x\n", 195339bef87cSFinn Thain tmp); 19541da177e4SLinus Torvalds 19551da177e4SLinus Torvalds msgout = MESSAGE_REJECT; 19561da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 19571da177e4SLinus Torvalds break; 19581da177e4SLinus Torvalds } /* switch (tmp) */ 19591da177e4SLinus Torvalds break; 19601da177e4SLinus Torvalds case PHASE_MSGOUT: 19611da177e4SLinus Torvalds len = 1; 19621da177e4SLinus Torvalds data = &msgout; 19631da177e4SLinus Torvalds hostdata->last_message = msgout; 1964e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &phase, &len, &data, 0); 19651da177e4SLinus Torvalds if (msgout == ABORT) { 19661da177e4SLinus Torvalds hostdata->connected = NULL; 196745ddc1b2SFinn Thain hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); 19681da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 1969677e0194SFinn Thain complete_cmd(instance, cmd); 19701da177e4SLinus Torvalds return; 19711da177e4SLinus Torvalds } 19721da177e4SLinus Torvalds msgout = NOP; 19731da177e4SLinus Torvalds break; 19741da177e4SLinus Torvalds case PHASE_CMDOUT: 19751da177e4SLinus Torvalds len = cmd->cmd_len; 19761da177e4SLinus Torvalds data = cmd->cmnd; 19771da177e4SLinus Torvalds /* 19781da177e4SLinus Torvalds * XXX for performance reasons, on machines with a 19791da177e4SLinus Torvalds * PSEUDO-DMA architecture we should probably 19801da177e4SLinus Torvalds * use the dma transfer function. 19811da177e4SLinus Torvalds */ 1982e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &phase, &len, &data, 0); 19831da177e4SLinus Torvalds break; 19841da177e4SLinus Torvalds case PHASE_STATIN: 19851da177e4SLinus Torvalds len = 1; 19861c71065dSFinn Thain tmp = ncmd->status; 19871da177e4SLinus Torvalds data = &tmp; 1988e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &phase, &len, &data, 0); 1989ff1269cbSFinn Thain ncmd->status = tmp; 19901da177e4SLinus Torvalds break; 19911da177e4SLinus Torvalds default: 19926a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "unknown phase\n"); 19934dde8f7dSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 19941da177e4SLinus Torvalds } /* switch(phase) */ 1995686f3990SFinn Thain } else { 1996086c4802SFinn Thain int err; 1997086c4802SFinn Thain 199811d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 1999086c4802SFinn Thain err = NCR5380_poll_politely(hostdata, STATUS_REG, 2000086c4802SFinn Thain SR_REQ, SR_REQ, HZ); 200111d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 2002086c4802SFinn Thain 2003086c4802SFinn Thain if (err < 0 && hostdata->connected && 2004086c4802SFinn Thain !(NCR5380_read(STATUS_REG) & SR_BSY)) { 2005086c4802SFinn Thain scmd_printk(KERN_ERR, hostdata->connected, 2006086c4802SFinn Thain "BSY signal lost\n"); 2007086c4802SFinn Thain do_reset(instance); 2008086c4802SFinn Thain bus_reset_cleanup(instance); 2009086c4802SFinn Thain } 20101da177e4SLinus Torvalds } 201111d2f63bSFinn Thain } 20121da177e4SLinus Torvalds } 20131da177e4SLinus Torvalds 20141da177e4SLinus Torvalds /* 20151da177e4SLinus Torvalds * Function : void NCR5380_reselect (struct Scsi_Host *instance) 20161da177e4SLinus Torvalds * 20171da177e4SLinus Torvalds * Purpose : does reselection, initializing the instance->connected 2018710ddd0dSFinn Thain * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q 20191da177e4SLinus Torvalds * nexus has been reestablished, 20201da177e4SLinus Torvalds * 20211da177e4SLinus Torvalds * Inputs : instance - this instance of the NCR5380. 20221da177e4SLinus Torvalds */ 20231da177e4SLinus Torvalds 20240d2cf867SFinn Thain static void NCR5380_reselect(struct Scsi_Host *instance) 20250d2cf867SFinn Thain { 2026e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 20271da177e4SLinus Torvalds unsigned char target_mask; 2028e9db3198SFinn Thain unsigned char lun; 20291da177e4SLinus Torvalds unsigned char msg[3]; 203032b26a10SFinn Thain struct NCR5380_cmd *ncmd; 203132b26a10SFinn Thain struct scsi_cmnd *tmp; 20321da177e4SLinus Torvalds 20331da177e4SLinus Torvalds /* 20341da177e4SLinus Torvalds * Disable arbitration, etc. since the host adapter obviously 20351da177e4SLinus Torvalds * lost, and tell an interrupted NCR5380_select() to restart. 20361da177e4SLinus Torvalds */ 20371da177e4SLinus Torvalds 20381da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 20391da177e4SLinus Torvalds 20401da177e4SLinus Torvalds target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); 20417ef55f67SFinn Thain if (!target_mask || target_mask & (target_mask - 1)) { 20427ef55f67SFinn Thain shost_printk(KERN_WARNING, instance, 20437ef55f67SFinn Thain "reselect: bad target_mask 0x%02x\n", target_mask); 20447ef55f67SFinn Thain return; 20457ef55f67SFinn Thain } 2046b746545fSFinn Thain 20471da177e4SLinus Torvalds /* 20481da177e4SLinus Torvalds * At this point, we have detected that our SCSI ID is on the bus, 20491da177e4SLinus Torvalds * SEL is true and BSY was false for at least one bus settle delay 20501da177e4SLinus Torvalds * (400 ns). 20511da177e4SLinus Torvalds * 20521da177e4SLinus Torvalds * We must assert BSY ourselves, until the target drops the SEL 20531da177e4SLinus Torvalds * signal. 20541da177e4SLinus Torvalds */ 20551da177e4SLinus Torvalds 20561da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); 2057d5d37a0aSFinn Thain if (NCR5380_poll_politely(hostdata, 2058e7734ef1SAhmed S. Darwish STATUS_REG, SR_SEL, 0, 0) < 0) { 205908267216SFinn Thain shost_printk(KERN_ERR, instance, "reselect: !SEL timeout\n"); 206072064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 206172064a78SFinn Thain return; 206272064a78SFinn Thain } 20631da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 20641da177e4SLinus Torvalds 20651da177e4SLinus Torvalds /* 20661da177e4SLinus Torvalds * Wait for target to go into MSGIN. 20671da177e4SLinus Torvalds */ 20681da177e4SLinus Torvalds 2069d5d37a0aSFinn Thain if (NCR5380_poll_politely(hostdata, 2070e7734ef1SAhmed S. Darwish STATUS_REG, SR_REQ, SR_REQ, 0) < 0) { 2071ca694afaSFinn Thain if ((NCR5380_read(STATUS_REG) & (SR_BSY | SR_SEL)) == 0) 2072ca694afaSFinn Thain /* BUS FREE phase */ 2073ca694afaSFinn Thain return; 207408267216SFinn Thain shost_printk(KERN_ERR, instance, "reselect: REQ timeout\n"); 2075e7734ef1SAhmed S. Darwish do_abort(instance, 0); 207672064a78SFinn Thain return; 207772064a78SFinn Thain } 20781da177e4SLinus Torvalds 2079e9db3198SFinn Thain #ifdef CONFIG_SUN3 2080e9db3198SFinn Thain /* acknowledge toggle to MSGIN */ 2081e9db3198SFinn Thain NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN)); 2082e9db3198SFinn Thain 2083e9db3198SFinn Thain /* peek at the byte without really hitting the bus */ 2084e9db3198SFinn Thain msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG); 2085e9db3198SFinn Thain #else 2086e9db3198SFinn Thain { 2087e9db3198SFinn Thain int len = 1; 2088e9db3198SFinn Thain unsigned char *data = msg; 2089e9db3198SFinn Thain unsigned char phase = PHASE_MSGIN; 2090e9db3198SFinn Thain 2091e7734ef1SAhmed S. Darwish NCR5380_transfer_pio(instance, &phase, &len, &data, 0); 20921da177e4SLinus Torvalds 209372064a78SFinn Thain if (len) { 2094e7734ef1SAhmed S. Darwish do_abort(instance, 0); 209572064a78SFinn Thain return; 209672064a78SFinn Thain } 2097e9db3198SFinn Thain } 2098e9db3198SFinn Thain #endif /* CONFIG_SUN3 */ 209972064a78SFinn Thain 21001da177e4SLinus Torvalds if (!(msg[0] & 0x80)) { 210172064a78SFinn Thain shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got "); 21021abfd370SMatthew Wilcox spi_print_msg(msg); 210372064a78SFinn Thain printk("\n"); 2104e7734ef1SAhmed S. Darwish do_abort(instance, 0); 210572064a78SFinn Thain return; 210672064a78SFinn Thain } 210772064a78SFinn Thain lun = msg[0] & 0x07; 21081da177e4SLinus Torvalds 21091da177e4SLinus Torvalds /* 21101da177e4SLinus Torvalds * We need to add code for SCSI-II to track which devices have 21111da177e4SLinus Torvalds * I_T_L_Q nexuses established, and which have simple I_T_L 21121da177e4SLinus Torvalds * nexuses so we can chose to do additional data transfer. 21131da177e4SLinus Torvalds */ 21141da177e4SLinus Torvalds 21151da177e4SLinus Torvalds /* 21161da177e4SLinus Torvalds * Find the command corresponding to the I_T_L or I_T_L_Q nexus we 21171da177e4SLinus Torvalds * just reestablished, and remove it from the disconnected queue. 21181da177e4SLinus Torvalds */ 21191da177e4SLinus Torvalds 212032b26a10SFinn Thain tmp = NULL; 212132b26a10SFinn Thain list_for_each_entry(ncmd, &hostdata->disconnected, list) { 212232b26a10SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 212332b26a10SFinn Thain 212432b26a10SFinn Thain if (target_mask == (1 << scmd_id(cmd)) && 212532b26a10SFinn Thain lun == (u8)cmd->device->lun) { 212632b26a10SFinn Thain list_del(&ncmd->list); 212732b26a10SFinn Thain tmp = cmd; 21281da177e4SLinus Torvalds break; 21291da177e4SLinus Torvalds } 213072064a78SFinn Thain } 21310d3d9a42SFinn Thain 21320d3d9a42SFinn Thain if (tmp) { 21330d3d9a42SFinn Thain dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance, 21340d3d9a42SFinn Thain "reselect: removed %p from disconnected queue\n", tmp); 21350d3d9a42SFinn Thain } else { 213645ddc1b2SFinn Thain int target = ffs(target_mask) - 1; 213745ddc1b2SFinn Thain 213872064a78SFinn Thain shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n", 213972064a78SFinn Thain target_mask, lun); 21401da177e4SLinus Torvalds /* 21410d2cf867SFinn Thain * Since we have an established nexus that we can't do anything 21420d2cf867SFinn Thain * with, we must abort it. 21431da177e4SLinus Torvalds */ 2144e7734ef1SAhmed S. Darwish if (do_abort(instance, 0) == 0) 214545ddc1b2SFinn Thain hostdata->busy[target] &= ~(1 << lun); 214672064a78SFinn Thain return; 21471da177e4SLinus Torvalds } 21481da177e4SLinus Torvalds 2149e9db3198SFinn Thain #ifdef CONFIG_SUN3 21504a98f896SFinn Thain if (sun3_dma_setup_done != tmp) { 21514a98f896SFinn Thain int count; 2152e9db3198SFinn Thain 2153ff1269cbSFinn Thain advance_sg_buffer(ncmd); 2154e9db3198SFinn Thain 21554a98f896SFinn Thain count = sun3scsi_dma_xfer_len(hostdata, tmp); 21564a98f896SFinn Thain 21574a98f896SFinn Thain if (count > 0) { 21582e4b231aSBart Van Assche if (tmp->sc_data_direction == DMA_TO_DEVICE) 21594a98f896SFinn Thain sun3scsi_dma_send_setup(hostdata, 2160ff1269cbSFinn Thain ncmd->ptr, count); 21614a98f896SFinn Thain else 21624a98f896SFinn Thain sun3scsi_dma_recv_setup(hostdata, 2163ff1269cbSFinn Thain ncmd->ptr, count); 2164e9db3198SFinn Thain sun3_dma_setup_done = tmp; 2165e9db3198SFinn Thain } 2166e9db3198SFinn Thain } 2167e9db3198SFinn Thain 2168e9db3198SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); 2169e9db3198SFinn Thain #endif /* CONFIG_SUN3 */ 2170e9db3198SFinn Thain 217172064a78SFinn Thain /* Accept message by clearing ACK */ 217272064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 217372064a78SFinn Thain 21741da177e4SLinus Torvalds hostdata->connected = tmp; 2175c4ec6f92SFinn Thain dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu\n", 2176c4ec6f92SFinn Thain scmd_id(tmp), tmp->device->lun); 21771da177e4SLinus Torvalds } 21781da177e4SLinus Torvalds 21798b00c3d5SFinn Thain /** 21808b00c3d5SFinn Thain * list_find_cmd - test for presence of a command in a linked list 21818b00c3d5SFinn Thain * @haystack: list of commands 21828b00c3d5SFinn Thain * @needle: command to search for 21838b00c3d5SFinn Thain */ 21848b00c3d5SFinn Thain 21858b00c3d5SFinn Thain static bool list_find_cmd(struct list_head *haystack, 21868b00c3d5SFinn Thain struct scsi_cmnd *needle) 21878b00c3d5SFinn Thain { 21888b00c3d5SFinn Thain struct NCR5380_cmd *ncmd; 21898b00c3d5SFinn Thain 21908b00c3d5SFinn Thain list_for_each_entry(ncmd, haystack, list) 21918b00c3d5SFinn Thain if (NCR5380_to_scmd(ncmd) == needle) 21928b00c3d5SFinn Thain return true; 21938b00c3d5SFinn Thain return false; 21948b00c3d5SFinn Thain } 21958b00c3d5SFinn Thain 21968b00c3d5SFinn Thain /** 21978b00c3d5SFinn Thain * list_remove_cmd - remove a command from linked list 21988b00c3d5SFinn Thain * @haystack: list of commands 21998b00c3d5SFinn Thain * @needle: command to remove 22008b00c3d5SFinn Thain */ 22018b00c3d5SFinn Thain 22028b00c3d5SFinn Thain static bool list_del_cmd(struct list_head *haystack, 22038b00c3d5SFinn Thain struct scsi_cmnd *needle) 22048b00c3d5SFinn Thain { 22058b00c3d5SFinn Thain if (list_find_cmd(haystack, needle)) { 2206ff1269cbSFinn Thain struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(needle); 22078b00c3d5SFinn Thain 22088b00c3d5SFinn Thain list_del(&ncmd->list); 22098b00c3d5SFinn Thain return true; 22108b00c3d5SFinn Thain } 22118b00c3d5SFinn Thain return false; 22128b00c3d5SFinn Thain } 22138b00c3d5SFinn Thain 22148b00c3d5SFinn Thain /** 22158b00c3d5SFinn Thain * NCR5380_abort - scsi host eh_abort_handler() method 22168b00c3d5SFinn Thain * @cmd: the command to be aborted 22171da177e4SLinus Torvalds * 22188b00c3d5SFinn Thain * Try to abort a given command by removing it from queues and/or sending 22198b00c3d5SFinn Thain * the target an abort message. This may not succeed in causing a target 22208b00c3d5SFinn Thain * to abort the command. Nonetheless, the low-level driver must forget about 22218b00c3d5SFinn Thain * the command because the mid-layer reclaims it and it may be re-issued. 22221da177e4SLinus Torvalds * 22238b00c3d5SFinn Thain * The normal path taken by a command is as follows. For EH we trace this 22248b00c3d5SFinn Thain * same path to locate and abort the command. 22251da177e4SLinus Torvalds * 22268b00c3d5SFinn Thain * unissued -> selecting -> [unissued -> selecting ->]... connected -> 22278b00c3d5SFinn Thain * [disconnected -> connected ->]... 22288b00c3d5SFinn Thain * [autosense -> connected ->] done 22291da177e4SLinus Torvalds * 22308b00c3d5SFinn Thain * If cmd was not found at all then presumably it has already been completed, 22318b00c3d5SFinn Thain * in which case return SUCCESS to try to avoid further EH measures. 2232dc183965SFinn Thain * 22338b00c3d5SFinn Thain * If the command has not completed yet, we must not fail to find it. 2234dc183965SFinn Thain * We have no option but to forget the aborted command (even if it still 2235dc183965SFinn Thain * lacks sense data). The mid-layer may re-issue a command that is in error 2236dc183965SFinn Thain * recovery (see scsi_send_eh_cmnd), but the logic and data structures in 2237dc183965SFinn Thain * this driver are such that a command can appear on one queue only. 223871a00593SFinn Thain * 223971a00593SFinn Thain * The lock protects driver data structures, but EH handlers also use it 224071a00593SFinn Thain * to serialize their own execution and prevent their own re-entry. 22411da177e4SLinus Torvalds */ 22421da177e4SLinus Torvalds 2243710ddd0dSFinn Thain static int NCR5380_abort(struct scsi_cmnd *cmd) 2244710ddd0dSFinn Thain { 22451da177e4SLinus Torvalds struct Scsi_Host *instance = cmd->device->host; 2246e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 224711d2f63bSFinn Thain unsigned long flags; 22488b00c3d5SFinn Thain int result = SUCCESS; 22491da177e4SLinus Torvalds 225011d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 225111d2f63bSFinn Thain 225232b26a10SFinn Thain #if (NDEBUG & NDEBUG_ANY) 22538b00c3d5SFinn Thain scmd_printk(KERN_INFO, cmd, __func__); 225432b26a10SFinn Thain #endif 2255e5c3fddfSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 2256e5c3fddfSFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 22571da177e4SLinus Torvalds 22588b00c3d5SFinn Thain if (list_del_cmd(&hostdata->unissued, cmd)) { 22598b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 22608b00c3d5SFinn Thain "abort: removed %p from issue queue\n", cmd); 22618b00c3d5SFinn Thain cmd->result = DID_ABORT << 16; 2262117cd238SBart Van Assche scsi_done(cmd); /* No tag or busy flag to worry about */ 2263dc183965SFinn Thain goto out; 22648b00c3d5SFinn Thain } 22658b00c3d5SFinn Thain 2266707d62b3SFinn Thain if (hostdata->selecting == cmd) { 2267707d62b3SFinn Thain dsprintk(NDEBUG_ABORT, instance, 2268707d62b3SFinn Thain "abort: cmd %p == selecting\n", cmd); 2269707d62b3SFinn Thain hostdata->selecting = NULL; 2270707d62b3SFinn Thain cmd->result = DID_ABORT << 16; 2271707d62b3SFinn Thain complete_cmd(instance, cmd); 2272707d62b3SFinn Thain goto out; 2273707d62b3SFinn Thain } 2274707d62b3SFinn Thain 22758b00c3d5SFinn Thain if (list_del_cmd(&hostdata->disconnected, cmd)) { 22768b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 22778b00c3d5SFinn Thain "abort: removed %p from disconnected list\n", cmd); 227871a00593SFinn Thain /* Can't call NCR5380_select() and send ABORT because that 227971a00593SFinn Thain * means releasing the lock. Need a bus reset. 228071a00593SFinn Thain */ 2281dc183965SFinn Thain set_host_byte(cmd, DID_ERROR); 2282dc183965SFinn Thain complete_cmd(instance, cmd); 22838b00c3d5SFinn Thain result = FAILED; 22848b00c3d5SFinn Thain goto out; 22858b00c3d5SFinn Thain } 22868b00c3d5SFinn Thain 22878b00c3d5SFinn Thain if (hostdata->connected == cmd) { 22888b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); 22898b00c3d5SFinn Thain hostdata->connected = NULL; 2290dc183965SFinn Thain hostdata->dma_len = 0; 2291e7734ef1SAhmed S. Darwish if (do_abort(instance, 0) < 0) { 22928b00c3d5SFinn Thain set_host_byte(cmd, DID_ERROR); 22938b00c3d5SFinn Thain complete_cmd(instance, cmd); 22948b00c3d5SFinn Thain result = FAILED; 22958b00c3d5SFinn Thain goto out; 22968b00c3d5SFinn Thain } 22978b00c3d5SFinn Thain set_host_byte(cmd, DID_ABORT); 22988b00c3d5SFinn Thain complete_cmd(instance, cmd); 2299dc183965SFinn Thain goto out; 23008b00c3d5SFinn Thain } 23018b00c3d5SFinn Thain 23028b00c3d5SFinn Thain if (list_del_cmd(&hostdata->autosense, cmd)) { 23038b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 23048b00c3d5SFinn Thain "abort: removed %p from sense queue\n", cmd); 23058b00c3d5SFinn Thain complete_cmd(instance, cmd); 23068b00c3d5SFinn Thain } 23078b00c3d5SFinn Thain 23088b00c3d5SFinn Thain out: 23098b00c3d5SFinn Thain if (result == FAILED) 23108b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd); 231145ddc1b2SFinn Thain else { 231245ddc1b2SFinn Thain hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); 23138b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd); 231445ddc1b2SFinn Thain } 23158b00c3d5SFinn Thain 23168b00c3d5SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 231711d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 23181da177e4SLinus Torvalds 23198b00c3d5SFinn Thain return result; 23201da177e4SLinus Torvalds } 23211da177e4SLinus Torvalds 23221da177e4SLinus Torvalds 23236b0e87a6SFinn Thain static void bus_reset_cleanup(struct Scsi_Host *instance) 232468b3aa7cSJeff Garzik { 232511d2f63bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 232662717f53SFinn Thain int i; 232762717f53SFinn Thain struct NCR5380_cmd *ncmd; 23281da177e4SLinus Torvalds 232962717f53SFinn Thain /* reset NCR registers */ 233062717f53SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 233162717f53SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 0); 233262717f53SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 233362717f53SFinn Thain 233462717f53SFinn Thain /* After the reset, there are no more connected or disconnected commands 233562717f53SFinn Thain * and no busy units; so clear the low-level status here to avoid 233662717f53SFinn Thain * conflicts when the mid-level code tries to wake up the affected 233762717f53SFinn Thain * commands! 233862717f53SFinn Thain */ 233962717f53SFinn Thain 23401884c283SFinn Thain if (hostdata->selecting) { 23411884c283SFinn Thain hostdata->selecting->result = DID_RESET << 16; 23421884c283SFinn Thain complete_cmd(instance, hostdata->selecting); 234362717f53SFinn Thain hostdata->selecting = NULL; 23441884c283SFinn Thain } 234562717f53SFinn Thain 234662717f53SFinn Thain list_for_each_entry(ncmd, &hostdata->disconnected, list) { 234762717f53SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 234862717f53SFinn Thain 234962717f53SFinn Thain set_host_byte(cmd, DID_RESET); 2350216fad91SFinn Thain complete_cmd(instance, cmd); 235162717f53SFinn Thain } 23521884c283SFinn Thain INIT_LIST_HEAD(&hostdata->disconnected); 235362717f53SFinn Thain 235462717f53SFinn Thain list_for_each_entry(ncmd, &hostdata->autosense, list) { 235562717f53SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 235662717f53SFinn Thain 2357117cd238SBart Van Assche scsi_done(cmd); 235862717f53SFinn Thain } 23591884c283SFinn Thain INIT_LIST_HEAD(&hostdata->autosense); 236062717f53SFinn Thain 236162717f53SFinn Thain if (hostdata->connected) { 236262717f53SFinn Thain set_host_byte(hostdata->connected, DID_RESET); 236362717f53SFinn Thain complete_cmd(instance, hostdata->connected); 236462717f53SFinn Thain hostdata->connected = NULL; 236562717f53SFinn Thain } 236662717f53SFinn Thain 236762717f53SFinn Thain for (i = 0; i < 8; ++i) 236862717f53SFinn Thain hostdata->busy[i] = 0; 236962717f53SFinn Thain hostdata->dma_len = 0; 237062717f53SFinn Thain 237162717f53SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 23726b0e87a6SFinn Thain } 23736b0e87a6SFinn Thain 23746b0e87a6SFinn Thain /** 23756b0e87a6SFinn Thain * NCR5380_host_reset - reset the SCSI host 23766b0e87a6SFinn Thain * @cmd: SCSI command undergoing EH 23776b0e87a6SFinn Thain * 23786b0e87a6SFinn Thain * Returns SUCCESS 23796b0e87a6SFinn Thain */ 23806b0e87a6SFinn Thain 23816b0e87a6SFinn Thain static int NCR5380_host_reset(struct scsi_cmnd *cmd) 23826b0e87a6SFinn Thain { 23836b0e87a6SFinn Thain struct Scsi_Host *instance = cmd->device->host; 23846b0e87a6SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 23856b0e87a6SFinn Thain unsigned long flags; 23866b0e87a6SFinn Thain struct NCR5380_cmd *ncmd; 23876b0e87a6SFinn Thain 23886b0e87a6SFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 23896b0e87a6SFinn Thain 23906b0e87a6SFinn Thain #if (NDEBUG & NDEBUG_ANY) 23916b0e87a6SFinn Thain shost_printk(KERN_INFO, instance, __func__); 23926b0e87a6SFinn Thain #endif 23936b0e87a6SFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 23946b0e87a6SFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 23956b0e87a6SFinn Thain 23966b0e87a6SFinn Thain list_for_each_entry(ncmd, &hostdata->unissued, list) { 23976b0e87a6SFinn Thain struct scsi_cmnd *scmd = NCR5380_to_scmd(ncmd); 23986b0e87a6SFinn Thain 23996b0e87a6SFinn Thain scmd->result = DID_RESET << 16; 2400117cd238SBart Van Assche scsi_done(scmd); 24016b0e87a6SFinn Thain } 24026b0e87a6SFinn Thain INIT_LIST_HEAD(&hostdata->unissued); 24036b0e87a6SFinn Thain 24046b0e87a6SFinn Thain do_reset(instance); 24056b0e87a6SFinn Thain bus_reset_cleanup(instance); 24066b0e87a6SFinn Thain 240711d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 240868b3aa7cSJeff Garzik 24091da177e4SLinus Torvalds return SUCCESS; 24101da177e4SLinus Torvalds } 2411