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 * 871da177e4SLinus Torvalds * SCSI pointers are maintained in the SCp field of SCSI command 881da177e4SLinus Torvalds * structures, being initialized after the command is connected 891da177e4SLinus Torvalds * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. 901da177e4SLinus Torvalds * Note that in violation of the standard, an implicit SAVE POINTERS operation 911da177e4SLinus Torvalds * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS. 921da177e4SLinus Torvalds */ 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds /* 951da177e4SLinus Torvalds * Using this file : 961da177e4SLinus Torvalds * This file a skeleton Linux SCSI driver for the NCR 5380 series 971da177e4SLinus Torvalds * of chips. To use it, you write an architecture specific functions 981da177e4SLinus Torvalds * and macros and include this file in your driver. 991da177e4SLinus Torvalds * 1001da177e4SLinus Torvalds * These macros MUST be defined : 1011da177e4SLinus Torvalds * 1021da177e4SLinus Torvalds * NCR5380_read(register) - read from the specified register 1031da177e4SLinus Torvalds * 1041da177e4SLinus Torvalds * NCR5380_write(register, value) - write to the specific register 1051da177e4SLinus Torvalds * 1061da177e4SLinus Torvalds * NCR5380_implementation_fields - additional fields needed for this 1071da177e4SLinus Torvalds * specific implementation of the NCR5380 1081da177e4SLinus Torvalds * 1091da177e4SLinus Torvalds * Either real DMA *or* pseudo DMA may be implemented 1101da177e4SLinus Torvalds * 1114a98f896SFinn Thain * NCR5380_dma_xfer_len - determine size of DMA/PDMA transfer 1124a98f896SFinn Thain * NCR5380_dma_send_setup - execute DMA/PDMA from memory to 5380 1134a98f896SFinn Thain * NCR5380_dma_recv_setup - execute DMA/PDMA from 5380 to memory 1144a98f896SFinn Thain * NCR5380_dma_residual - residual byte count 1151da177e4SLinus Torvalds * 1161da177e4SLinus Torvalds * The generic driver is initialized by calling NCR5380_init(instance), 117906e4a3cSOndrej Zary * after setting the appropriate host specific fields and ID. 1181da177e4SLinus Torvalds */ 1191da177e4SLinus Torvalds 120e5d55d1aSFinn Thain #ifndef NCR5380_io_delay 121e5d55d1aSFinn Thain #define NCR5380_io_delay(x) 122e5d55d1aSFinn Thain #endif 123e5d55d1aSFinn Thain 12452d3e561SFinn Thain #ifndef NCR5380_acquire_dma_irq 12552d3e561SFinn Thain #define NCR5380_acquire_dma_irq(x) (1) 12652d3e561SFinn Thain #endif 12752d3e561SFinn Thain 12852d3e561SFinn Thain #ifndef NCR5380_release_dma_irq 12952d3e561SFinn Thain #define NCR5380_release_dma_irq(x) 13052d3e561SFinn Thain #endif 13152d3e561SFinn Thain 13254d8fe44SFinn Thain static int do_abort(struct Scsi_Host *); 13354d8fe44SFinn Thain static void do_reset(struct Scsi_Host *); 1341da177e4SLinus Torvalds 135c16df32eSFinn Thain /** 1361da177e4SLinus Torvalds * initialize_SCp - init the scsi pointer field 1371da177e4SLinus Torvalds * @cmd: command block to set up 1381da177e4SLinus Torvalds * 1391da177e4SLinus Torvalds * Set up the internal fields in the SCSI command. 1401da177e4SLinus Torvalds */ 1411da177e4SLinus Torvalds 142710ddd0dSFinn Thain static inline void initialize_SCp(struct scsi_cmnd *cmd) 1431da177e4SLinus Torvalds { 1441da177e4SLinus Torvalds /* 1451da177e4SLinus Torvalds * Initialize the Scsi Pointer field so that all of the commands in the 1461da177e4SLinus Torvalds * various queues are valid. 1471da177e4SLinus Torvalds */ 1481da177e4SLinus Torvalds 1499e0fe44dSBoaz Harrosh if (scsi_bufflen(cmd)) { 1509e0fe44dSBoaz Harrosh cmd->SCp.buffer = scsi_sglist(cmd); 1519e0fe44dSBoaz Harrosh cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; 15245711f1aSJens Axboe cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 1531da177e4SLinus Torvalds cmd->SCp.this_residual = cmd->SCp.buffer->length; 1541da177e4SLinus Torvalds } else { 1551da177e4SLinus Torvalds cmd->SCp.buffer = NULL; 1561da177e4SLinus Torvalds cmd->SCp.buffers_residual = 0; 1579e0fe44dSBoaz Harrosh cmd->SCp.ptr = NULL; 1589e0fe44dSBoaz Harrosh cmd->SCp.this_residual = 0; 1591da177e4SLinus Torvalds } 160f27db8ebSFinn Thain 161f27db8ebSFinn Thain cmd->SCp.Status = 0; 162f27db8ebSFinn Thain cmd->SCp.Message = 0; 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds /** 166b32ade12SFinn Thain * NCR5380_poll_politely2 - wait for two chip register values 167d5d37a0aSFinn Thain * @hostdata: host private data 168b32ade12SFinn Thain * @reg1: 5380 register to poll 169b32ade12SFinn Thain * @bit1: Bitmask to check 170b32ade12SFinn Thain * @val1: Expected value 171b32ade12SFinn Thain * @reg2: Second 5380 register to poll 172b32ade12SFinn Thain * @bit2: Second bitmask to check 173b32ade12SFinn Thain * @val2: Second expected value 1742f854b82SFinn Thain * @wait: Time-out in jiffies 1751da177e4SLinus Torvalds * 1762f854b82SFinn Thain * Polls the chip in a reasonably efficient manner waiting for an 1772f854b82SFinn Thain * event to occur. After a short quick poll we begin to yield the CPU 1782f854b82SFinn Thain * (if possible). In irq contexts the time-out is arbitrarily limited. 1792f854b82SFinn Thain * Callers may hold locks as long as they are held in irq mode. 1801da177e4SLinus Torvalds * 181b32ade12SFinn Thain * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT. 1821da177e4SLinus Torvalds */ 1831da177e4SLinus Torvalds 184d5d37a0aSFinn Thain static int NCR5380_poll_politely2(struct NCR5380_hostdata *hostdata, 18561e1ce58SFinn Thain unsigned int reg1, u8 bit1, u8 val1, 18661e1ce58SFinn Thain unsigned int reg2, u8 bit2, u8 val2, 18761e1ce58SFinn Thain unsigned long wait) 1881da177e4SLinus Torvalds { 189d4408dd7SFinn Thain unsigned long n = hostdata->poll_loops; 1902f854b82SFinn Thain unsigned long deadline = jiffies + wait; 1911da177e4SLinus Torvalds 1922f854b82SFinn Thain do { 193b32ade12SFinn Thain if ((NCR5380_read(reg1) & bit1) == val1) 194b32ade12SFinn Thain return 0; 195b32ade12SFinn Thain if ((NCR5380_read(reg2) & bit2) == val2) 1961da177e4SLinus Torvalds return 0; 1971da177e4SLinus Torvalds cpu_relax(); 1982f854b82SFinn Thain } while (n--); 1992f854b82SFinn Thain 2002f854b82SFinn Thain if (irqs_disabled() || in_interrupt()) 2012f854b82SFinn Thain return -ETIMEDOUT; 2022f854b82SFinn Thain 2032f854b82SFinn Thain /* Repeatedly sleep for 1 ms until deadline */ 2042f854b82SFinn Thain while (time_is_after_jiffies(deadline)) { 2052f854b82SFinn Thain schedule_timeout_uninterruptible(1); 206b32ade12SFinn Thain if ((NCR5380_read(reg1) & bit1) == val1) 207b32ade12SFinn Thain return 0; 208b32ade12SFinn Thain if ((NCR5380_read(reg2) & bit2) == val2) 2092f854b82SFinn Thain return 0; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds return -ETIMEDOUT; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 215185a7a1cSviro@ZenIV.linux.org.uk #if NDEBUG 2161da177e4SLinus Torvalds static struct { 2171da177e4SLinus Torvalds unsigned char mask; 2181da177e4SLinus Torvalds const char *name; 2191da177e4SLinus Torvalds } signals[] = { 2201da177e4SLinus Torvalds {SR_DBP, "PARITY"}, 2211da177e4SLinus Torvalds {SR_RST, "RST"}, 2221da177e4SLinus Torvalds {SR_BSY, "BSY"}, 2231da177e4SLinus Torvalds {SR_REQ, "REQ"}, 2241da177e4SLinus Torvalds {SR_MSG, "MSG"}, 2251da177e4SLinus Torvalds {SR_CD, "CD"}, 2261da177e4SLinus Torvalds {SR_IO, "IO"}, 2271da177e4SLinus Torvalds {SR_SEL, "SEL"}, 2281da177e4SLinus Torvalds {0, NULL} 2291da177e4SLinus Torvalds }, 2301da177e4SLinus Torvalds basrs[] = { 23112866b99SFinn Thain {BASR_END_DMA_TRANSFER, "END OF DMA"}, 23212866b99SFinn Thain {BASR_DRQ, "DRQ"}, 23312866b99SFinn Thain {BASR_PARITY_ERROR, "PARITY ERROR"}, 23412866b99SFinn Thain {BASR_IRQ, "IRQ"}, 23512866b99SFinn Thain {BASR_PHASE_MATCH, "PHASE MATCH"}, 23612866b99SFinn Thain {BASR_BUSY_ERROR, "BUSY ERROR"}, 2371da177e4SLinus Torvalds {BASR_ATN, "ATN"}, 2381da177e4SLinus Torvalds {BASR_ACK, "ACK"}, 2391da177e4SLinus Torvalds {0, NULL} 2401da177e4SLinus Torvalds }, 2411da177e4SLinus Torvalds icrs[] = { 2421da177e4SLinus Torvalds {ICR_ASSERT_RST, "ASSERT RST"}, 24312866b99SFinn Thain {ICR_ARBITRATION_PROGRESS, "ARB. IN PROGRESS"}, 24412866b99SFinn Thain {ICR_ARBITRATION_LOST, "LOST ARB."}, 2451da177e4SLinus Torvalds {ICR_ASSERT_ACK, "ASSERT ACK"}, 2461da177e4SLinus Torvalds {ICR_ASSERT_BSY, "ASSERT BSY"}, 2471da177e4SLinus Torvalds {ICR_ASSERT_SEL, "ASSERT SEL"}, 2481da177e4SLinus Torvalds {ICR_ASSERT_ATN, "ASSERT ATN"}, 2491da177e4SLinus Torvalds {ICR_ASSERT_DATA, "ASSERT DATA"}, 2501da177e4SLinus Torvalds {0, NULL} 2511da177e4SLinus Torvalds }, 2521da177e4SLinus Torvalds mrs[] = { 25312866b99SFinn Thain {MR_BLOCK_DMA_MODE, "BLOCK DMA MODE"}, 25412866b99SFinn Thain {MR_TARGET, "TARGET"}, 25512866b99SFinn Thain {MR_ENABLE_PAR_CHECK, "PARITY CHECK"}, 25612866b99SFinn Thain {MR_ENABLE_PAR_INTR, "PARITY INTR"}, 25712866b99SFinn Thain {MR_ENABLE_EOP_INTR, "EOP INTR"}, 25812866b99SFinn Thain {MR_MONITOR_BSY, "MONITOR BSY"}, 25912866b99SFinn Thain {MR_DMA_MODE, "DMA MODE"}, 26012866b99SFinn Thain {MR_ARBITRATE, "ARBITRATE"}, 2611da177e4SLinus Torvalds {0, NULL} 2621da177e4SLinus Torvalds }; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds /** 2651da177e4SLinus Torvalds * NCR5380_print - print scsi bus signals 2661da177e4SLinus Torvalds * @instance: adapter state to dump 2671da177e4SLinus Torvalds * 2681da177e4SLinus Torvalds * Print the SCSI bus signals for debugging purposes 2691da177e4SLinus Torvalds */ 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds static void NCR5380_print(struct Scsi_Host *instance) 2721da177e4SLinus Torvalds { 27361e1ce58SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 2741da177e4SLinus Torvalds unsigned char status, data, basr, mr, icr, i; 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds data = NCR5380_read(CURRENT_SCSI_DATA_REG); 2771da177e4SLinus Torvalds status = NCR5380_read(STATUS_REG); 2781da177e4SLinus Torvalds mr = NCR5380_read(MODE_REG); 2791da177e4SLinus Torvalds icr = NCR5380_read(INITIATOR_COMMAND_REG); 2801da177e4SLinus Torvalds basr = NCR5380_read(BUS_AND_STATUS_REG); 2811da177e4SLinus Torvalds 28212866b99SFinn Thain printk(KERN_DEBUG "SR = 0x%02x : ", status); 2831da177e4SLinus Torvalds for (i = 0; signals[i].mask; ++i) 2841da177e4SLinus Torvalds if (status & signals[i].mask) 28512866b99SFinn Thain printk(KERN_CONT "%s, ", signals[i].name); 28612866b99SFinn Thain printk(KERN_CONT "\nBASR = 0x%02x : ", basr); 2871da177e4SLinus Torvalds for (i = 0; basrs[i].mask; ++i) 2881da177e4SLinus Torvalds if (basr & basrs[i].mask) 28912866b99SFinn Thain printk(KERN_CONT "%s, ", basrs[i].name); 29012866b99SFinn Thain printk(KERN_CONT "\nICR = 0x%02x : ", icr); 2911da177e4SLinus Torvalds for (i = 0; icrs[i].mask; ++i) 2921da177e4SLinus Torvalds if (icr & icrs[i].mask) 29312866b99SFinn Thain printk(KERN_CONT "%s, ", icrs[i].name); 29412866b99SFinn Thain printk(KERN_CONT "\nMR = 0x%02x : ", mr); 2951da177e4SLinus Torvalds for (i = 0; mrs[i].mask; ++i) 2961da177e4SLinus Torvalds if (mr & mrs[i].mask) 29712866b99SFinn Thain printk(KERN_CONT "%s, ", mrs[i].name); 29812866b99SFinn Thain printk(KERN_CONT "\n"); 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds 3010d2cf867SFinn Thain static struct { 3020d2cf867SFinn Thain unsigned char value; 3030d2cf867SFinn Thain const char *name; 3040d2cf867SFinn Thain } phases[] = { 3050d2cf867SFinn Thain {PHASE_DATAOUT, "DATAOUT"}, 3060d2cf867SFinn Thain {PHASE_DATAIN, "DATAIN"}, 3070d2cf867SFinn Thain {PHASE_CMDOUT, "CMDOUT"}, 3080d2cf867SFinn Thain {PHASE_STATIN, "STATIN"}, 3090d2cf867SFinn Thain {PHASE_MSGOUT, "MSGOUT"}, 3100d2cf867SFinn Thain {PHASE_MSGIN, "MSGIN"}, 3110d2cf867SFinn Thain {PHASE_UNKNOWN, "UNKNOWN"} 3120d2cf867SFinn Thain }; 3131da177e4SLinus Torvalds 314c16df32eSFinn Thain /** 3151da177e4SLinus Torvalds * NCR5380_print_phase - show SCSI phase 3161da177e4SLinus Torvalds * @instance: adapter to dump 3171da177e4SLinus Torvalds * 3181da177e4SLinus Torvalds * Print the current SCSI phase for debugging purposes 3191da177e4SLinus Torvalds */ 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds static void NCR5380_print_phase(struct Scsi_Host *instance) 3221da177e4SLinus Torvalds { 32361e1ce58SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 3241da177e4SLinus Torvalds unsigned char status; 3251da177e4SLinus Torvalds int i; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds status = NCR5380_read(STATUS_REG); 3281da177e4SLinus Torvalds if (!(status & SR_REQ)) 3296a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n"); 3301da177e4SLinus Torvalds else { 3310d2cf867SFinn Thain for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 3320d2cf867SFinn Thain (phases[i].value != (status & PHASE_MASK)); ++i) 3330d2cf867SFinn Thain ; 3346a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name); 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds #endif 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds /** 34009028461SFinn Thain * NCR5380_info - report driver and host information 3418c32513bSFinn Thain * @instance: relevant scsi host instance 3421da177e4SLinus Torvalds * 3438c32513bSFinn Thain * For use as the host template info() handler. 3441da177e4SLinus Torvalds */ 3451da177e4SLinus Torvalds 3468c32513bSFinn Thain static const char *NCR5380_info(struct Scsi_Host *instance) 3471da177e4SLinus Torvalds { 3488c32513bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 3498c32513bSFinn Thain 3508c32513bSFinn Thain return hostdata->info; 3518c32513bSFinn Thain } 3528c32513bSFinn Thain 3531da177e4SLinus Torvalds /** 3541da177e4SLinus Torvalds * NCR5380_init - initialise an NCR5380 3551da177e4SLinus Torvalds * @instance: adapter to configure 3561da177e4SLinus Torvalds * @flags: control flags 3571da177e4SLinus Torvalds * 3581da177e4SLinus Torvalds * Initializes *instance and corresponding 5380 chip, 3591da177e4SLinus Torvalds * with flags OR'd into the initial flags value. 3601da177e4SLinus Torvalds * 3611da177e4SLinus Torvalds * Notes : I assume that the host, hostno, and id bits have been 3621da177e4SLinus Torvalds * set correctly. I don't care about the irq and other fields. 3631da177e4SLinus Torvalds * 3641da177e4SLinus Torvalds * Returns 0 for success 3651da177e4SLinus Torvalds */ 3661da177e4SLinus Torvalds 3676f039790SGreg Kroah-Hartman static int NCR5380_init(struct Scsi_Host *instance, int flags) 3681da177e4SLinus Torvalds { 369e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 370b6488f97SFinn Thain int i; 3712f854b82SFinn Thain unsigned long deadline; 372d4408dd7SFinn Thain unsigned long accesses_per_ms; 3731da177e4SLinus Torvalds 374ae5e33afSFinn Thain instance->max_lun = 7; 375ae5e33afSFinn Thain 3760d2cf867SFinn Thain hostdata->host = instance; 3771da177e4SLinus Torvalds hostdata->id_mask = 1 << instance->this_id; 3780d2cf867SFinn Thain hostdata->id_higher_mask = 0; 3791da177e4SLinus Torvalds for (i = hostdata->id_mask; i <= 0x80; i <<= 1) 3801da177e4SLinus Torvalds if (i > hostdata->id_mask) 3811da177e4SLinus Torvalds hostdata->id_higher_mask |= i; 3821da177e4SLinus Torvalds for (i = 0; i < 8; ++i) 3831da177e4SLinus Torvalds hostdata->busy[i] = 0; 384e4dec680SFinn Thain hostdata->dma_len = 0; 385e4dec680SFinn Thain 38611d2f63bSFinn Thain spin_lock_init(&hostdata->lock); 3871da177e4SLinus Torvalds hostdata->connected = NULL; 388f27db8ebSFinn Thain hostdata->sensing = NULL; 389f27db8ebSFinn Thain INIT_LIST_HEAD(&hostdata->autosense); 39032b26a10SFinn Thain INIT_LIST_HEAD(&hostdata->unissued); 39132b26a10SFinn Thain INIT_LIST_HEAD(&hostdata->disconnected); 39232b26a10SFinn Thain 39355181be8SFinn Thain hostdata->flags = flags; 3941da177e4SLinus Torvalds 3958d8601a7SFinn Thain INIT_WORK(&hostdata->main_task, NCR5380_main); 3960ad0eff9SFinn Thain hostdata->work_q = alloc_workqueue("ncr5380_%d", 3970ad0eff9SFinn Thain WQ_UNBOUND | WQ_MEM_RECLAIM, 3980ad0eff9SFinn Thain 1, instance->host_no); 3990ad0eff9SFinn Thain if (!hostdata->work_q) 4000ad0eff9SFinn Thain return -ENOMEM; 4011da177e4SLinus Torvalds 40209028461SFinn Thain snprintf(hostdata->info, sizeof(hostdata->info), 40309028461SFinn 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}", 40409028461SFinn Thain instance->hostt->name, instance->irq, hostdata->io_port, 40509028461SFinn Thain hostdata->base, instance->can_queue, instance->cmd_per_lun, 40609028461SFinn Thain instance->sg_tablesize, instance->this_id, 40709028461SFinn Thain hostdata->flags & FLAG_DMA_FIXUP ? "DMA_FIXUP " : "", 40809028461SFinn Thain hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "", 40909028461SFinn Thain hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : ""); 4108c32513bSFinn Thain 4111da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 4121da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 4131da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 4141da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 4152f854b82SFinn Thain 4162f854b82SFinn Thain /* Calibrate register polling loop */ 4172f854b82SFinn Thain i = 0; 4182f854b82SFinn Thain deadline = jiffies + 1; 4192f854b82SFinn Thain do { 4202f854b82SFinn Thain cpu_relax(); 4212f854b82SFinn Thain } while (time_is_after_jiffies(deadline)); 4222f854b82SFinn Thain deadline += msecs_to_jiffies(256); 4232f854b82SFinn Thain do { 4242f854b82SFinn Thain NCR5380_read(STATUS_REG); 4252f854b82SFinn Thain ++i; 4262f854b82SFinn Thain cpu_relax(); 4272f854b82SFinn Thain } while (time_is_after_jiffies(deadline)); 428d4408dd7SFinn Thain accesses_per_ms = i / 256; 429d4408dd7SFinn Thain hostdata->poll_loops = NCR5380_REG_POLL_TIME * accesses_per_ms / 2; 4302f854b82SFinn Thain 431b6488f97SFinn Thain return 0; 432b6488f97SFinn Thain } 4331da177e4SLinus Torvalds 434b6488f97SFinn Thain /** 435b6488f97SFinn Thain * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems. 436b6488f97SFinn Thain * @instance: adapter to check 4371da177e4SLinus Torvalds * 438b6488f97SFinn Thain * If the system crashed, it may have crashed with a connected target and 439b6488f97SFinn Thain * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the 440b6488f97SFinn Thain * currently established nexus, which we know nothing about. Failing that 441b6488f97SFinn Thain * do a bus reset. 4421da177e4SLinus Torvalds * 443b6488f97SFinn Thain * Note that a bus reset will cause the chip to assert IRQ. 444b6488f97SFinn Thain * 445b6488f97SFinn Thain * Returns 0 if successful, otherwise -ENXIO. 4461da177e4SLinus Torvalds */ 4471da177e4SLinus Torvalds 448b6488f97SFinn Thain static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance) 449b6488f97SFinn Thain { 4509c3f0e2bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 451b6488f97SFinn Thain int pass; 452b6488f97SFinn Thain 4531da177e4SLinus Torvalds for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) { 4541da177e4SLinus Torvalds switch (pass) { 4551da177e4SLinus Torvalds case 1: 4561da177e4SLinus Torvalds case 3: 4571da177e4SLinus Torvalds case 5: 458636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n"); 459d5d37a0aSFinn Thain NCR5380_poll_politely(hostdata, 460636b1ec8SFinn Thain STATUS_REG, SR_BSY, 0, 5 * HZ); 4611da177e4SLinus Torvalds break; 4621da177e4SLinus Torvalds case 2: 463636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n"); 4641da177e4SLinus Torvalds do_abort(instance); 4651da177e4SLinus Torvalds break; 4661da177e4SLinus Torvalds case 4: 467636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n"); 4681da177e4SLinus Torvalds do_reset(instance); 4699c3f0e2bSFinn Thain /* Wait after a reset; the SCSI standard calls for 4709c3f0e2bSFinn Thain * 250ms, we wait 500ms to be on the safe side. 4719c3f0e2bSFinn Thain * But some Toshiba CD-ROMs need ten times that. 4729c3f0e2bSFinn Thain */ 4739c3f0e2bSFinn Thain if (hostdata->flags & FLAG_TOSHIBA_DELAY) 4749c3f0e2bSFinn Thain msleep(2500); 4759c3f0e2bSFinn Thain else 4769c3f0e2bSFinn Thain msleep(500); 4771da177e4SLinus Torvalds break; 4781da177e4SLinus Torvalds case 6: 479636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus locked solid\n"); 4801da177e4SLinus Torvalds return -ENXIO; 4811da177e4SLinus Torvalds } 4821da177e4SLinus Torvalds } 4831da177e4SLinus Torvalds return 0; 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds /** 4871da177e4SLinus Torvalds * NCR5380_exit - remove an NCR5380 4881da177e4SLinus Torvalds * @instance: adapter to remove 4890d2cf867SFinn Thain * 4900d2cf867SFinn Thain * Assumes that no more work can be queued (e.g. by NCR5380_intr). 4911da177e4SLinus Torvalds */ 4921da177e4SLinus Torvalds 493a43cf0f3SRandy Dunlap static void NCR5380_exit(struct Scsi_Host *instance) 4941da177e4SLinus Torvalds { 495e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 4961da177e4SLinus Torvalds 4978d8601a7SFinn Thain cancel_work_sync(&hostdata->main_task); 4980ad0eff9SFinn Thain destroy_workqueue(hostdata->work_q); 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds 5011da177e4SLinus Torvalds /** 502677e0194SFinn Thain * complete_cmd - finish processing a command and return it to the SCSI ML 503677e0194SFinn Thain * @instance: the host instance 504677e0194SFinn Thain * @cmd: command to complete 505677e0194SFinn Thain */ 506677e0194SFinn Thain 507677e0194SFinn Thain static void complete_cmd(struct Scsi_Host *instance, 508677e0194SFinn Thain struct scsi_cmnd *cmd) 509677e0194SFinn Thain { 510677e0194SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 511677e0194SFinn Thain 512677e0194SFinn Thain dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd); 513677e0194SFinn Thain 514f27db8ebSFinn Thain if (hostdata->sensing == cmd) { 515f27db8ebSFinn Thain /* Autosense processing ends here */ 516f27db8ebSFinn Thain if ((cmd->result & 0xff) != SAM_STAT_GOOD) { 517f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 518f27db8ebSFinn Thain set_host_byte(cmd, DID_ERROR); 519f27db8ebSFinn Thain } else 520f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 521f27db8ebSFinn Thain hostdata->sensing = NULL; 522f27db8ebSFinn Thain } 523f27db8ebSFinn Thain 524677e0194SFinn Thain hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); 525677e0194SFinn Thain 526677e0194SFinn Thain cmd->scsi_done(cmd); 527677e0194SFinn Thain } 528677e0194SFinn Thain 529677e0194SFinn Thain /** 5301da177e4SLinus Torvalds * NCR5380_queue_command - queue a command 5311bb40589SFinn Thain * @instance: the relevant SCSI adapter 5321da177e4SLinus Torvalds * @cmd: SCSI command 5331da177e4SLinus Torvalds * 5341bb40589SFinn Thain * cmd is added to the per-instance issue queue, with minor 5351da177e4SLinus Torvalds * twiddling done to the host specific fields of cmd. If the 5361da177e4SLinus Torvalds * main coroutine is not running, it is restarted. 5371da177e4SLinus Torvalds */ 5381da177e4SLinus Torvalds 5391bb40589SFinn Thain static int NCR5380_queue_command(struct Scsi_Host *instance, 5401bb40589SFinn Thain struct scsi_cmnd *cmd) 5411da177e4SLinus Torvalds { 5421bb40589SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 54332b26a10SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 5441bb40589SFinn Thain unsigned long flags; 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_WRITE) 5471da177e4SLinus Torvalds switch (cmd->cmnd[0]) { 5481da177e4SLinus Torvalds case WRITE_6: 5491da177e4SLinus Torvalds case WRITE_10: 550dbb6b350SFinn Thain shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n"); 5511da177e4SLinus Torvalds cmd->result = (DID_ERROR << 16); 5521bb40589SFinn Thain cmd->scsi_done(cmd); 5531da177e4SLinus Torvalds return 0; 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds cmd->result = 0; 5581da177e4SLinus Torvalds 55952d3e561SFinn Thain if (!NCR5380_acquire_dma_irq(instance)) 56052d3e561SFinn Thain return SCSI_MLQUEUE_HOST_BUSY; 56152d3e561SFinn Thain 56211d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 5631bb40589SFinn Thain 5641da177e4SLinus Torvalds /* 5651da177e4SLinus Torvalds * Insert the cmd into the issue queue. Note that REQUEST SENSE 5661da177e4SLinus Torvalds * commands are added to the head of the queue since any command will 5671da177e4SLinus Torvalds * clear the contingent allegiance condition that exists and the 5681da177e4SLinus Torvalds * sense data is only guaranteed to be valid while the condition exists. 5691da177e4SLinus Torvalds */ 5701da177e4SLinus Torvalds 57132b26a10SFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 57232b26a10SFinn Thain list_add(&ncmd->list, &hostdata->unissued); 57332b26a10SFinn Thain else 57432b26a10SFinn Thain list_add_tail(&ncmd->list, &hostdata->unissued); 57532b26a10SFinn Thain 57611d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 5771bb40589SFinn Thain 578dbb6b350SFinn Thain dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n", 579dbb6b350SFinn Thain cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds /* Kick off command processing */ 5828d8601a7SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 5831da177e4SLinus Torvalds return 0; 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds 58652d3e561SFinn Thain static inline void maybe_release_dma_irq(struct Scsi_Host *instance) 58752d3e561SFinn Thain { 58852d3e561SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 58952d3e561SFinn Thain 59052d3e561SFinn Thain /* Caller does the locking needed to set & test these data atomically */ 59152d3e561SFinn Thain if (list_empty(&hostdata->disconnected) && 59252d3e561SFinn Thain list_empty(&hostdata->unissued) && 59352d3e561SFinn Thain list_empty(&hostdata->autosense) && 59452d3e561SFinn Thain !hostdata->connected && 5954ab2a787SFinn Thain !hostdata->selecting) { 59652d3e561SFinn Thain NCR5380_release_dma_irq(instance); 59752d3e561SFinn Thain } 5984ab2a787SFinn Thain } 59952d3e561SFinn Thain 6001da177e4SLinus Torvalds /** 601f27db8ebSFinn Thain * dequeue_next_cmd - dequeue a command for processing 602f27db8ebSFinn Thain * @instance: the scsi host instance 603f27db8ebSFinn Thain * 604f27db8ebSFinn Thain * Priority is given to commands on the autosense queue. These commands 605f27db8ebSFinn Thain * need autosense because of a CHECK CONDITION result. 606f27db8ebSFinn Thain * 607f27db8ebSFinn Thain * Returns a command pointer if a command is found for a target that is 608f27db8ebSFinn Thain * not already busy. Otherwise returns NULL. 609f27db8ebSFinn Thain */ 610f27db8ebSFinn Thain 611f27db8ebSFinn Thain static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance) 612f27db8ebSFinn Thain { 613f27db8ebSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 614f27db8ebSFinn Thain struct NCR5380_cmd *ncmd; 615f27db8ebSFinn Thain struct scsi_cmnd *cmd; 616f27db8ebSFinn Thain 6178d5dbec3SFinn Thain if (hostdata->sensing || list_empty(&hostdata->autosense)) { 618f27db8ebSFinn Thain list_for_each_entry(ncmd, &hostdata->unissued, list) { 619f27db8ebSFinn Thain cmd = NCR5380_to_scmd(ncmd); 620f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n", 621f27db8ebSFinn Thain cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun); 622f27db8ebSFinn Thain 623f27db8ebSFinn Thain if (!(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))) { 624f27db8ebSFinn Thain list_del(&ncmd->list); 625f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, 626f27db8ebSFinn Thain "dequeue: removed %p from issue queue\n", cmd); 627f27db8ebSFinn Thain return cmd; 628f27db8ebSFinn Thain } 629f27db8ebSFinn Thain } 630f27db8ebSFinn Thain } else { 631f27db8ebSFinn Thain /* Autosense processing begins here */ 632f27db8ebSFinn Thain ncmd = list_first_entry(&hostdata->autosense, 633f27db8ebSFinn Thain struct NCR5380_cmd, list); 634f27db8ebSFinn Thain list_del(&ncmd->list); 635f27db8ebSFinn Thain cmd = NCR5380_to_scmd(ncmd); 636f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, 637f27db8ebSFinn Thain "dequeue: removed %p from autosense queue\n", cmd); 638f27db8ebSFinn Thain scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); 639f27db8ebSFinn Thain hostdata->sensing = cmd; 640f27db8ebSFinn Thain return cmd; 641f27db8ebSFinn Thain } 642f27db8ebSFinn Thain return NULL; 643f27db8ebSFinn Thain } 644f27db8ebSFinn Thain 645f27db8ebSFinn Thain static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd) 646f27db8ebSFinn Thain { 647f27db8ebSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 648f27db8ebSFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 649f27db8ebSFinn Thain 6508d5dbec3SFinn Thain if (hostdata->sensing == cmd) { 651f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 652f27db8ebSFinn Thain list_add(&ncmd->list, &hostdata->autosense); 653f27db8ebSFinn Thain hostdata->sensing = NULL; 654f27db8ebSFinn Thain } else 655f27db8ebSFinn Thain list_add(&ncmd->list, &hostdata->unissued); 656f27db8ebSFinn Thain } 657f27db8ebSFinn Thain 658f27db8ebSFinn Thain /** 6591da177e4SLinus Torvalds * NCR5380_main - NCR state machines 6601da177e4SLinus Torvalds * 6611da177e4SLinus Torvalds * NCR5380_main is a coroutine that runs as long as more work can 6621da177e4SLinus Torvalds * be done on the NCR5380 host adapters in a system. Both 6631da177e4SLinus Torvalds * NCR5380_queue_command() and NCR5380_intr() will try to start it 6641da177e4SLinus Torvalds * in case it is not running. 6651da177e4SLinus Torvalds */ 6661da177e4SLinus Torvalds 667c4028958SDavid Howells static void NCR5380_main(struct work_struct *work) 6681da177e4SLinus Torvalds { 669c4028958SDavid Howells struct NCR5380_hostdata *hostdata = 6708d8601a7SFinn Thain container_of(work, struct NCR5380_hostdata, main_task); 6711da177e4SLinus Torvalds struct Scsi_Host *instance = hostdata->host; 6721da177e4SLinus Torvalds int done; 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds do { 6751da177e4SLinus Torvalds done = 1; 67611d2f63bSFinn Thain 6770a4e3612SFinn Thain spin_lock_irq(&hostdata->lock); 678ccf6efd7SFinn Thain while (!hostdata->connected && !hostdata->selecting) { 679ccf6efd7SFinn Thain struct scsi_cmnd *cmd = dequeue_next_cmd(instance); 680ccf6efd7SFinn Thain 681ccf6efd7SFinn Thain if (!cmd) 682ccf6efd7SFinn Thain break; 68332b26a10SFinn Thain 684f27db8ebSFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd); 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds /* 6871da177e4SLinus Torvalds * Attempt to establish an I_T_L nexus here. 6881da177e4SLinus Torvalds * On success, instance->hostdata->connected is set. 6891da177e4SLinus Torvalds * On failure, we must add the command back to the 6901da177e4SLinus Torvalds * issue queue so we can keep trying. 6911da177e4SLinus Torvalds */ 6921da177e4SLinus Torvalds /* 6931da177e4SLinus Torvalds * REQUEST SENSE commands are issued without tagged 6941da177e4SLinus Torvalds * queueing, even on SCSI-II devices because the 6951da177e4SLinus Torvalds * contingent allegiance condition exists for the 6961da177e4SLinus Torvalds * entire unit. 6971da177e4SLinus Torvalds */ 69876f13b93SFinn Thain 699ccf6efd7SFinn Thain if (!NCR5380_select(instance, cmd)) { 700707d62b3SFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: select complete\n"); 70152d3e561SFinn Thain maybe_release_dma_irq(instance); 7021da177e4SLinus Torvalds } else { 703f27db8ebSFinn Thain dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance, 704f27db8ebSFinn Thain "main: select failed, returning %p to queue\n", cmd); 705f27db8ebSFinn Thain requeue_cmd(instance, cmd); 7061da177e4SLinus Torvalds } 707f27db8ebSFinn Thain } 708e4dec680SFinn Thain if (hostdata->connected && !hostdata->dma_len) { 709b746545fSFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n"); 7101da177e4SLinus Torvalds NCR5380_information_transfer(instance); 7111da177e4SLinus Torvalds done = 0; 7121d3db59dSFinn Thain } 71311d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 7140a4e3612SFinn Thain if (!done) 7150a4e3612SFinn Thain cond_resched(); 7160a4e3612SFinn Thain } while (!done); 7171da177e4SLinus Torvalds } 7181da177e4SLinus Torvalds 7198053b0eeSFinn Thain /* 7208053b0eeSFinn Thain * NCR5380_dma_complete - finish DMA transfer 7218053b0eeSFinn Thain * @instance: the scsi host instance 7228053b0eeSFinn Thain * 7238053b0eeSFinn Thain * Called by the interrupt handler when DMA finishes or a phase 7248053b0eeSFinn Thain * mismatch occurs (which would end the DMA transfer). 7258053b0eeSFinn Thain */ 7268053b0eeSFinn Thain 7278053b0eeSFinn Thain static void NCR5380_dma_complete(struct Scsi_Host *instance) 7288053b0eeSFinn Thain { 7298053b0eeSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 7308053b0eeSFinn Thain int transferred; 7318053b0eeSFinn Thain unsigned char **data; 7328053b0eeSFinn Thain int *count; 7338053b0eeSFinn Thain int saved_data = 0, overrun = 0; 7348053b0eeSFinn Thain unsigned char p; 7358053b0eeSFinn Thain 7368053b0eeSFinn Thain if (hostdata->read_overruns) { 7378053b0eeSFinn Thain p = hostdata->connected->SCp.phase; 7388053b0eeSFinn Thain if (p & SR_IO) { 7398053b0eeSFinn Thain udelay(10); 7408053b0eeSFinn Thain if ((NCR5380_read(BUS_AND_STATUS_REG) & 7418053b0eeSFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) == 7428053b0eeSFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) { 7438053b0eeSFinn Thain saved_data = NCR5380_read(INPUT_DATA_REG); 7448053b0eeSFinn Thain overrun = 1; 7458053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, "read overrun handled\n"); 7468053b0eeSFinn Thain } 7478053b0eeSFinn Thain } 7488053b0eeSFinn Thain } 7498053b0eeSFinn Thain 750e9db3198SFinn Thain #ifdef CONFIG_SUN3 751e9db3198SFinn Thain if ((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) { 752e9db3198SFinn Thain pr_err("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", 753e9db3198SFinn Thain instance->host_no); 754e9db3198SFinn Thain BUG(); 755e9db3198SFinn Thain } 756e9db3198SFinn Thain 757e9db3198SFinn Thain if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == 758e9db3198SFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) { 759e9db3198SFinn Thain pr_err("scsi%d: BASR %02x\n", instance->host_no, 760e9db3198SFinn Thain NCR5380_read(BUS_AND_STATUS_REG)); 761e9db3198SFinn Thain pr_err("scsi%d: bus stuck in data phase -- probably a single byte overrun!\n", 762e9db3198SFinn Thain instance->host_no); 763e9db3198SFinn Thain BUG(); 764e9db3198SFinn Thain } 765e9db3198SFinn Thain #endif 766e9db3198SFinn Thain 7678053b0eeSFinn Thain NCR5380_write(MODE_REG, MR_BASE); 7688053b0eeSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 7698053b0eeSFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 7708053b0eeSFinn Thain 7714a98f896SFinn Thain transferred = hostdata->dma_len - NCR5380_dma_residual(hostdata); 7728053b0eeSFinn Thain hostdata->dma_len = 0; 7738053b0eeSFinn Thain 7748053b0eeSFinn Thain data = (unsigned char **)&hostdata->connected->SCp.ptr; 7758053b0eeSFinn Thain count = &hostdata->connected->SCp.this_residual; 7768053b0eeSFinn Thain *data += transferred; 7778053b0eeSFinn Thain *count -= transferred; 7788053b0eeSFinn Thain 7798053b0eeSFinn Thain if (hostdata->read_overruns) { 7808053b0eeSFinn Thain int cnt, toPIO; 7818053b0eeSFinn Thain 7828053b0eeSFinn Thain if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { 7838053b0eeSFinn Thain cnt = toPIO = hostdata->read_overruns; 7848053b0eeSFinn Thain if (overrun) { 7858053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, 7868053b0eeSFinn Thain "Got an input overrun, using saved byte\n"); 7878053b0eeSFinn Thain *(*data)++ = saved_data; 7888053b0eeSFinn Thain (*count)--; 7898053b0eeSFinn Thain cnt--; 7908053b0eeSFinn Thain toPIO--; 7918053b0eeSFinn Thain } 7928053b0eeSFinn Thain if (toPIO > 0) { 7938053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, 7948053b0eeSFinn Thain "Doing %d byte PIO to 0x%p\n", cnt, *data); 7958053b0eeSFinn Thain NCR5380_transfer_pio(instance, &p, &cnt, data); 7968053b0eeSFinn Thain *count -= toPIO - cnt; 7978053b0eeSFinn Thain } 7988053b0eeSFinn Thain } 7998053b0eeSFinn Thain } 8008053b0eeSFinn Thain } 8018053b0eeSFinn Thain 8021da177e4SLinus Torvalds /** 8031da177e4SLinus Torvalds * NCR5380_intr - generic NCR5380 irq handler 8041da177e4SLinus Torvalds * @irq: interrupt number 8051da177e4SLinus Torvalds * @dev_id: device info 8061da177e4SLinus Torvalds * 8071da177e4SLinus Torvalds * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses 8081da177e4SLinus Torvalds * from the disconnected queue, and restarting NCR5380_main() 8091da177e4SLinus Torvalds * as required. 8101da177e4SLinus Torvalds * 811cd400825SFinn Thain * The chip can assert IRQ in any of six different conditions. The IRQ flag 812cd400825SFinn Thain * is then cleared by reading the Reset Parity/Interrupt Register (RPIR). 813cd400825SFinn Thain * Three of these six conditions are latched in the Bus and Status Register: 814cd400825SFinn Thain * - End of DMA (cleared by ending DMA Mode) 815cd400825SFinn Thain * - Parity error (cleared by reading RPIR) 816cd400825SFinn Thain * - Loss of BSY (cleared by reading RPIR) 817cd400825SFinn Thain * Two conditions have flag bits that are not latched: 818cd400825SFinn Thain * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode) 819cd400825SFinn Thain * - Bus reset (non-maskable) 820cd400825SFinn Thain * The remaining condition has no flag bit at all: 821cd400825SFinn Thain * - Selection/reselection 822cd400825SFinn Thain * 823cd400825SFinn Thain * Hence, establishing the cause(s) of any interrupt is partly guesswork. 824cd400825SFinn Thain * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor 825cd400825SFinn Thain * claimed that "the design of the [DP8490] interrupt logic ensures 826cd400825SFinn Thain * interrupts will not be lost (they can be on the DP5380)." 827cd400825SFinn Thain * The L5380/53C80 datasheet from LOGIC Devices has more details. 828cd400825SFinn Thain * 829cd400825SFinn Thain * Checking for bus reset by reading RST is futile because of interrupt 830cd400825SFinn Thain * latency, but a bus reset will reset chip logic. Checking for parity error 831cd400825SFinn Thain * is unnecessary because that interrupt is never enabled. A Loss of BSY 832cd400825SFinn Thain * condition will clear DMA Mode. We can tell when this occurs because the 833cd400825SFinn Thain * the Busy Monitor interrupt is enabled together with DMA Mode. 8341da177e4SLinus Torvalds */ 8351da177e4SLinus Torvalds 836a46865dcSFinn Thain static irqreturn_t __maybe_unused NCR5380_intr(int irq, void *dev_id) 8371da177e4SLinus Torvalds { 838baa9aac6SJeff Garzik struct Scsi_Host *instance = dev_id; 839cd400825SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 840cd400825SFinn Thain int handled = 0; 8411da177e4SLinus Torvalds unsigned char basr; 8421da177e4SLinus Torvalds unsigned long flags; 8431da177e4SLinus Torvalds 84411d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 845cd400825SFinn Thain 8461da177e4SLinus Torvalds basr = NCR5380_read(BUS_AND_STATUS_REG); 8471da177e4SLinus Torvalds if (basr & BASR_IRQ) { 848cd400825SFinn Thain unsigned char mr = NCR5380_read(MODE_REG); 849cd400825SFinn Thain unsigned char sr = NCR5380_read(STATUS_REG); 850cd400825SFinn Thain 851b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n", 852b746545fSFinn Thain irq, basr, sr, mr); 853cd400825SFinn Thain 8548053b0eeSFinn Thain if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) { 8558053b0eeSFinn Thain /* Probably End of DMA, Phase Mismatch or Loss of BSY. 8568053b0eeSFinn Thain * We ack IRQ after clearing Mode Register. Workarounds 8578053b0eeSFinn Thain * for End of DMA errata need to happen in DMA Mode. 8588053b0eeSFinn Thain */ 8598053b0eeSFinn Thain 8608053b0eeSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n"); 8618053b0eeSFinn Thain 8628053b0eeSFinn Thain if (hostdata->connected) { 8638053b0eeSFinn Thain NCR5380_dma_complete(instance); 8648053b0eeSFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 8658053b0eeSFinn Thain } else { 8668053b0eeSFinn Thain NCR5380_write(MODE_REG, MR_BASE); 8678053b0eeSFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 8688053b0eeSFinn Thain } 8698053b0eeSFinn Thain } else if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) && 870cd400825SFinn Thain (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) { 871cd400825SFinn Thain /* Probably reselected */ 872cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 873cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 874cd400825SFinn Thain 875b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n"); 876cd400825SFinn Thain 877cd400825SFinn Thain if (!hostdata->connected) { 878cd400825SFinn Thain NCR5380_reselect(instance); 8798d8601a7SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 880cd400825SFinn Thain } 881cd400825SFinn Thain if (!hostdata->connected) 882cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 883cd400825SFinn Thain } else { 884cd400825SFinn Thain /* Probably Bus Reset */ 885cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 886cd400825SFinn Thain 887b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n"); 888e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 889e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 890e9db3198SFinn Thain #endif 891cd400825SFinn Thain } 892cd400825SFinn Thain handled = 1; 893cd400825SFinn Thain } else { 8949af9fecbSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt without IRQ bit\n"); 895e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 896e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 897e9db3198SFinn Thain #endif 898cd400825SFinn Thain } 899cd400825SFinn Thain 90011d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 901cd400825SFinn Thain 902cd400825SFinn Thain return IRQ_RETVAL(handled); 9031da177e4SLinus Torvalds } 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds /* 906710ddd0dSFinn Thain * Function : int NCR5380_select(struct Scsi_Host *instance, 907710ddd0dSFinn Thain * struct scsi_cmnd *cmd) 9081da177e4SLinus Torvalds * 9091da177e4SLinus Torvalds * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, 9101da177e4SLinus Torvalds * including ARBITRATION, SELECTION, and initial message out for 9111da177e4SLinus Torvalds * IDENTIFY and queue messages. 9121da177e4SLinus Torvalds * 9131da177e4SLinus Torvalds * Inputs : instance - instantiation of the 5380 driver on which this 91476f13b93SFinn Thain * target lives, cmd - SCSI command to execute. 9151da177e4SLinus Torvalds * 916707d62b3SFinn Thain * Returns cmd if selection failed but should be retried, 917707d62b3SFinn Thain * NULL if selection failed and should not be retried, or 918707d62b3SFinn Thain * NULL if selection succeeded (hostdata->connected == cmd). 9191da177e4SLinus Torvalds * 9201da177e4SLinus Torvalds * Side effects : 9211da177e4SLinus Torvalds * If bus busy, arbitration failed, etc, NCR5380_select() will exit 9221da177e4SLinus Torvalds * with registers as they should have been on entry - ie 9231da177e4SLinus Torvalds * SELECT_ENABLE will be set appropriately, the NCR5380 9241da177e4SLinus Torvalds * will cease to drive any SCSI bus signals. 9251da177e4SLinus Torvalds * 9261da177e4SLinus Torvalds * If successful : I_T_L or I_T_L_Q nexus will be established, 9271da177e4SLinus Torvalds * instance->connected will be set to cmd. 9281da177e4SLinus Torvalds * SELECT interrupt will be disabled. 9291da177e4SLinus Torvalds * 9301da177e4SLinus Torvalds * If failed (no target) : cmd->scsi_done() will be called, and the 9311da177e4SLinus Torvalds * cmd->result host byte set to DID_BAD_TARGET. 9321da177e4SLinus Torvalds */ 9331da177e4SLinus Torvalds 934707d62b3SFinn Thain static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, 935707d62b3SFinn Thain struct scsi_cmnd *cmd) 9364ab2a787SFinn Thain __releases(&hostdata->lock) __acquires(&hostdata->lock) 9371da177e4SLinus Torvalds { 938e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 9391da177e4SLinus Torvalds unsigned char tmp[3], phase; 9401da177e4SLinus Torvalds unsigned char *data; 9411da177e4SLinus Torvalds int len; 9421da177e4SLinus Torvalds int err; 9431da177e4SLinus Torvalds 9441da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_ARBITRATION, instance); 945b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n", 946b746545fSFinn Thain instance->this_id); 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds /* 949707d62b3SFinn Thain * Arbitration and selection phases are slow and involve dropping the 950707d62b3SFinn Thain * lock, so we have to watch out for EH. An exception handler may 951707d62b3SFinn Thain * change 'selecting' to NULL. This function will then return NULL 952707d62b3SFinn Thain * so that the caller will forget about 'cmd'. (During information 953707d62b3SFinn Thain * transfer phases, EH may change 'connected' to NULL.) 954707d62b3SFinn Thain */ 955707d62b3SFinn Thain hostdata->selecting = cmd; 956707d62b3SFinn Thain 957707d62b3SFinn Thain /* 9581da177e4SLinus Torvalds * Set the phase bits to 0, otherwise the NCR5380 won't drive the 9591da177e4SLinus Torvalds * data bus during SELECTION. 9601da177e4SLinus Torvalds */ 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 9631da177e4SLinus Torvalds 9641da177e4SLinus Torvalds /* 9651da177e4SLinus Torvalds * Start arbitration. 9661da177e4SLinus Torvalds */ 9671da177e4SLinus Torvalds 9681da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); 9691da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_ARBITRATE); 9701da177e4SLinus Torvalds 97155500d9bSFinn Thain /* The chip now waits for BUS FREE phase. Then after the 800 ns 97255500d9bSFinn Thain * Bus Free Delay, arbitration will begin. 9731da177e4SLinus Torvalds */ 9741da177e4SLinus Torvalds 97511d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 976d5d37a0aSFinn Thain err = NCR5380_poll_politely2(hostdata, MODE_REG, MR_ARBITRATE, 0, 977b32ade12SFinn Thain INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, 978b32ade12SFinn Thain ICR_ARBITRATION_PROGRESS, HZ); 97911d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 98055500d9bSFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) { 98155500d9bSFinn Thain /* Reselection interrupt */ 982707d62b3SFinn Thain goto out; 98355500d9bSFinn Thain } 984ccf6efd7SFinn Thain if (!hostdata->selecting) { 985ccf6efd7SFinn Thain /* Command was aborted */ 986ccf6efd7SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 987*6a162836SFinn Thain return NULL; 988ccf6efd7SFinn Thain } 989b32ade12SFinn Thain if (err < 0) { 990b32ade12SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 991b32ade12SFinn Thain shost_printk(KERN_ERR, instance, 992b32ade12SFinn Thain "select: arbitration timeout\n"); 993707d62b3SFinn Thain goto out; 99455500d9bSFinn Thain } 99511d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 99655500d9bSFinn Thain 99755500d9bSFinn Thain /* The SCSI-2 arbitration delay is 2.4 us */ 9981da177e4SLinus Torvalds udelay(3); 9991da177e4SLinus Torvalds 10001da177e4SLinus Torvalds /* Check for lost arbitration */ 10010d2cf867SFinn Thain if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || 10020d2cf867SFinn Thain (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || 10030d2cf867SFinn Thain (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { 10041da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 1005b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n"); 100611d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1007707d62b3SFinn Thain goto out; 10081da177e4SLinus Torvalds } 1009cf13b083SFinn Thain 1010cf13b083SFinn Thain /* After/during arbitration, BSY should be asserted. 1011cf13b083SFinn Thain * IBM DPES-31080 Version S31Q works now 1012cf13b083SFinn Thain * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) 1013cf13b083SFinn Thain */ 1014cf13b083SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, 1015cf13b083SFinn Thain ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY); 10161da177e4SLinus Torvalds 10171da177e4SLinus Torvalds /* 10181da177e4SLinus Torvalds * Again, bus clear + bus settle time is 1.2us, however, this is 10191da177e4SLinus Torvalds * a minimum so we'll udelay ceil(1.2) 10201da177e4SLinus Torvalds */ 10211da177e4SLinus Torvalds 10229c3f0e2bSFinn Thain if (hostdata->flags & FLAG_TOSHIBA_DELAY) 10239c3f0e2bSFinn Thain udelay(15); 10249c3f0e2bSFinn Thain else 10251da177e4SLinus Torvalds udelay(2); 10261da177e4SLinus Torvalds 102711d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 102811d2f63bSFinn Thain 102972064a78SFinn Thain /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */ 103072064a78SFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) 1031707d62b3SFinn Thain goto out; 1032707d62b3SFinn Thain 1033707d62b3SFinn Thain if (!hostdata->selecting) { 1034707d62b3SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1035707d62b3SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1036*6a162836SFinn Thain return NULL; 1037707d62b3SFinn Thain } 103872064a78SFinn Thain 1039b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n"); 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds /* 10421da177e4SLinus Torvalds * Now that we have won arbitration, start Selection process, asserting 10431da177e4SLinus Torvalds * the host and target ID's on the SCSI bus. 10441da177e4SLinus Torvalds */ 10451da177e4SLinus Torvalds 10463d07d22bSFinn Thain NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask | (1 << scmd_id(cmd))); 10471da177e4SLinus Torvalds 10481da177e4SLinus Torvalds /* 10491da177e4SLinus Torvalds * Raise ATN while SEL is true before BSY goes false from arbitration, 10501da177e4SLinus Torvalds * since this is the only way to guarantee that we'll get a MESSAGE OUT 10511da177e4SLinus Torvalds * phase immediately after selection. 10521da177e4SLinus Torvalds */ 10531da177e4SLinus Torvalds 10543d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY | 10553d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL); 10561da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 10571da177e4SLinus Torvalds 10581da177e4SLinus Torvalds /* 10591da177e4SLinus Torvalds * Reselect interrupts must be turned off prior to the dropping of BSY, 10601da177e4SLinus Torvalds * otherwise we will trigger an interrupt. 10611da177e4SLinus Torvalds */ 10621da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 10631da177e4SLinus Torvalds 106411d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 106511d2f63bSFinn Thain 10661da177e4SLinus Torvalds /* 10671da177e4SLinus Torvalds * The initiator shall then wait at least two deskew delays and release 10681da177e4SLinus Torvalds * the BSY signal. 10691da177e4SLinus Torvalds */ 10701da177e4SLinus Torvalds udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ 10711da177e4SLinus Torvalds 10721da177e4SLinus Torvalds /* Reset BSY */ 10733d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | 10743d07d22bSFinn Thain ICR_ASSERT_ATN | ICR_ASSERT_SEL); 10751da177e4SLinus Torvalds 10761da177e4SLinus Torvalds /* 10771da177e4SLinus Torvalds * Something weird happens when we cease to drive BSY - looks 10781da177e4SLinus Torvalds * like the board/chip is letting us do another read before the 10791da177e4SLinus Torvalds * appropriate propagation delay has expired, and we're confusing 10801da177e4SLinus Torvalds * a BSY signal from ourselves as the target's response to SELECTION. 10811da177e4SLinus Torvalds * 10821da177e4SLinus Torvalds * A small delay (the 'C++' frontend breaks the pipeline with an 10831da177e4SLinus Torvalds * unnecessary jump, making it work on my 386-33/Trantor T128, the 10841da177e4SLinus Torvalds * tighter 'C' code breaks and requires this) solves the problem - 10851da177e4SLinus Torvalds * the 1 us delay is arbitrary, and only used because this delay will 10861da177e4SLinus Torvalds * be the same on other platforms and since it works here, it should 10871da177e4SLinus Torvalds * work there. 10881da177e4SLinus Torvalds * 10891da177e4SLinus Torvalds * wingel suggests that this could be due to failing to wait 10901da177e4SLinus Torvalds * one deskew delay. 10911da177e4SLinus Torvalds */ 10921da177e4SLinus Torvalds 10931da177e4SLinus Torvalds udelay(1); 10941da177e4SLinus Torvalds 1095b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd)); 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds /* 10981da177e4SLinus Torvalds * The SCSI specification calls for a 250 ms timeout for the actual 10991da177e4SLinus Torvalds * selection. 11001da177e4SLinus Torvalds */ 11011da177e4SLinus Torvalds 1102d5d37a0aSFinn Thain err = NCR5380_poll_politely(hostdata, STATUS_REG, SR_BSY, SR_BSY, 1103ae753a33SFinn Thain msecs_to_jiffies(250)); 11041da177e4SLinus Torvalds 11051da177e4SLinus Torvalds if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { 110611d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 11071da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 11081da177e4SLinus Torvalds NCR5380_reselect(instance); 1109cd400825SFinn Thain if (!hostdata->connected) 11101da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 11116a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n"); 1112707d62b3SFinn Thain goto out; 11131da177e4SLinus Torvalds } 1114ae753a33SFinn Thain 1115ae753a33SFinn Thain if (err < 0) { 111611d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1117ae753a33SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1118707d62b3SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1119*6a162836SFinn Thain 1120707d62b3SFinn Thain /* Can't touch cmd if it has been reclaimed by the scsi ML */ 1121*6a162836SFinn Thain if (!hostdata->selecting) 1122*6a162836SFinn Thain return NULL; 1123*6a162836SFinn Thain 1124ae753a33SFinn Thain cmd->result = DID_BAD_TARGET << 16; 1125677e0194SFinn Thain complete_cmd(instance, cmd); 1126*6a162836SFinn Thain dsprintk(NDEBUG_SELECTION, instance, 1127*6a162836SFinn Thain "target did not respond within 250ms\n"); 1128707d62b3SFinn Thain cmd = NULL; 1129707d62b3SFinn Thain goto out; 1130ae753a33SFinn Thain } 1131ae753a33SFinn Thain 11321da177e4SLinus Torvalds /* 11331da177e4SLinus Torvalds * No less than two deskew delays after the initiator detects the 11341da177e4SLinus Torvalds * BSY signal is true, it shall release the SEL signal and may 11351da177e4SLinus Torvalds * change the DATA BUS. -wingel 11361da177e4SLinus Torvalds */ 11371da177e4SLinus Torvalds 11381da177e4SLinus Torvalds udelay(1); 11391da177e4SLinus Torvalds 11401da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds /* 11431da177e4SLinus Torvalds * Since we followed the SCSI spec, and raised ATN while SEL 11441da177e4SLinus Torvalds * was true but before BSY was false during selection, the information 11451da177e4SLinus Torvalds * transfer phase should be a MESSAGE OUT phase so that we can send the 11461da177e4SLinus Torvalds * IDENTIFY message. 11471da177e4SLinus Torvalds */ 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds /* Wait for start of REQ/ACK handshake */ 11501da177e4SLinus Torvalds 1151d5d37a0aSFinn Thain err = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, HZ); 115211d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 11531cc160e1SFinn Thain if (err < 0) { 115455500d9bSFinn Thain shost_printk(KERN_ERR, instance, "select: REQ timeout\n"); 115555500d9bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 11561da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1157707d62b3SFinn Thain goto out; 1158707d62b3SFinn Thain } 1159707d62b3SFinn Thain if (!hostdata->selecting) { 1160707d62b3SFinn Thain do_abort(instance); 1161*6a162836SFinn Thain return NULL; 11621da177e4SLinus Torvalds } 11631da177e4SLinus Torvalds 1164b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n", 1165b746545fSFinn Thain scmd_id(cmd)); 116622f5f10dSFinn Thain tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun); 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds len = 1; 11691da177e4SLinus Torvalds data = tmp; 11701da177e4SLinus Torvalds phase = PHASE_MSGOUT; 11711da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 1172b15e791dSFinn Thain if (len) { 1173b15e791dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1174b15e791dSFinn Thain cmd->result = DID_ERROR << 16; 1175b15e791dSFinn Thain complete_cmd(instance, cmd); 1176b15e791dSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "IDENTIFY message transfer failed\n"); 1177b15e791dSFinn Thain cmd = NULL; 1178b15e791dSFinn Thain goto out; 1179b15e791dSFinn Thain } 1180b15e791dSFinn Thain 1181b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n"); 118211d2f63bSFinn Thain 11831da177e4SLinus Torvalds hostdata->connected = cmd; 11843d07d22bSFinn Thain hostdata->busy[cmd->device->id] |= 1 << cmd->device->lun; 11851da177e4SLinus Torvalds 1186e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1187e9db3198SFinn Thain dregs->csr |= CSR_INTR; 1188e9db3198SFinn Thain #endif 1189e9db3198SFinn Thain 11901da177e4SLinus Torvalds initialize_SCp(cmd); 11911da177e4SLinus Torvalds 1192707d62b3SFinn Thain cmd = NULL; 1193707d62b3SFinn Thain 1194707d62b3SFinn Thain out: 1195707d62b3SFinn Thain if (!hostdata->selecting) 1196707d62b3SFinn Thain return NULL; 1197707d62b3SFinn Thain hostdata->selecting = NULL; 1198707d62b3SFinn Thain return cmd; 11991da177e4SLinus Torvalds } 12001da177e4SLinus Torvalds 12011da177e4SLinus Torvalds /* 12021da177e4SLinus Torvalds * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 12031da177e4SLinus Torvalds * unsigned char *phase, int *count, unsigned char **data) 12041da177e4SLinus Torvalds * 12051da177e4SLinus Torvalds * Purpose : transfers data in given phase using polled I/O 12061da177e4SLinus Torvalds * 12071da177e4SLinus Torvalds * Inputs : instance - instance of driver, *phase - pointer to 12081da177e4SLinus Torvalds * what phase is expected, *count - pointer to number of 12091da177e4SLinus Torvalds * bytes to transfer, **data - pointer to data pointer. 12101da177e4SLinus Torvalds * 12111da177e4SLinus Torvalds * Returns : -1 when different phase is entered without transferring 12120d2cf867SFinn Thain * maximum number of bytes, 0 if all bytes are transferred or exit 12131da177e4SLinus Torvalds * is in same phase. 12141da177e4SLinus Torvalds * 12151da177e4SLinus Torvalds * Also, *phase, *count, *data are modified in place. 12161da177e4SLinus Torvalds * 12171da177e4SLinus Torvalds * XXX Note : handling for bus free may be useful. 12181da177e4SLinus Torvalds */ 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds /* 12211da177e4SLinus Torvalds * Note : this code is not as quick as it could be, however it 12221da177e4SLinus Torvalds * IS 100% reliable, and for the actual data transfer where speed 12231da177e4SLinus Torvalds * counts, we will always do a pseudo DMA or DMA transfer. 12241da177e4SLinus Torvalds */ 12251da177e4SLinus Torvalds 12260d2cf867SFinn Thain static int NCR5380_transfer_pio(struct Scsi_Host *instance, 12270d2cf867SFinn Thain unsigned char *phase, int *count, 12280d2cf867SFinn Thain unsigned char **data) 12290d2cf867SFinn Thain { 123061e1ce58SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 12311da177e4SLinus Torvalds unsigned char p = *phase, tmp; 12321da177e4SLinus Torvalds int c = *count; 12331da177e4SLinus Torvalds unsigned char *d = *data; 12341da177e4SLinus Torvalds 12351da177e4SLinus Torvalds /* 12361da177e4SLinus Torvalds * The NCR5380 chip will only drive the SCSI bus when the 12371da177e4SLinus Torvalds * phase specified in the appropriate bits of the TARGET COMMAND 12381da177e4SLinus Torvalds * REGISTER match the STATUS REGISTER 12391da177e4SLinus Torvalds */ 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 12421da177e4SLinus Torvalds 12431da177e4SLinus Torvalds do { 12441da177e4SLinus Torvalds /* 12451da177e4SLinus Torvalds * Wait for assertion of REQ, after which the phase bits will be 12461da177e4SLinus Torvalds * valid 12471da177e4SLinus Torvalds */ 12481da177e4SLinus Torvalds 1249d5d37a0aSFinn Thain if (NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0) 12501da177e4SLinus Torvalds break; 12511da177e4SLinus Torvalds 1252b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n"); 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds /* Check for phase mismatch */ 1255686f3990SFinn Thain if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) { 1256b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "phase mismatch\n"); 1257b746545fSFinn Thain NCR5380_dprint_phase(NDEBUG_PIO, instance); 12581da177e4SLinus Torvalds break; 12591da177e4SLinus Torvalds } 12600d2cf867SFinn Thain 12611da177e4SLinus Torvalds /* Do actual transfer from SCSI bus to / from memory */ 12621da177e4SLinus Torvalds if (!(p & SR_IO)) 12631da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, *d); 12641da177e4SLinus Torvalds else 12651da177e4SLinus Torvalds *d = NCR5380_read(CURRENT_SCSI_DATA_REG); 12661da177e4SLinus Torvalds 12671da177e4SLinus Torvalds ++d; 12681da177e4SLinus Torvalds 12691da177e4SLinus Torvalds /* 12701da177e4SLinus Torvalds * The SCSI standard suggests that in MSGOUT phase, the initiator 12711da177e4SLinus Torvalds * should drop ATN on the last byte of the message phase 12721da177e4SLinus Torvalds * after REQ has been asserted for the handshake but before 12731da177e4SLinus Torvalds * the initiator raises ACK. 12741da177e4SLinus Torvalds */ 12751da177e4SLinus Torvalds 12761da177e4SLinus Torvalds if (!(p & SR_IO)) { 12771da177e4SLinus Torvalds if (!((p & SR_MSG) && c > 1)) { 12781da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 12791da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 12803d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 12813d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ACK); 12821da177e4SLinus Torvalds } else { 12833d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 12843d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ATN); 12851da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 12863d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 12873d07d22bSFinn Thain ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 12881da177e4SLinus Torvalds } 12891da177e4SLinus Torvalds } else { 12901da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 12911da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); 12921da177e4SLinus Torvalds } 12931da177e4SLinus Torvalds 1294d5d37a0aSFinn Thain if (NCR5380_poll_politely(hostdata, 1295a2edc4a6SFinn Thain STATUS_REG, SR_REQ, 0, 5 * HZ) < 0) 1296a2edc4a6SFinn Thain break; 1297a2edc4a6SFinn Thain 1298b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n"); 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds /* 13011da177e4SLinus Torvalds * We have several special cases to consider during REQ/ACK handshaking : 13021da177e4SLinus Torvalds * 1. We were in MSGOUT phase, and we are on the last byte of the 13031da177e4SLinus Torvalds * message. ATN must be dropped as ACK is dropped. 13041da177e4SLinus Torvalds * 13051da177e4SLinus Torvalds * 2. We are in a MSGIN phase, and we are on the last byte of the 13061da177e4SLinus Torvalds * message. We must exit with ACK asserted, so that the calling 13071da177e4SLinus Torvalds * code may raise ATN before dropping ACK to reject the message. 13081da177e4SLinus Torvalds * 13091da177e4SLinus Torvalds * 3. ACK and ATN are clear and the target may proceed as normal. 13101da177e4SLinus Torvalds */ 13111da177e4SLinus Torvalds if (!(p == PHASE_MSGIN && c == 1)) { 13121da177e4SLinus Torvalds if (p == PHASE_MSGOUT && c > 1) 13131da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 13141da177e4SLinus Torvalds else 13151da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 13161da177e4SLinus Torvalds } 13171da177e4SLinus Torvalds } while (--c); 13181da177e4SLinus Torvalds 1319b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "residual %d\n", c); 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds *count = c; 13221da177e4SLinus Torvalds *data = d; 13231da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 1324a2edc4a6SFinn Thain /* The phase read from the bus is valid if either REQ is (already) 1325a2edc4a6SFinn Thain * asserted or if ACK hasn't been released yet. The latter applies if 1326a2edc4a6SFinn Thain * we're in MSG IN, DATA IN or STATUS and all bytes have been received. 1327a2edc4a6SFinn Thain */ 1328a2edc4a6SFinn Thain if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0)) 13291da177e4SLinus Torvalds *phase = tmp & PHASE_MASK; 13301da177e4SLinus Torvalds else 13311da177e4SLinus Torvalds *phase = PHASE_UNKNOWN; 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds if (!c || (*phase == p)) 13341da177e4SLinus Torvalds return 0; 13351da177e4SLinus Torvalds else 13361da177e4SLinus Torvalds return -1; 13371da177e4SLinus Torvalds } 13381da177e4SLinus Torvalds 13391da177e4SLinus Torvalds /** 13401da177e4SLinus Torvalds * do_reset - issue a reset command 1341636b1ec8SFinn Thain * @instance: adapter to reset 13421da177e4SLinus Torvalds * 13431da177e4SLinus Torvalds * Issue a reset sequence to the NCR5380 and try and get the bus 13441da177e4SLinus Torvalds * back into sane shape. 13451da177e4SLinus Torvalds * 1346636b1ec8SFinn Thain * This clears the reset interrupt flag because there may be no handler for 1347636b1ec8SFinn Thain * it. When the driver is initialized, the NCR5380_intr() handler has not yet 1348636b1ec8SFinn Thain * been installed. And when in EH we may have released the ST DMA interrupt. 13491da177e4SLinus Torvalds */ 13501da177e4SLinus Torvalds 135154d8fe44SFinn Thain static void do_reset(struct Scsi_Host *instance) 135254d8fe44SFinn Thain { 135361e1ce58SFinn Thain struct NCR5380_hostdata __maybe_unused *hostdata = shost_priv(instance); 1354636b1ec8SFinn Thain unsigned long flags; 1355636b1ec8SFinn Thain 1356636b1ec8SFinn Thain local_irq_save(flags); 1357636b1ec8SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 1358636b1ec8SFinn Thain PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); 13591da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); 1360636b1ec8SFinn Thain udelay(50); 13611da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1362636b1ec8SFinn Thain (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); 1363636b1ec8SFinn Thain local_irq_restore(flags); 13641da177e4SLinus Torvalds } 13651da177e4SLinus Torvalds 136680d3eb6dSFinn Thain /** 136780d3eb6dSFinn Thain * do_abort - abort the currently established nexus by going to 136880d3eb6dSFinn Thain * MESSAGE OUT phase and sending an ABORT message. 136980d3eb6dSFinn Thain * @instance: relevant scsi host instance 13701da177e4SLinus Torvalds * 137180d3eb6dSFinn Thain * Returns 0 on success, -1 on failure. 13721da177e4SLinus Torvalds */ 13731da177e4SLinus Torvalds 137454d8fe44SFinn Thain static int do_abort(struct Scsi_Host *instance) 137554d8fe44SFinn Thain { 137661e1ce58SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 13771da177e4SLinus Torvalds unsigned char *msgptr, phase, tmp; 13781da177e4SLinus Torvalds int len; 13791da177e4SLinus Torvalds int rc; 13801da177e4SLinus Torvalds 13811da177e4SLinus Torvalds /* Request message out phase */ 13821da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 13831da177e4SLinus Torvalds 13841da177e4SLinus Torvalds /* 13851da177e4SLinus Torvalds * Wait for the target to indicate a valid phase by asserting 13861da177e4SLinus Torvalds * REQ. Once this happens, we'll have either a MSGOUT phase 13871da177e4SLinus Torvalds * and can immediately send the ABORT message, or we'll have some 13881da177e4SLinus Torvalds * other phase and will have to source/sink data. 13891da177e4SLinus Torvalds * 13901da177e4SLinus Torvalds * We really don't care what value was on the bus or what value 13911da177e4SLinus Torvalds * the target sees, so we just handshake. 13921da177e4SLinus Torvalds */ 13931da177e4SLinus Torvalds 1394d5d37a0aSFinn Thain rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ); 13951da177e4SLinus Torvalds if (rc < 0) 139680d3eb6dSFinn Thain goto timeout; 13971da177e4SLinus Torvalds 1398f35d3474SFinn Thain tmp = NCR5380_read(STATUS_REG) & PHASE_MASK; 13991da177e4SLinus Torvalds 14001da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 14011da177e4SLinus Torvalds 1402f35d3474SFinn Thain if (tmp != PHASE_MSGOUT) { 14030d2cf867SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, 14040d2cf867SFinn Thain ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 1405d5d37a0aSFinn Thain rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, 0, 3 * HZ); 14061cc160e1SFinn Thain if (rc < 0) 140780d3eb6dSFinn Thain goto timeout; 140880d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 14091da177e4SLinus Torvalds } 14100d2cf867SFinn Thain 14111da177e4SLinus Torvalds tmp = ABORT; 14121da177e4SLinus Torvalds msgptr = &tmp; 14131da177e4SLinus Torvalds len = 1; 14141da177e4SLinus Torvalds phase = PHASE_MSGOUT; 141554d8fe44SFinn Thain NCR5380_transfer_pio(instance, &phase, &len, &msgptr); 14161da177e4SLinus Torvalds 14171da177e4SLinus Torvalds /* 14181da177e4SLinus Torvalds * If we got here, and the command completed successfully, 14191da177e4SLinus Torvalds * we're about to go into bus free state. 14201da177e4SLinus Torvalds */ 14211da177e4SLinus Torvalds 14221da177e4SLinus Torvalds return len ? -1 : 0; 142380d3eb6dSFinn Thain 142480d3eb6dSFinn Thain timeout: 142580d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 142680d3eb6dSFinn Thain return -1; 14271da177e4SLinus Torvalds } 14281da177e4SLinus Torvalds 14291da177e4SLinus Torvalds /* 14301da177e4SLinus Torvalds * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 14311da177e4SLinus Torvalds * unsigned char *phase, int *count, unsigned char **data) 14321da177e4SLinus Torvalds * 14331da177e4SLinus Torvalds * Purpose : transfers data in given phase using either real 14341da177e4SLinus Torvalds * or pseudo DMA. 14351da177e4SLinus Torvalds * 14361da177e4SLinus Torvalds * Inputs : instance - instance of driver, *phase - pointer to 14371da177e4SLinus Torvalds * what phase is expected, *count - pointer to number of 14381da177e4SLinus Torvalds * bytes to transfer, **data - pointer to data pointer. 14391da177e4SLinus Torvalds * 14401da177e4SLinus Torvalds * Returns : -1 when different phase is entered without transferring 144125985edcSLucas De Marchi * maximum number of bytes, 0 if all bytes or transferred or exit 14421da177e4SLinus Torvalds * is in same phase. 14431da177e4SLinus Torvalds * 14441da177e4SLinus Torvalds * Also, *phase, *count, *data are modified in place. 14451da177e4SLinus Torvalds */ 14461da177e4SLinus Torvalds 14471da177e4SLinus Torvalds 14480d2cf867SFinn Thain static int NCR5380_transfer_dma(struct Scsi_Host *instance, 14490d2cf867SFinn Thain unsigned char *phase, int *count, 14500d2cf867SFinn Thain unsigned char **data) 14510d2cf867SFinn Thain { 14520d2cf867SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 1453f0ea73a4SFinn Thain int c = *count; 1454f0ea73a4SFinn Thain unsigned char p = *phase; 1455f0ea73a4SFinn Thain unsigned char *d = *data; 14561da177e4SLinus Torvalds unsigned char tmp; 14578053b0eeSFinn Thain int result = 0; 14581da177e4SLinus Torvalds 14591da177e4SLinus Torvalds if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { 14601da177e4SLinus Torvalds *phase = tmp; 14611da177e4SLinus Torvalds return -1; 14621da177e4SLinus Torvalds } 14631da177e4SLinus Torvalds 14648053b0eeSFinn Thain hostdata->connected->SCp.phase = p; 14658053b0eeSFinn Thain 14668053b0eeSFinn Thain if (p & SR_IO) { 14678053b0eeSFinn Thain if (hostdata->read_overruns) 14688053b0eeSFinn Thain c -= hostdata->read_overruns; 14698053b0eeSFinn Thain else if (hostdata->flags & FLAG_DMA_FIXUP) 14708053b0eeSFinn Thain --c; 14718053b0eeSFinn Thain } 14728053b0eeSFinn Thain 14738053b0eeSFinn Thain dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n", 14748053b0eeSFinn Thain (p & SR_IO) ? "receive" : "send", c, d); 14758053b0eeSFinn Thain 1476e9db3198SFinn Thain #ifdef CONFIG_SUN3 1477e9db3198SFinn Thain /* send start chain */ 1478e9db3198SFinn Thain sun3scsi_dma_start(c, *data); 1479e9db3198SFinn Thain #endif 1480e9db3198SFinn Thain 14811da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 1482cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY | 1483cd400825SFinn Thain MR_ENABLE_EOP_INTR); 14841da177e4SLinus Torvalds 14858053b0eeSFinn Thain if (!(hostdata->flags & FLAG_LATE_DMA_SETUP)) { 14868053b0eeSFinn Thain /* On the Medusa, it is a must to initialize the DMA before 14878053b0eeSFinn Thain * starting the NCR. This is also the cleaner way for the TT. 14888053b0eeSFinn Thain */ 14898053b0eeSFinn Thain if (p & SR_IO) 14904a98f896SFinn Thain result = NCR5380_dma_recv_setup(hostdata, d, c); 14918053b0eeSFinn Thain else 14924a98f896SFinn Thain result = NCR5380_dma_send_setup(hostdata, d, c); 14938053b0eeSFinn Thain } 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds /* 14961da177e4SLinus Torvalds * On the PAS16 at least I/O recovery delays are not needed here. 14971da177e4SLinus Torvalds * Everyone else seems to want them. 14981da177e4SLinus Torvalds */ 14991da177e4SLinus Torvalds 15001da177e4SLinus Torvalds if (p & SR_IO) { 1501e9db3198SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1502e5d55d1aSFinn Thain NCR5380_io_delay(1); 15031da177e4SLinus Torvalds NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); 15041da177e4SLinus Torvalds } else { 1505e5d55d1aSFinn Thain NCR5380_io_delay(1); 15061da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 1507e5d55d1aSFinn Thain NCR5380_io_delay(1); 15081da177e4SLinus Torvalds NCR5380_write(START_DMA_SEND_REG, 0); 1509e5d55d1aSFinn Thain NCR5380_io_delay(1); 15101da177e4SLinus Torvalds } 15111da177e4SLinus Torvalds 1512e9db3198SFinn Thain #ifdef CONFIG_SUN3 1513e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1514e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 1515e9db3198SFinn Thain #endif 1516e9db3198SFinn Thain sun3_dma_active = 1; 1517e9db3198SFinn Thain #endif 1518e9db3198SFinn Thain 15198053b0eeSFinn Thain if (hostdata->flags & FLAG_LATE_DMA_SETUP) { 15208053b0eeSFinn Thain /* On the Falcon, the DMA setup must be done after the last 15218053b0eeSFinn Thain * NCR access, else the DMA setup gets trashed! 15228053b0eeSFinn Thain */ 15238053b0eeSFinn Thain if (p & SR_IO) 15244a98f896SFinn Thain result = NCR5380_dma_recv_setup(hostdata, d, c); 15258053b0eeSFinn Thain else 15264a98f896SFinn Thain result = NCR5380_dma_send_setup(hostdata, d, c); 15278053b0eeSFinn Thain } 15288053b0eeSFinn Thain 15298053b0eeSFinn Thain /* On failure, NCR5380_dma_xxxx_setup() returns a negative int. */ 15308053b0eeSFinn Thain if (result < 0) 15318053b0eeSFinn Thain return result; 15328053b0eeSFinn Thain 15338053b0eeSFinn Thain /* For real DMA, result is the byte count. DMA interrupt is expected. */ 15348053b0eeSFinn Thain if (result > 0) { 15358053b0eeSFinn Thain hostdata->dma_len = result; 15368053b0eeSFinn Thain return 0; 15378053b0eeSFinn Thain } 15388053b0eeSFinn Thain 15398053b0eeSFinn Thain /* The result is zero iff pseudo DMA send/receive was completed. */ 15408053b0eeSFinn Thain hostdata->dma_len = c; 15418053b0eeSFinn Thain 15421da177e4SLinus Torvalds /* 1543e4dec680SFinn Thain * A note regarding the DMA errata workarounds for early NMOS silicon. 1544c16df32eSFinn Thain * 1545c16df32eSFinn Thain * For DMA sends, we want to wait until the last byte has been 1546c16df32eSFinn Thain * transferred out over the bus before we turn off DMA mode. Alas, there 1547c16df32eSFinn Thain * seems to be no terribly good way of doing this on a 5380 under all 1548c16df32eSFinn Thain * conditions. For non-scatter-gather operations, we can wait until REQ 1549c16df32eSFinn Thain * and ACK both go false, or until a phase mismatch occurs. Gather-sends 1550c16df32eSFinn Thain * are nastier, since the device will be expecting more data than we 1551c16df32eSFinn Thain * are prepared to send it, and REQ will remain asserted. On a 53C8[01] we 1552c16df32eSFinn Thain * could test Last Byte Sent to assure transfer (I imagine this is precisely 1553c16df32eSFinn Thain * why this signal was added to the newer chips) but on the older 538[01] 1554c16df32eSFinn Thain * this signal does not exist. The workaround for this lack is a watchdog; 1555c16df32eSFinn Thain * we bail out of the wait-loop after a modest amount of wait-time if 1556c16df32eSFinn Thain * the usual exit conditions are not met. Not a terribly clean or 1557c16df32eSFinn Thain * correct solution :-% 1558c16df32eSFinn Thain * 1559c16df32eSFinn Thain * DMA receive is equally tricky due to a nasty characteristic of the NCR5380. 1560c16df32eSFinn Thain * If the chip is in DMA receive mode, it will respond to a target's 1561c16df32eSFinn Thain * REQ by latching the SCSI data into the INPUT DATA register and asserting 1562c16df32eSFinn Thain * ACK, even if it has _already_ been notified by the DMA controller that 1563c16df32eSFinn Thain * the current DMA transfer has completed! If the NCR5380 is then taken 1564c16df32eSFinn Thain * out of DMA mode, this already-acknowledged byte is lost. This is 1565c16df32eSFinn Thain * not a problem for "one DMA transfer per READ command", because 1566c16df32eSFinn Thain * the situation will never arise... either all of the data is DMA'ed 1567c16df32eSFinn Thain * properly, or the target switches to MESSAGE IN phase to signal a 1568c16df32eSFinn Thain * disconnection (either operation bringing the DMA to a clean halt). 1569c16df32eSFinn Thain * However, in order to handle scatter-receive, we must work around the 1570e4dec680SFinn Thain * problem. The chosen fix is to DMA fewer bytes, then check for the 1571c16df32eSFinn Thain * condition before taking the NCR5380 out of DMA mode. One or two extra 1572c16df32eSFinn Thain * bytes are transferred via PIO as necessary to fill out the original 1573c16df32eSFinn Thain * request. 15741da177e4SLinus Torvalds */ 15751da177e4SLinus Torvalds 15768053b0eeSFinn Thain if (hostdata->flags & FLAG_DMA_FIXUP) { 15771da177e4SLinus Torvalds if (p & SR_IO) { 15781da177e4SLinus Torvalds /* 1579e4dec680SFinn Thain * The workaround was to transfer fewer bytes than we 15801da177e4SLinus Torvalds * intended to with the pseudo-DMA read function, wait for 15811da177e4SLinus Torvalds * the chip to latch the last byte, read it, and then disable 15821da177e4SLinus Torvalds * pseudo-DMA mode. 15831da177e4SLinus Torvalds * 15841da177e4SLinus Torvalds * After REQ is asserted, the NCR5380 asserts DRQ and ACK. 15851da177e4SLinus Torvalds * REQ is deasserted when ACK is asserted, and not reasserted 15861da177e4SLinus Torvalds * until ACK goes false. Since the NCR5380 won't lower ACK 15871da177e4SLinus Torvalds * until DACK is asserted, which won't happen unless we twiddle 15881da177e4SLinus Torvalds * the DMA port or we take the NCR5380 out of DMA mode, we 15891da177e4SLinus Torvalds * can guarantee that we won't handshake another extra 15901da177e4SLinus Torvalds * byte. 15911da177e4SLinus Torvalds */ 15921da177e4SLinus Torvalds 1593d5d37a0aSFinn Thain if (NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, 159455181be8SFinn Thain BASR_DRQ, BASR_DRQ, HZ) < 0) { 1595438af51cSFinn Thain result = -1; 159655181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n"); 159755181be8SFinn Thain } 1598d5d37a0aSFinn Thain if (NCR5380_poll_politely(hostdata, STATUS_REG, 159955181be8SFinn Thain SR_REQ, 0, HZ) < 0) { 1600438af51cSFinn Thain result = -1; 160155181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n"); 160255181be8SFinn Thain } 16038053b0eeSFinn Thain d[*count - 1] = NCR5380_read(INPUT_DATA_REG); 16041da177e4SLinus Torvalds } else { 16051da177e4SLinus Torvalds /* 16061da177e4SLinus Torvalds * Wait for the last byte to be sent. If REQ is being asserted for 16071da177e4SLinus Torvalds * the byte we're interested, we'll ACK it and it will go false. 16081da177e4SLinus Torvalds */ 1609d5d37a0aSFinn Thain if (NCR5380_poll_politely2(hostdata, 161055181be8SFinn Thain BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ, 161155181be8SFinn Thain BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) { 1612438af51cSFinn Thain result = -1; 161355181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n"); 16141da177e4SLinus Torvalds } 16151da177e4SLinus Torvalds } 16161da177e4SLinus Torvalds } 16178053b0eeSFinn Thain 16188053b0eeSFinn Thain NCR5380_dma_complete(instance); 1619438af51cSFinn Thain return result; 16201da177e4SLinus Torvalds } 16211da177e4SLinus Torvalds 16221da177e4SLinus Torvalds /* 16231da177e4SLinus Torvalds * Function : NCR5380_information_transfer (struct Scsi_Host *instance) 16241da177e4SLinus Torvalds * 16251da177e4SLinus Torvalds * Purpose : run through the various SCSI phases and do as the target 16261da177e4SLinus Torvalds * directs us to. Operates on the currently connected command, 16271da177e4SLinus Torvalds * instance->connected. 16281da177e4SLinus Torvalds * 16291da177e4SLinus Torvalds * Inputs : instance, instance for which we are doing commands 16301da177e4SLinus Torvalds * 16311da177e4SLinus Torvalds * Side effects : SCSI things happen, the disconnected queue will be 16321da177e4SLinus Torvalds * modified if a command disconnects, *instance->connected will 16331da177e4SLinus Torvalds * change. 16341da177e4SLinus Torvalds * 16351da177e4SLinus Torvalds * XXX Note : we need to watch for bus free or a reset condition here 16361da177e4SLinus Torvalds * to recover from an unexpected bus free condition. 16371da177e4SLinus Torvalds */ 16381da177e4SLinus Torvalds 16390d2cf867SFinn Thain static void NCR5380_information_transfer(struct Scsi_Host *instance) 16404ab2a787SFinn Thain __releases(&hostdata->lock) __acquires(&hostdata->lock) 16410d2cf867SFinn Thain { 1642e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 16431da177e4SLinus Torvalds unsigned char msgout = NOP; 16441da177e4SLinus Torvalds int sink = 0; 16451da177e4SLinus Torvalds int len; 16461da177e4SLinus Torvalds int transfersize; 16471da177e4SLinus Torvalds unsigned char *data; 16481da177e4SLinus Torvalds unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; 164911d2f63bSFinn Thain struct scsi_cmnd *cmd; 16501da177e4SLinus Torvalds 1651e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1652e9db3198SFinn Thain dregs->csr |= CSR_INTR; 1653e9db3198SFinn Thain #endif 1654e9db3198SFinn Thain 165511d2f63bSFinn Thain while ((cmd = hostdata->connected)) { 165632b26a10SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 165732b26a10SFinn Thain 16581da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 16591da177e4SLinus Torvalds /* We only have a valid SCSI phase when REQ is asserted */ 16601da177e4SLinus Torvalds if (tmp & SR_REQ) { 16611da177e4SLinus Torvalds phase = (tmp & PHASE_MASK); 16621da177e4SLinus Torvalds if (phase != old_phase) { 16631da177e4SLinus Torvalds old_phase = phase; 16641da177e4SLinus Torvalds NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); 16651da177e4SLinus Torvalds } 1666e9db3198SFinn Thain #ifdef CONFIG_SUN3 16674a98f896SFinn Thain if (phase == PHASE_CMDOUT && 16684a98f896SFinn Thain sun3_dma_setup_done != cmd) { 16694a98f896SFinn Thain int count; 1670e9db3198SFinn Thain 1671e9db3198SFinn Thain if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { 16724a98f896SFinn Thain ++cmd->SCp.buffer; 16734a98f896SFinn Thain --cmd->SCp.buffers_residual; 16744a98f896SFinn Thain cmd->SCp.this_residual = cmd->SCp.buffer->length; 16754a98f896SFinn Thain cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 1676e9db3198SFinn Thain } 1677e9db3198SFinn Thain 16784a98f896SFinn Thain count = sun3scsi_dma_xfer_len(hostdata, cmd); 16794a98f896SFinn Thain 16804a98f896SFinn Thain if (count > 0) { 16814a98f896SFinn Thain if (rq_data_dir(cmd->request)) 16824a98f896SFinn Thain sun3scsi_dma_send_setup(hostdata, 16834a98f896SFinn Thain cmd->SCp.ptr, count); 16844a98f896SFinn Thain else 16854a98f896SFinn Thain sun3scsi_dma_recv_setup(hostdata, 16864a98f896SFinn Thain cmd->SCp.ptr, count); 1687e9db3198SFinn Thain sun3_dma_setup_done = cmd; 1688e9db3198SFinn Thain } 1689e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1690e9db3198SFinn Thain dregs->csr |= CSR_INTR; 1691e9db3198SFinn Thain #endif 1692e9db3198SFinn Thain } 1693e9db3198SFinn Thain #endif /* CONFIG_SUN3 */ 1694e9db3198SFinn Thain 16951da177e4SLinus Torvalds if (sink && (phase != PHASE_MSGOUT)) { 16961da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 16971da177e4SLinus Torvalds 16983d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 16993d07d22bSFinn Thain ICR_ASSERT_ACK); 17000d2cf867SFinn Thain while (NCR5380_read(STATUS_REG) & SR_REQ) 17010d2cf867SFinn Thain ; 17023d07d22bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 17033d07d22bSFinn Thain ICR_ASSERT_ATN); 17041da177e4SLinus Torvalds sink = 0; 17051da177e4SLinus Torvalds continue; 17061da177e4SLinus Torvalds } 17070d2cf867SFinn Thain 17081da177e4SLinus Torvalds switch (phase) { 17091da177e4SLinus Torvalds case PHASE_DATAOUT: 17101da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_DATAOUT) 17116a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n"); 17121da177e4SLinus Torvalds sink = 1; 17131da177e4SLinus Torvalds do_abort(instance); 17141da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 1715677e0194SFinn Thain complete_cmd(instance, cmd); 1716dc183965SFinn Thain hostdata->connected = NULL; 17171da177e4SLinus Torvalds return; 17181da177e4SLinus Torvalds #endif 1719bf1a0c6fSFinn Thain case PHASE_DATAIN: 17201da177e4SLinus Torvalds /* 17211da177e4SLinus Torvalds * If there is no room left in the current buffer in the 17221da177e4SLinus Torvalds * scatter-gather list, move onto the next one. 17231da177e4SLinus Torvalds */ 17241da177e4SLinus Torvalds 17251da177e4SLinus Torvalds if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { 17261da177e4SLinus Torvalds ++cmd->SCp.buffer; 17271da177e4SLinus Torvalds --cmd->SCp.buffers_residual; 17281da177e4SLinus Torvalds cmd->SCp.this_residual = cmd->SCp.buffer->length; 172945711f1aSJens Axboe cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 1730b746545fSFinn Thain dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n", 1731b746545fSFinn Thain cmd->SCp.this_residual, 1732b746545fSFinn Thain cmd->SCp.buffers_residual); 17331da177e4SLinus Torvalds } 17340d2cf867SFinn Thain 17351da177e4SLinus Torvalds /* 17361da177e4SLinus Torvalds * The preferred transfer method is going to be 17371da177e4SLinus Torvalds * PSEUDO-DMA for systems that are strictly PIO, 17381da177e4SLinus Torvalds * since we can let the hardware do the handshaking. 17391da177e4SLinus Torvalds * 17401da177e4SLinus Torvalds * For this to work, we need to know the transfersize 17411da177e4SLinus Torvalds * ahead of time, since the pseudo-DMA code will sit 17421da177e4SLinus Torvalds * in an unconditional loop. 17431da177e4SLinus Torvalds */ 17441da177e4SLinus Torvalds 1745ff3d4578SFinn Thain transfersize = 0; 17467e9ec8d9SFinn Thain if (!cmd->device->borken) 17474a98f896SFinn Thain transfersize = NCR5380_dma_xfer_len(hostdata, cmd); 17481da177e4SLinus Torvalds 1749438af51cSFinn Thain if (transfersize > 0) { 17501da177e4SLinus Torvalds len = transfersize; 17510d2cf867SFinn Thain if (NCR5380_transfer_dma(instance, &phase, 17520d2cf867SFinn Thain &len, (unsigned char **)&cmd->SCp.ptr)) { 17531da177e4SLinus Torvalds /* 17540d2cf867SFinn Thain * If the watchdog timer fires, all future 17550d2cf867SFinn Thain * accesses to this device will use the 17560d2cf867SFinn Thain * polled-IO. 17571da177e4SLinus Torvalds */ 1758017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 1759017560fcSJeff Garzik "switching to slow handshake\n"); 17601da177e4SLinus Torvalds cmd->device->borken = 1; 17611da177e4SLinus Torvalds sink = 1; 17621da177e4SLinus Torvalds do_abort(instance); 17631da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 17641da177e4SLinus Torvalds /* XXX - need to source or sink data here, as appropriate */ 17658053b0eeSFinn Thain } 1766f825e40bSFinn Thain } else { 176708348b1cSFinn Thain /* Transfer a small chunk so that the 176808348b1cSFinn Thain * irq mode lock is not held too long. 17691678847eSFinn Thain */ 177008348b1cSFinn Thain transfersize = min(cmd->SCp.this_residual, 177108348b1cSFinn Thain NCR5380_PIO_CHUNK_SIZE); 17721678847eSFinn Thain len = transfersize; 17731678847eSFinn Thain NCR5380_transfer_pio(instance, &phase, &len, 17743d07d22bSFinn Thain (unsigned char **)&cmd->SCp.ptr); 17751678847eSFinn Thain cmd->SCp.this_residual -= transfersize - len; 177611d2f63bSFinn Thain } 1777e9db3198SFinn Thain #ifdef CONFIG_SUN3 1778e9db3198SFinn Thain if (sun3_dma_setup_done == cmd) 1779e9db3198SFinn Thain sun3_dma_setup_done = NULL; 1780e9db3198SFinn Thain #endif 17811678847eSFinn Thain return; 17821da177e4SLinus Torvalds case PHASE_MSGIN: 17831da177e4SLinus Torvalds len = 1; 17841da177e4SLinus Torvalds data = &tmp; 17851da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 17861da177e4SLinus Torvalds cmd->SCp.Message = tmp; 17871da177e4SLinus Torvalds 17881da177e4SLinus Torvalds switch (tmp) { 17891da177e4SLinus Torvalds case ABORT: 17901da177e4SLinus Torvalds case COMMAND_COMPLETE: 17911da177e4SLinus Torvalds /* Accept message by clearing ACK */ 17921da177e4SLinus Torvalds sink = 1; 17931da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 17940d3d9a42SFinn Thain dsprintk(NDEBUG_QUEUES, instance, 17950d3d9a42SFinn Thain "COMMAND COMPLETE %p target %d lun %llu\n", 17960d3d9a42SFinn Thain cmd, scmd_id(cmd), cmd->device->lun); 17970d3d9a42SFinn Thain 17981da177e4SLinus Torvalds hostdata->connected = NULL; 17991da177e4SLinus Torvalds 1800f27db8ebSFinn Thain cmd->result &= ~0xffff; 1801f27db8ebSFinn Thain cmd->result |= cmd->SCp.Status; 1802f27db8ebSFinn Thain cmd->result |= cmd->SCp.Message << 8; 18031da177e4SLinus Torvalds 1804f27db8ebSFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 1805f27db8ebSFinn Thain complete_cmd(instance, cmd); 1806f27db8ebSFinn Thain else { 1807f27db8ebSFinn Thain if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION || 1808f27db8ebSFinn Thain cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) { 1809f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n", 1810dbb6b350SFinn Thain cmd); 1811f27db8ebSFinn Thain list_add_tail(&ncmd->list, 1812f27db8ebSFinn Thain &hostdata->autosense); 1813f27db8ebSFinn Thain } else 1814677e0194SFinn Thain complete_cmd(instance, cmd); 18151da177e4SLinus Torvalds } 18161da177e4SLinus Torvalds 18171da177e4SLinus Torvalds /* 18181da177e4SLinus Torvalds * Restore phase bits to 0 so an interrupted selection, 18191da177e4SLinus Torvalds * arbitration can resume. 18201da177e4SLinus Torvalds */ 18211da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 182272064a78SFinn Thain 182372064a78SFinn Thain /* Enable reselect interrupts */ 182472064a78SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 182552d3e561SFinn Thain 182652d3e561SFinn Thain maybe_release_dma_irq(instance); 18271da177e4SLinus Torvalds return; 18281da177e4SLinus Torvalds case MESSAGE_REJECT: 18291da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18301da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18311da177e4SLinus Torvalds switch (hostdata->last_message) { 18321da177e4SLinus Torvalds case HEAD_OF_QUEUE_TAG: 18331da177e4SLinus Torvalds case ORDERED_QUEUE_TAG: 18341da177e4SLinus Torvalds case SIMPLE_QUEUE_TAG: 18351da177e4SLinus Torvalds cmd->device->simple_tags = 0; 18369cb78c16SHannes Reinecke hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF)); 18371da177e4SLinus Torvalds break; 18381da177e4SLinus Torvalds default: 18391da177e4SLinus Torvalds break; 18401da177e4SLinus Torvalds } 1841340b9612SFinn Thain break; 18420d2cf867SFinn Thain case DISCONNECT: 18431da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18441da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18451da177e4SLinus Torvalds hostdata->connected = NULL; 184632b26a10SFinn Thain list_add(&ncmd->list, &hostdata->disconnected); 18470d3d9a42SFinn Thain dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES, 18480d3d9a42SFinn Thain instance, "connected command %p for target %d lun %llu moved to disconnected queue\n", 18490d3d9a42SFinn Thain cmd, scmd_id(cmd), cmd->device->lun); 18500d3d9a42SFinn Thain 18511da177e4SLinus Torvalds /* 18521da177e4SLinus Torvalds * Restore phase bits to 0 so an interrupted selection, 18531da177e4SLinus Torvalds * arbitration can resume. 18541da177e4SLinus Torvalds */ 18551da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 18561da177e4SLinus Torvalds 18571da177e4SLinus Torvalds /* Enable reselect interrupts */ 18581da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1859e9db3198SFinn Thain #ifdef SUN3_SCSI_VME 1860e9db3198SFinn Thain dregs->csr |= CSR_DMA_ENABLE; 1861e9db3198SFinn Thain #endif 18621da177e4SLinus Torvalds return; 18631da177e4SLinus Torvalds /* 18641da177e4SLinus Torvalds * The SCSI data pointer is *IMPLICITLY* saved on a disconnect 18651da177e4SLinus Torvalds * operation, in violation of the SCSI spec so we can safely 18661da177e4SLinus Torvalds * ignore SAVE/RESTORE pointers calls. 18671da177e4SLinus Torvalds * 18681da177e4SLinus Torvalds * Unfortunately, some disks violate the SCSI spec and 18691da177e4SLinus Torvalds * don't issue the required SAVE_POINTERS message before 18701da177e4SLinus Torvalds * disconnecting, and we have to break spec to remain 18711da177e4SLinus Torvalds * compatible. 18721da177e4SLinus Torvalds */ 18731da177e4SLinus Torvalds case SAVE_POINTERS: 18741da177e4SLinus Torvalds case RESTORE_POINTERS: 18751da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18761da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18771da177e4SLinus Torvalds break; 18781da177e4SLinus Torvalds case EXTENDED_MESSAGE: 18791da177e4SLinus Torvalds /* 1880c16df32eSFinn Thain * Start the message buffer with the EXTENDED_MESSAGE 18811abfd370SMatthew Wilcox * byte, since spi_print_msg() wants the whole thing. 18821da177e4SLinus Torvalds */ 18831da177e4SLinus Torvalds extended_msg[0] = EXTENDED_MESSAGE; 18841da177e4SLinus Torvalds /* Accept first byte by clearing ACK */ 18851da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 188611d2f63bSFinn Thain 188711d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 188811d2f63bSFinn Thain 1889b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n"); 18901da177e4SLinus Torvalds 18911da177e4SLinus Torvalds len = 2; 18921da177e4SLinus Torvalds data = extended_msg + 1; 18931da177e4SLinus Torvalds phase = PHASE_MSGIN; 18941da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 1895b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n", 1896b746545fSFinn Thain (int)extended_msg[1], 1897b746545fSFinn Thain (int)extended_msg[2]); 18981da177e4SLinus Torvalds 1899e0783ed3SFinn Thain if (!len && extended_msg[1] > 0 && 1900e0783ed3SFinn Thain extended_msg[1] <= sizeof(extended_msg) - 2) { 19011da177e4SLinus Torvalds /* Accept third byte by clearing ACK */ 19021da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 19031da177e4SLinus Torvalds len = extended_msg[1] - 1; 19041da177e4SLinus Torvalds data = extended_msg + 3; 19051da177e4SLinus Torvalds phase = PHASE_MSGIN; 19061da177e4SLinus Torvalds 19071da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 1908b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n", 1909b746545fSFinn Thain len); 19101da177e4SLinus Torvalds 19111da177e4SLinus Torvalds switch (extended_msg[2]) { 19121da177e4SLinus Torvalds case EXTENDED_SDTR: 19131da177e4SLinus Torvalds case EXTENDED_WDTR: 19141da177e4SLinus Torvalds tmp = 0; 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds } else if (len) { 19176a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "error receiving extended message\n"); 19181da177e4SLinus Torvalds tmp = 0; 19191da177e4SLinus Torvalds } else { 19206a6ff4acSFinn Thain shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n", 19216a6ff4acSFinn Thain extended_msg[2], extended_msg[1]); 19221da177e4SLinus Torvalds tmp = 0; 19231da177e4SLinus Torvalds } 192411d2f63bSFinn Thain 192511d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 192611d2f63bSFinn Thain if (!hostdata->connected) 192711d2f63bSFinn Thain return; 192811d2f63bSFinn Thain 19291da177e4SLinus Torvalds /* Fall through to reject message */ 19301da177e4SLinus Torvalds 19311da177e4SLinus Torvalds /* 19321da177e4SLinus Torvalds * If we get something weird that we aren't expecting, 19331da177e4SLinus Torvalds * reject it. 19341da177e4SLinus Torvalds */ 19351da177e4SLinus Torvalds default: 193639bef87cSFinn Thain if (tmp == EXTENDED_MESSAGE) 1937017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 19380d2cf867SFinn Thain "rejecting unknown extended message code %02x, length %d\n", 193939bef87cSFinn Thain extended_msg[2], extended_msg[1]); 194039bef87cSFinn Thain else if (tmp) 194139bef87cSFinn Thain scmd_printk(KERN_INFO, cmd, 194239bef87cSFinn Thain "rejecting unknown message code %02x\n", 194339bef87cSFinn Thain tmp); 19441da177e4SLinus Torvalds 19451da177e4SLinus Torvalds msgout = MESSAGE_REJECT; 19461da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 19471da177e4SLinus Torvalds break; 19481da177e4SLinus Torvalds } /* switch (tmp) */ 19491da177e4SLinus Torvalds break; 19501da177e4SLinus Torvalds case PHASE_MSGOUT: 19511da177e4SLinus Torvalds len = 1; 19521da177e4SLinus Torvalds data = &msgout; 19531da177e4SLinus Torvalds hostdata->last_message = msgout; 19541da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 19551da177e4SLinus Torvalds if (msgout == ABORT) { 19561da177e4SLinus Torvalds hostdata->connected = NULL; 19571da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 1958677e0194SFinn Thain complete_cmd(instance, cmd); 195952d3e561SFinn Thain maybe_release_dma_irq(instance); 19601da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 19611da177e4SLinus Torvalds return; 19621da177e4SLinus Torvalds } 19631da177e4SLinus Torvalds msgout = NOP; 19641da177e4SLinus Torvalds break; 19651da177e4SLinus Torvalds case PHASE_CMDOUT: 19661da177e4SLinus Torvalds len = cmd->cmd_len; 19671da177e4SLinus Torvalds data = cmd->cmnd; 19681da177e4SLinus Torvalds /* 19691da177e4SLinus Torvalds * XXX for performance reasons, on machines with a 19701da177e4SLinus Torvalds * PSEUDO-DMA architecture we should probably 19711da177e4SLinus Torvalds * use the dma transfer function. 19721da177e4SLinus Torvalds */ 19731da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 19741da177e4SLinus Torvalds break; 19751da177e4SLinus Torvalds case PHASE_STATIN: 19761da177e4SLinus Torvalds len = 1; 19771da177e4SLinus Torvalds data = &tmp; 19781da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 19791da177e4SLinus Torvalds cmd->SCp.Status = tmp; 19801da177e4SLinus Torvalds break; 19811da177e4SLinus Torvalds default: 19826a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "unknown phase\n"); 19834dde8f7dSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 19841da177e4SLinus Torvalds } /* switch(phase) */ 1985686f3990SFinn Thain } else { 198611d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 1987d5d37a0aSFinn Thain NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, HZ); 198811d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 19891da177e4SLinus Torvalds } 199011d2f63bSFinn Thain } 19911da177e4SLinus Torvalds } 19921da177e4SLinus Torvalds 19931da177e4SLinus Torvalds /* 19941da177e4SLinus Torvalds * Function : void NCR5380_reselect (struct Scsi_Host *instance) 19951da177e4SLinus Torvalds * 19961da177e4SLinus Torvalds * Purpose : does reselection, initializing the instance->connected 1997710ddd0dSFinn Thain * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q 19981da177e4SLinus Torvalds * nexus has been reestablished, 19991da177e4SLinus Torvalds * 20001da177e4SLinus Torvalds * Inputs : instance - this instance of the NCR5380. 20011da177e4SLinus Torvalds */ 20021da177e4SLinus Torvalds 20030d2cf867SFinn Thain static void NCR5380_reselect(struct Scsi_Host *instance) 20040d2cf867SFinn Thain { 2005e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 20061da177e4SLinus Torvalds unsigned char target_mask; 2007e9db3198SFinn Thain unsigned char lun; 20081da177e4SLinus Torvalds unsigned char msg[3]; 200932b26a10SFinn Thain struct NCR5380_cmd *ncmd; 201032b26a10SFinn Thain struct scsi_cmnd *tmp; 20111da177e4SLinus Torvalds 20121da177e4SLinus Torvalds /* 20131da177e4SLinus Torvalds * Disable arbitration, etc. since the host adapter obviously 20141da177e4SLinus Torvalds * lost, and tell an interrupted NCR5380_select() to restart. 20151da177e4SLinus Torvalds */ 20161da177e4SLinus Torvalds 20171da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 20181da177e4SLinus Torvalds 20191da177e4SLinus Torvalds target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); 2020b746545fSFinn Thain 2021b746545fSFinn Thain dsprintk(NDEBUG_RESELECTION, instance, "reselect\n"); 20221da177e4SLinus Torvalds 20231da177e4SLinus Torvalds /* 20241da177e4SLinus Torvalds * At this point, we have detected that our SCSI ID is on the bus, 20251da177e4SLinus Torvalds * SEL is true and BSY was false for at least one bus settle delay 20261da177e4SLinus Torvalds * (400 ns). 20271da177e4SLinus Torvalds * 20281da177e4SLinus Torvalds * We must assert BSY ourselves, until the target drops the SEL 20291da177e4SLinus Torvalds * signal. 20301da177e4SLinus Torvalds */ 20311da177e4SLinus Torvalds 20321da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); 2033d5d37a0aSFinn Thain if (NCR5380_poll_politely(hostdata, 203472064a78SFinn Thain STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) { 203572064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 203672064a78SFinn Thain return; 203772064a78SFinn Thain } 20381da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 20391da177e4SLinus Torvalds 20401da177e4SLinus Torvalds /* 20411da177e4SLinus Torvalds * Wait for target to go into MSGIN. 20421da177e4SLinus Torvalds */ 20431da177e4SLinus Torvalds 2044d5d37a0aSFinn Thain if (NCR5380_poll_politely(hostdata, 204572064a78SFinn Thain STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) { 204672064a78SFinn Thain do_abort(instance); 204772064a78SFinn Thain return; 204872064a78SFinn Thain } 20491da177e4SLinus Torvalds 2050e9db3198SFinn Thain #ifdef CONFIG_SUN3 2051e9db3198SFinn Thain /* acknowledge toggle to MSGIN */ 2052e9db3198SFinn Thain NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN)); 2053e9db3198SFinn Thain 2054e9db3198SFinn Thain /* peek at the byte without really hitting the bus */ 2055e9db3198SFinn Thain msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG); 2056e9db3198SFinn Thain #else 2057e9db3198SFinn Thain { 2058e9db3198SFinn Thain int len = 1; 2059e9db3198SFinn Thain unsigned char *data = msg; 2060e9db3198SFinn Thain unsigned char phase = PHASE_MSGIN; 2061e9db3198SFinn Thain 20621da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 20631da177e4SLinus Torvalds 206472064a78SFinn Thain if (len) { 206572064a78SFinn Thain do_abort(instance); 206672064a78SFinn Thain return; 206772064a78SFinn Thain } 2068e9db3198SFinn Thain } 2069e9db3198SFinn Thain #endif /* CONFIG_SUN3 */ 207072064a78SFinn Thain 20711da177e4SLinus Torvalds if (!(msg[0] & 0x80)) { 207272064a78SFinn Thain shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got "); 20731abfd370SMatthew Wilcox spi_print_msg(msg); 207472064a78SFinn Thain printk("\n"); 207572064a78SFinn Thain do_abort(instance); 207672064a78SFinn Thain return; 207772064a78SFinn Thain } 207872064a78SFinn Thain lun = msg[0] & 0x07; 20791da177e4SLinus Torvalds 20801da177e4SLinus Torvalds /* 20811da177e4SLinus Torvalds * We need to add code for SCSI-II to track which devices have 20821da177e4SLinus Torvalds * I_T_L_Q nexuses established, and which have simple I_T_L 20831da177e4SLinus Torvalds * nexuses so we can chose to do additional data transfer. 20841da177e4SLinus Torvalds */ 20851da177e4SLinus Torvalds 20861da177e4SLinus Torvalds /* 20871da177e4SLinus Torvalds * Find the command corresponding to the I_T_L or I_T_L_Q nexus we 20881da177e4SLinus Torvalds * just reestablished, and remove it from the disconnected queue. 20891da177e4SLinus Torvalds */ 20901da177e4SLinus Torvalds 209132b26a10SFinn Thain tmp = NULL; 209232b26a10SFinn Thain list_for_each_entry(ncmd, &hostdata->disconnected, list) { 209332b26a10SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 209432b26a10SFinn Thain 209532b26a10SFinn Thain if (target_mask == (1 << scmd_id(cmd)) && 209632b26a10SFinn Thain lun == (u8)cmd->device->lun) { 209732b26a10SFinn Thain list_del(&ncmd->list); 209832b26a10SFinn Thain tmp = cmd; 20991da177e4SLinus Torvalds break; 21001da177e4SLinus Torvalds } 210172064a78SFinn Thain } 21020d3d9a42SFinn Thain 21030d3d9a42SFinn Thain if (tmp) { 21040d3d9a42SFinn Thain dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance, 21050d3d9a42SFinn Thain "reselect: removed %p from disconnected queue\n", tmp); 21060d3d9a42SFinn Thain } else { 210772064a78SFinn Thain shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n", 210872064a78SFinn Thain target_mask, lun); 21091da177e4SLinus Torvalds /* 21100d2cf867SFinn Thain * Since we have an established nexus that we can't do anything 21110d2cf867SFinn Thain * with, we must abort it. 21121da177e4SLinus Torvalds */ 211372064a78SFinn Thain do_abort(instance); 211472064a78SFinn Thain return; 21151da177e4SLinus Torvalds } 21161da177e4SLinus Torvalds 2117e9db3198SFinn Thain #ifdef CONFIG_SUN3 21184a98f896SFinn Thain if (sun3_dma_setup_done != tmp) { 21194a98f896SFinn Thain int count; 2120e9db3198SFinn Thain 2121e9db3198SFinn Thain if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) { 21224a98f896SFinn Thain ++tmp->SCp.buffer; 21234a98f896SFinn Thain --tmp->SCp.buffers_residual; 21244a98f896SFinn Thain tmp->SCp.this_residual = tmp->SCp.buffer->length; 21254a98f896SFinn Thain tmp->SCp.ptr = sg_virt(tmp->SCp.buffer); 2126e9db3198SFinn Thain } 2127e9db3198SFinn Thain 21284a98f896SFinn Thain count = sun3scsi_dma_xfer_len(hostdata, tmp); 21294a98f896SFinn Thain 21304a98f896SFinn Thain if (count > 0) { 21314a98f896SFinn Thain if (rq_data_dir(tmp->request)) 21324a98f896SFinn Thain sun3scsi_dma_send_setup(hostdata, 21334a98f896SFinn Thain tmp->SCp.ptr, count); 21344a98f896SFinn Thain else 21354a98f896SFinn Thain sun3scsi_dma_recv_setup(hostdata, 21364a98f896SFinn Thain tmp->SCp.ptr, count); 2137e9db3198SFinn Thain sun3_dma_setup_done = tmp; 2138e9db3198SFinn Thain } 2139e9db3198SFinn Thain } 2140e9db3198SFinn Thain 2141e9db3198SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); 2142e9db3198SFinn Thain #endif /* CONFIG_SUN3 */ 2143e9db3198SFinn Thain 214472064a78SFinn Thain /* Accept message by clearing ACK */ 214572064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 214672064a78SFinn Thain 21471da177e4SLinus Torvalds hostdata->connected = tmp; 2148c4ec6f92SFinn Thain dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu\n", 2149c4ec6f92SFinn Thain scmd_id(tmp), tmp->device->lun); 21501da177e4SLinus Torvalds } 21511da177e4SLinus Torvalds 21528b00c3d5SFinn Thain /** 21538b00c3d5SFinn Thain * list_find_cmd - test for presence of a command in a linked list 21548b00c3d5SFinn Thain * @haystack: list of commands 21558b00c3d5SFinn Thain * @needle: command to search for 21568b00c3d5SFinn Thain */ 21578b00c3d5SFinn Thain 21588b00c3d5SFinn Thain static bool list_find_cmd(struct list_head *haystack, 21598b00c3d5SFinn Thain struct scsi_cmnd *needle) 21608b00c3d5SFinn Thain { 21618b00c3d5SFinn Thain struct NCR5380_cmd *ncmd; 21628b00c3d5SFinn Thain 21638b00c3d5SFinn Thain list_for_each_entry(ncmd, haystack, list) 21648b00c3d5SFinn Thain if (NCR5380_to_scmd(ncmd) == needle) 21658b00c3d5SFinn Thain return true; 21668b00c3d5SFinn Thain return false; 21678b00c3d5SFinn Thain } 21688b00c3d5SFinn Thain 21698b00c3d5SFinn Thain /** 21708b00c3d5SFinn Thain * list_remove_cmd - remove a command from linked list 21718b00c3d5SFinn Thain * @haystack: list of commands 21728b00c3d5SFinn Thain * @needle: command to remove 21738b00c3d5SFinn Thain */ 21748b00c3d5SFinn Thain 21758b00c3d5SFinn Thain static bool list_del_cmd(struct list_head *haystack, 21768b00c3d5SFinn Thain struct scsi_cmnd *needle) 21778b00c3d5SFinn Thain { 21788b00c3d5SFinn Thain if (list_find_cmd(haystack, needle)) { 21798b00c3d5SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle); 21808b00c3d5SFinn Thain 21818b00c3d5SFinn Thain list_del(&ncmd->list); 21828b00c3d5SFinn Thain return true; 21838b00c3d5SFinn Thain } 21848b00c3d5SFinn Thain return false; 21858b00c3d5SFinn Thain } 21868b00c3d5SFinn Thain 21878b00c3d5SFinn Thain /** 21888b00c3d5SFinn Thain * NCR5380_abort - scsi host eh_abort_handler() method 21898b00c3d5SFinn Thain * @cmd: the command to be aborted 21901da177e4SLinus Torvalds * 21918b00c3d5SFinn Thain * Try to abort a given command by removing it from queues and/or sending 21928b00c3d5SFinn Thain * the target an abort message. This may not succeed in causing a target 21938b00c3d5SFinn Thain * to abort the command. Nonetheless, the low-level driver must forget about 21948b00c3d5SFinn Thain * the command because the mid-layer reclaims it and it may be re-issued. 21951da177e4SLinus Torvalds * 21968b00c3d5SFinn Thain * The normal path taken by a command is as follows. For EH we trace this 21978b00c3d5SFinn Thain * same path to locate and abort the command. 21981da177e4SLinus Torvalds * 21998b00c3d5SFinn Thain * unissued -> selecting -> [unissued -> selecting ->]... connected -> 22008b00c3d5SFinn Thain * [disconnected -> connected ->]... 22018b00c3d5SFinn Thain * [autosense -> connected ->] done 22021da177e4SLinus Torvalds * 22038b00c3d5SFinn Thain * If cmd was not found at all then presumably it has already been completed, 22048b00c3d5SFinn Thain * in which case return SUCCESS to try to avoid further EH measures. 2205dc183965SFinn Thain * 22068b00c3d5SFinn Thain * If the command has not completed yet, we must not fail to find it. 2207dc183965SFinn Thain * We have no option but to forget the aborted command (even if it still 2208dc183965SFinn Thain * lacks sense data). The mid-layer may re-issue a command that is in error 2209dc183965SFinn Thain * recovery (see scsi_send_eh_cmnd), but the logic and data structures in 2210dc183965SFinn Thain * this driver are such that a command can appear on one queue only. 221171a00593SFinn Thain * 221271a00593SFinn Thain * The lock protects driver data structures, but EH handlers also use it 221371a00593SFinn Thain * to serialize their own execution and prevent their own re-entry. 22141da177e4SLinus Torvalds */ 22151da177e4SLinus Torvalds 2216710ddd0dSFinn Thain static int NCR5380_abort(struct scsi_cmnd *cmd) 2217710ddd0dSFinn Thain { 22181da177e4SLinus Torvalds struct Scsi_Host *instance = cmd->device->host; 2219e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 222011d2f63bSFinn Thain unsigned long flags; 22218b00c3d5SFinn Thain int result = SUCCESS; 22221da177e4SLinus Torvalds 222311d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 222411d2f63bSFinn Thain 222532b26a10SFinn Thain #if (NDEBUG & NDEBUG_ANY) 22268b00c3d5SFinn Thain scmd_printk(KERN_INFO, cmd, __func__); 222732b26a10SFinn Thain #endif 2228e5c3fddfSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 2229e5c3fddfSFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 22301da177e4SLinus Torvalds 22318b00c3d5SFinn Thain if (list_del_cmd(&hostdata->unissued, cmd)) { 22328b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 22338b00c3d5SFinn Thain "abort: removed %p from issue queue\n", cmd); 22348b00c3d5SFinn Thain cmd->result = DID_ABORT << 16; 22358b00c3d5SFinn Thain cmd->scsi_done(cmd); /* No tag or busy flag to worry about */ 2236dc183965SFinn Thain goto out; 22378b00c3d5SFinn Thain } 22388b00c3d5SFinn Thain 2239707d62b3SFinn Thain if (hostdata->selecting == cmd) { 2240707d62b3SFinn Thain dsprintk(NDEBUG_ABORT, instance, 2241707d62b3SFinn Thain "abort: cmd %p == selecting\n", cmd); 2242707d62b3SFinn Thain hostdata->selecting = NULL; 2243707d62b3SFinn Thain cmd->result = DID_ABORT << 16; 2244707d62b3SFinn Thain complete_cmd(instance, cmd); 2245707d62b3SFinn Thain goto out; 2246707d62b3SFinn Thain } 2247707d62b3SFinn Thain 22488b00c3d5SFinn Thain if (list_del_cmd(&hostdata->disconnected, cmd)) { 22498b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 22508b00c3d5SFinn Thain "abort: removed %p from disconnected list\n", cmd); 225171a00593SFinn Thain /* Can't call NCR5380_select() and send ABORT because that 225271a00593SFinn Thain * means releasing the lock. Need a bus reset. 225371a00593SFinn Thain */ 2254dc183965SFinn Thain set_host_byte(cmd, DID_ERROR); 2255dc183965SFinn Thain complete_cmd(instance, cmd); 22568b00c3d5SFinn Thain result = FAILED; 22578b00c3d5SFinn Thain goto out; 22588b00c3d5SFinn Thain } 22598b00c3d5SFinn Thain 22608b00c3d5SFinn Thain if (hostdata->connected == cmd) { 22618b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); 22628b00c3d5SFinn Thain hostdata->connected = NULL; 2263dc183965SFinn Thain hostdata->dma_len = 0; 22648b00c3d5SFinn Thain if (do_abort(instance)) { 22658b00c3d5SFinn Thain set_host_byte(cmd, DID_ERROR); 22668b00c3d5SFinn Thain complete_cmd(instance, cmd); 22678b00c3d5SFinn Thain result = FAILED; 22688b00c3d5SFinn Thain goto out; 22698b00c3d5SFinn Thain } 22708b00c3d5SFinn Thain set_host_byte(cmd, DID_ABORT); 22718b00c3d5SFinn Thain complete_cmd(instance, cmd); 2272dc183965SFinn Thain goto out; 22738b00c3d5SFinn Thain } 22748b00c3d5SFinn Thain 22758b00c3d5SFinn Thain if (list_del_cmd(&hostdata->autosense, cmd)) { 22768b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 22778b00c3d5SFinn Thain "abort: removed %p from sense queue\n", cmd); 22788b00c3d5SFinn Thain set_host_byte(cmd, DID_ERROR); 22798b00c3d5SFinn Thain complete_cmd(instance, cmd); 22808b00c3d5SFinn Thain } 22818b00c3d5SFinn Thain 22828b00c3d5SFinn Thain out: 22838b00c3d5SFinn Thain if (result == FAILED) 22848b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd); 22858b00c3d5SFinn Thain else 22868b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd); 22878b00c3d5SFinn Thain 22888b00c3d5SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 228952d3e561SFinn Thain maybe_release_dma_irq(instance); 229011d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 22911da177e4SLinus Torvalds 22928b00c3d5SFinn Thain return result; 22931da177e4SLinus Torvalds } 22941da177e4SLinus Torvalds 22951da177e4SLinus Torvalds 22963be1b3eaSFinn Thain /** 229712e5fc66SHannes Reinecke * NCR5380_host_reset - reset the SCSI host 22983be1b3eaSFinn Thain * @cmd: SCSI command undergoing EH 22991da177e4SLinus Torvalds * 23003be1b3eaSFinn Thain * Returns SUCCESS 23011da177e4SLinus Torvalds */ 23021da177e4SLinus Torvalds 230312e5fc66SHannes Reinecke static int NCR5380_host_reset(struct scsi_cmnd *cmd) 230468b3aa7cSJeff Garzik { 230568b3aa7cSJeff Garzik struct Scsi_Host *instance = cmd->device->host; 230611d2f63bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 230762717f53SFinn Thain int i; 230811d2f63bSFinn Thain unsigned long flags; 230962717f53SFinn Thain struct NCR5380_cmd *ncmd; 23101da177e4SLinus Torvalds 231111d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 23123be1b3eaSFinn Thain 23133be1b3eaSFinn Thain #if (NDEBUG & NDEBUG_ANY) 23141aeeeed7SHannes Reinecke shost_printk(KERN_INFO, instance, __func__); 23153be1b3eaSFinn Thain #endif 2316e5c3fddfSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 2317e5c3fddfSFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 23183be1b3eaSFinn Thain 231968b3aa7cSJeff Garzik do_reset(instance); 23203be1b3eaSFinn Thain 232162717f53SFinn Thain /* reset NCR registers */ 232262717f53SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 232362717f53SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 0); 232462717f53SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 232562717f53SFinn Thain 232662717f53SFinn Thain /* After the reset, there are no more connected or disconnected commands 232762717f53SFinn Thain * and no busy units; so clear the low-level status here to avoid 232862717f53SFinn Thain * conflicts when the mid-level code tries to wake up the affected 232962717f53SFinn Thain * commands! 233062717f53SFinn Thain */ 233162717f53SFinn Thain 23321aeeeed7SHannes Reinecke list_for_each_entry(ncmd, &hostdata->unissued, list) { 23331aeeeed7SHannes Reinecke struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 23341aeeeed7SHannes Reinecke 23351884c283SFinn Thain cmd->result = DID_RESET << 16; 23361884c283SFinn Thain cmd->scsi_done(cmd); 23371884c283SFinn Thain } 23381aeeeed7SHannes Reinecke INIT_LIST_HEAD(&hostdata->unissued); 23391884c283SFinn 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 235762717f53SFinn Thain set_host_byte(cmd, DID_RESET); 235862717f53SFinn Thain cmd->scsi_done(cmd); 235962717f53SFinn Thain } 23601884c283SFinn Thain INIT_LIST_HEAD(&hostdata->autosense); 236162717f53SFinn Thain 236262717f53SFinn Thain if (hostdata->connected) { 236362717f53SFinn Thain set_host_byte(hostdata->connected, DID_RESET); 236462717f53SFinn Thain complete_cmd(instance, hostdata->connected); 236562717f53SFinn Thain hostdata->connected = NULL; 236662717f53SFinn Thain } 236762717f53SFinn Thain 236862717f53SFinn Thain for (i = 0; i < 8; ++i) 236962717f53SFinn Thain hostdata->busy[i] = 0; 237062717f53SFinn Thain hostdata->dma_len = 0; 237162717f53SFinn Thain 237262717f53SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 237352d3e561SFinn Thain maybe_release_dma_irq(instance); 237411d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 237568b3aa7cSJeff Garzik 23761da177e4SLinus Torvalds return SUCCESS; 23771da177e4SLinus Torvalds } 2378