11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * NCR 5380 generic driver routines. These should make it *trivial* 31da177e4SLinus Torvalds * to implement 5380 SCSI drivers under Linux with a non-trantor 41da177e4SLinus Torvalds * architecture. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Note that these routines also work with NR53c400 family chips. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Copyright 1993, Drew Eckhardt 91da177e4SLinus Torvalds * Visionary Computing 101da177e4SLinus Torvalds * (Unix and Linux consulting and custom programming) 111da177e4SLinus Torvalds * drew@colorado.edu 121da177e4SLinus Torvalds * +1 (303) 666-5836 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * For more information, please consult 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * NCR 5380 Family 171da177e4SLinus Torvalds * SCSI Protocol Controller 181da177e4SLinus Torvalds * Databook 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * NCR Microelectronics 211da177e4SLinus Torvalds * 1635 Aeroplaza Drive 221da177e4SLinus Torvalds * Colorado Springs, CO 80916 231da177e4SLinus Torvalds * 1+ (719) 578-3400 241da177e4SLinus Torvalds * 1+ (800) 334-5454 251da177e4SLinus Torvalds */ 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* 28*c16df32eSFinn Thain * With contributions from Ray Van Tassle, Ingmar Baumgart, 29*c16df32eSFinn Thain * Ronald van Cuijlenborg, Alan Cox and others. 301da177e4SLinus Torvalds */ 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds /* 331da177e4SLinus Torvalds * Further development / testing that should be done : 341da177e4SLinus Torvalds * 1. Cleanup the NCR5380_transfer_dma function and DMA operation complete 351da177e4SLinus Torvalds * code so that everything does the same thing that's done at the 361da177e4SLinus Torvalds * end of a pseudo-DMA read operation. 371da177e4SLinus Torvalds * 381da177e4SLinus Torvalds * 2. Fix REAL_DMA (interrupt driven, polled works fine) - 391da177e4SLinus Torvalds * basically, transfer size needs to be reduced by one 401da177e4SLinus Torvalds * and the last byte read as is done with PSEUDO_DMA. 411da177e4SLinus Torvalds * 421da177e4SLinus Torvalds * 4. Test SCSI-II tagged queueing (I have no devices which support 431da177e4SLinus Torvalds * tagged queueing) 441da177e4SLinus Torvalds */ 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds #ifndef notyet 471da177e4SLinus Torvalds #undef REAL_DMA 481da177e4SLinus Torvalds #endif 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds #ifdef BOARD_REQUIRES_NO_DELAY 511da177e4SLinus Torvalds #define io_recovery_delay(x) 521da177e4SLinus Torvalds #else 531da177e4SLinus Torvalds #define io_recovery_delay(x) udelay(x) 541da177e4SLinus Torvalds #endif 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* 571da177e4SLinus Torvalds * Design 581da177e4SLinus Torvalds * 591da177e4SLinus Torvalds * This is a generic 5380 driver. To use it on a different platform, 601da177e4SLinus Torvalds * one simply writes appropriate system specific macros (ie, data 611da177e4SLinus Torvalds * transfer - some PC's will use the I/O bus, 68K's must use 621da177e4SLinus Torvalds * memory mapped) and drops this file in their 'C' wrapper. 631da177e4SLinus Torvalds * 641da177e4SLinus Torvalds * As far as command queueing, two queues are maintained for 651da177e4SLinus Torvalds * each 5380 in the system - commands that haven't been issued yet, 661da177e4SLinus Torvalds * and commands that are currently executing. This means that an 671da177e4SLinus Torvalds * unlimited number of commands may be queued, letting 681da177e4SLinus Torvalds * more commands propagate from the higher driver levels giving higher 691da177e4SLinus Torvalds * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, 701da177e4SLinus Torvalds * allowing multiple commands to propagate all the way to a SCSI-II device 711da177e4SLinus Torvalds * while a command is already executing. 721da177e4SLinus Torvalds * 731da177e4SLinus Torvalds * 741da177e4SLinus Torvalds * Issues specific to the NCR5380 : 751da177e4SLinus Torvalds * 761da177e4SLinus Torvalds * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 771da177e4SLinus Torvalds * piece of hardware that requires you to sit in a loop polling for 781da177e4SLinus Torvalds * the REQ signal as long as you are connected. Some devices are 791da177e4SLinus Torvalds * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 80686f3990SFinn Thain * while doing long seek operations. [...] These 811da177e4SLinus Torvalds * broken devices are the exception rather than the rule and I'd rather 821da177e4SLinus Torvalds * spend my time optimizing for the normal case. 831da177e4SLinus Torvalds * 841da177e4SLinus Torvalds * Architecture : 851da177e4SLinus Torvalds * 861da177e4SLinus Torvalds * At the heart of the design is a coroutine, NCR5380_main, 871da177e4SLinus Torvalds * which is started from a workqueue for each NCR5380 host in the 881da177e4SLinus Torvalds * system. It attempts to establish I_T_L or I_T_L_Q nexuses by 891da177e4SLinus Torvalds * removing the commands from the issue queue and calling 901da177e4SLinus Torvalds * NCR5380_select() if a nexus is not established. 911da177e4SLinus Torvalds * 921da177e4SLinus Torvalds * Once a nexus is established, the NCR5380_information_transfer() 931da177e4SLinus Torvalds * phase goes through the various phases as instructed by the target. 941da177e4SLinus Torvalds * if the target goes into MSG IN and sends a DISCONNECT message, 951da177e4SLinus Torvalds * the command structure is placed into the per instance disconnected 961da177e4SLinus Torvalds * queue, and NCR5380_main tries to find more work. If the target is 971da177e4SLinus Torvalds * idle for too long, the system will try to sleep. 981da177e4SLinus Torvalds * 991da177e4SLinus Torvalds * If a command has disconnected, eventually an interrupt will trigger, 1001da177e4SLinus Torvalds * calling NCR5380_intr() which will in turn call NCR5380_reselect 1011da177e4SLinus Torvalds * to reestablish a nexus. This will run main if necessary. 1021da177e4SLinus Torvalds * 1031da177e4SLinus Torvalds * On command termination, the done function will be called as 1041da177e4SLinus Torvalds * appropriate. 1051da177e4SLinus Torvalds * 1061da177e4SLinus Torvalds * SCSI pointers are maintained in the SCp field of SCSI command 1071da177e4SLinus Torvalds * structures, being initialized after the command is connected 1081da177e4SLinus Torvalds * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. 1091da177e4SLinus Torvalds * Note that in violation of the standard, an implicit SAVE POINTERS operation 1101da177e4SLinus Torvalds * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS. 1111da177e4SLinus Torvalds */ 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds /* 1141da177e4SLinus Torvalds * Using this file : 1151da177e4SLinus Torvalds * This file a skeleton Linux SCSI driver for the NCR 5380 series 1161da177e4SLinus Torvalds * of chips. To use it, you write an architecture specific functions 1171da177e4SLinus Torvalds * and macros and include this file in your driver. 1181da177e4SLinus Torvalds * 1191da177e4SLinus Torvalds * These macros control options : 1201da177e4SLinus Torvalds * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be 1211da177e4SLinus Torvalds * defined. 1221da177e4SLinus Torvalds * 1231da177e4SLinus Torvalds * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically 1241da177e4SLinus Torvalds * for commands that return with a CHECK CONDITION status. 1251da177e4SLinus Torvalds * 1261da177e4SLinus Torvalds * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential 1271da177e4SLinus Torvalds * transceivers. 1281da177e4SLinus Torvalds * 1291da177e4SLinus Torvalds * DONT_USE_INTR - if defined, never use interrupts, even if we probe or 1301da177e4SLinus Torvalds * override-configure an IRQ. 1311da177e4SLinus Torvalds * 1321da177e4SLinus Torvalds * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases. 1331da177e4SLinus Torvalds * 1341da177e4SLinus Torvalds * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. 1351da177e4SLinus Torvalds * 1361da177e4SLinus Torvalds * REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't 1371da177e4SLinus Torvalds * rely on phase mismatch and EOP interrupts to determine end 1381da177e4SLinus Torvalds * of phase. 1391da177e4SLinus Torvalds * 1401da177e4SLinus Torvalds * These macros MUST be defined : 1411da177e4SLinus Torvalds * 1421da177e4SLinus Torvalds * NCR5380_read(register) - read from the specified register 1431da177e4SLinus Torvalds * 1441da177e4SLinus Torvalds * NCR5380_write(register, value) - write to the specific register 1451da177e4SLinus Torvalds * 1461da177e4SLinus Torvalds * NCR5380_implementation_fields - additional fields needed for this 1471da177e4SLinus Torvalds * specific implementation of the NCR5380 1481da177e4SLinus Torvalds * 1491da177e4SLinus Torvalds * Either real DMA *or* pseudo DMA may be implemented 1501da177e4SLinus Torvalds * REAL functions : 1511da177e4SLinus Torvalds * NCR5380_REAL_DMA should be defined if real DMA is to be used. 1521da177e4SLinus Torvalds * Note that the DMA setup functions should return the number of bytes 1531da177e4SLinus Torvalds * that they were able to program the controller for. 1541da177e4SLinus Torvalds * 1551da177e4SLinus Torvalds * Also note that generic i386/PC versions of these macros are 1561da177e4SLinus Torvalds * available as NCR5380_i386_dma_write_setup, 1571da177e4SLinus Torvalds * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. 1581da177e4SLinus Torvalds * 1591da177e4SLinus Torvalds * NCR5380_dma_write_setup(instance, src, count) - initialize 1601da177e4SLinus Torvalds * NCR5380_dma_read_setup(instance, dst, count) - initialize 1611da177e4SLinus Torvalds * NCR5380_dma_residual(instance); - residual count 1621da177e4SLinus Torvalds * 1631da177e4SLinus Torvalds * PSEUDO functions : 1641da177e4SLinus Torvalds * NCR5380_pwrite(instance, src, count) 1651da177e4SLinus Torvalds * NCR5380_pread(instance, dst, count); 1661da177e4SLinus Torvalds * 1671da177e4SLinus Torvalds * The generic driver is initialized by calling NCR5380_init(instance), 1681da177e4SLinus Torvalds * after setting the appropriate host specific fields and ID. If the 1691da177e4SLinus Torvalds * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, 1701da177e4SLinus Torvalds * possible) function may be used. 1711da177e4SLinus Torvalds */ 1721da177e4SLinus Torvalds 17354d8fe44SFinn Thain static int do_abort(struct Scsi_Host *); 17454d8fe44SFinn Thain static void do_reset(struct Scsi_Host *); 1751da177e4SLinus Torvalds 176*c16df32eSFinn Thain /** 1771da177e4SLinus Torvalds * initialize_SCp - init the scsi pointer field 1781da177e4SLinus Torvalds * @cmd: command block to set up 1791da177e4SLinus Torvalds * 1801da177e4SLinus Torvalds * Set up the internal fields in the SCSI command. 1811da177e4SLinus Torvalds */ 1821da177e4SLinus Torvalds 183710ddd0dSFinn Thain static inline void initialize_SCp(struct scsi_cmnd *cmd) 1841da177e4SLinus Torvalds { 1851da177e4SLinus Torvalds /* 1861da177e4SLinus Torvalds * Initialize the Scsi Pointer field so that all of the commands in the 1871da177e4SLinus Torvalds * various queues are valid. 1881da177e4SLinus Torvalds */ 1891da177e4SLinus Torvalds 1909e0fe44dSBoaz Harrosh if (scsi_bufflen(cmd)) { 1919e0fe44dSBoaz Harrosh cmd->SCp.buffer = scsi_sglist(cmd); 1929e0fe44dSBoaz Harrosh cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; 19345711f1aSJens Axboe cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 1941da177e4SLinus Torvalds cmd->SCp.this_residual = cmd->SCp.buffer->length; 1951da177e4SLinus Torvalds } else { 1961da177e4SLinus Torvalds cmd->SCp.buffer = NULL; 1971da177e4SLinus Torvalds cmd->SCp.buffers_residual = 0; 1989e0fe44dSBoaz Harrosh cmd->SCp.ptr = NULL; 1999e0fe44dSBoaz Harrosh cmd->SCp.this_residual = 0; 2001da177e4SLinus Torvalds } 201f27db8ebSFinn Thain 202f27db8ebSFinn Thain cmd->SCp.Status = 0; 203f27db8ebSFinn Thain cmd->SCp.Message = 0; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds /** 207b32ade12SFinn Thain * NCR5380_poll_politely2 - wait for two chip register values 2081da177e4SLinus Torvalds * @instance: controller to poll 209b32ade12SFinn Thain * @reg1: 5380 register to poll 210b32ade12SFinn Thain * @bit1: Bitmask to check 211b32ade12SFinn Thain * @val1: Expected value 212b32ade12SFinn Thain * @reg2: Second 5380 register to poll 213b32ade12SFinn Thain * @bit2: Second bitmask to check 214b32ade12SFinn Thain * @val2: Second expected value 2152f854b82SFinn Thain * @wait: Time-out in jiffies 2161da177e4SLinus Torvalds * 2172f854b82SFinn Thain * Polls the chip in a reasonably efficient manner waiting for an 2182f854b82SFinn Thain * event to occur. After a short quick poll we begin to yield the CPU 2192f854b82SFinn Thain * (if possible). In irq contexts the time-out is arbitrarily limited. 2202f854b82SFinn Thain * Callers may hold locks as long as they are held in irq mode. 2211da177e4SLinus Torvalds * 222b32ade12SFinn Thain * Returns 0 if either or both event(s) occurred otherwise -ETIMEDOUT. 2231da177e4SLinus Torvalds */ 2241da177e4SLinus Torvalds 225b32ade12SFinn Thain static int NCR5380_poll_politely2(struct Scsi_Host *instance, 226b32ade12SFinn Thain int reg1, int bit1, int val1, 227b32ade12SFinn Thain int reg2, int bit2, int val2, int wait) 2281da177e4SLinus Torvalds { 2292f854b82SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 2302f854b82SFinn Thain unsigned long deadline = jiffies + wait; 2312f854b82SFinn Thain unsigned long n; 2321da177e4SLinus Torvalds 2332f854b82SFinn Thain /* Busy-wait for up to 10 ms */ 2342f854b82SFinn Thain n = min(10000U, jiffies_to_usecs(wait)); 2352f854b82SFinn Thain n *= hostdata->accesses_per_ms; 236b32ade12SFinn Thain n /= 2000; 2372f854b82SFinn Thain do { 238b32ade12SFinn Thain if ((NCR5380_read(reg1) & bit1) == val1) 239b32ade12SFinn Thain return 0; 240b32ade12SFinn Thain if ((NCR5380_read(reg2) & bit2) == val2) 2411da177e4SLinus Torvalds return 0; 2421da177e4SLinus Torvalds cpu_relax(); 2432f854b82SFinn Thain } while (n--); 2442f854b82SFinn Thain 2452f854b82SFinn Thain if (irqs_disabled() || in_interrupt()) 2462f854b82SFinn Thain return -ETIMEDOUT; 2472f854b82SFinn Thain 2482f854b82SFinn Thain /* Repeatedly sleep for 1 ms until deadline */ 2492f854b82SFinn Thain while (time_is_after_jiffies(deadline)) { 2502f854b82SFinn Thain schedule_timeout_uninterruptible(1); 251b32ade12SFinn Thain if ((NCR5380_read(reg1) & bit1) == val1) 252b32ade12SFinn Thain return 0; 253b32ade12SFinn Thain if ((NCR5380_read(reg2) & bit2) == val2) 2542f854b82SFinn Thain return 0; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds return -ETIMEDOUT; 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 260b32ade12SFinn Thain static inline int NCR5380_poll_politely(struct Scsi_Host *instance, 261b32ade12SFinn Thain int reg, int bit, int val, int wait) 262b32ade12SFinn Thain { 263b32ade12SFinn Thain return NCR5380_poll_politely2(instance, reg, bit, val, 264b32ade12SFinn Thain reg, bit, val, wait); 265b32ade12SFinn Thain } 266b32ade12SFinn Thain 2671da177e4SLinus Torvalds static struct { 2681da177e4SLinus Torvalds unsigned char value; 2691da177e4SLinus Torvalds const char *name; 270702809ceSAndrew Morton } phases[] __maybe_unused = { 2711da177e4SLinus Torvalds {PHASE_DATAOUT, "DATAOUT"}, 2721da177e4SLinus Torvalds {PHASE_DATAIN, "DATAIN"}, 2731da177e4SLinus Torvalds {PHASE_CMDOUT, "CMDOUT"}, 2741da177e4SLinus Torvalds {PHASE_STATIN, "STATIN"}, 2751da177e4SLinus Torvalds {PHASE_MSGOUT, "MSGOUT"}, 2761da177e4SLinus Torvalds {PHASE_MSGIN, "MSGIN"}, 2771da177e4SLinus Torvalds {PHASE_UNKNOWN, "UNKNOWN"} 2781da177e4SLinus Torvalds }; 2791da177e4SLinus Torvalds 280185a7a1cSviro@ZenIV.linux.org.uk #if NDEBUG 2811da177e4SLinus Torvalds static struct { 2821da177e4SLinus Torvalds unsigned char mask; 2831da177e4SLinus Torvalds const char *name; 2841da177e4SLinus Torvalds } signals[] = { 2851da177e4SLinus Torvalds {SR_DBP, "PARITY"}, 2861da177e4SLinus Torvalds {SR_RST, "RST"}, 2871da177e4SLinus Torvalds {SR_BSY, "BSY"}, 2881da177e4SLinus Torvalds {SR_REQ, "REQ"}, 2891da177e4SLinus Torvalds {SR_MSG, "MSG"}, 2901da177e4SLinus Torvalds {SR_CD, "CD"}, 2911da177e4SLinus Torvalds {SR_IO, "IO"}, 2921da177e4SLinus Torvalds {SR_SEL, "SEL"}, 2931da177e4SLinus Torvalds {0, NULL} 2941da177e4SLinus Torvalds }, 2951da177e4SLinus Torvalds basrs[] = { 2961da177e4SLinus Torvalds {BASR_ATN, "ATN"}, 2971da177e4SLinus Torvalds {BASR_ACK, "ACK"}, 2981da177e4SLinus Torvalds {0, NULL} 2991da177e4SLinus Torvalds }, 3001da177e4SLinus Torvalds icrs[] = { 3011da177e4SLinus Torvalds {ICR_ASSERT_RST, "ASSERT RST"}, 3021da177e4SLinus Torvalds {ICR_ASSERT_ACK, "ASSERT ACK"}, 3031da177e4SLinus Torvalds {ICR_ASSERT_BSY, "ASSERT BSY"}, 3041da177e4SLinus Torvalds {ICR_ASSERT_SEL, "ASSERT SEL"}, 3051da177e4SLinus Torvalds {ICR_ASSERT_ATN, "ASSERT ATN"}, 3061da177e4SLinus Torvalds {ICR_ASSERT_DATA, "ASSERT DATA"}, 3071da177e4SLinus Torvalds {0, NULL} 3081da177e4SLinus Torvalds }, 3091da177e4SLinus Torvalds mrs[] = { 3101da177e4SLinus Torvalds {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, 3111da177e4SLinus Torvalds {MR_TARGET, "MODE TARGET"}, 3121da177e4SLinus Torvalds {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, 3131da177e4SLinus Torvalds {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, 3141da177e4SLinus Torvalds {MR_MONITOR_BSY, "MODE MONITOR BSY"}, 3151da177e4SLinus Torvalds {MR_DMA_MODE, "MODE DMA"}, 3161da177e4SLinus Torvalds {MR_ARBITRATE, "MODE ARBITRATION"}, 3171da177e4SLinus Torvalds {0, NULL} 3181da177e4SLinus Torvalds }; 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds /** 3211da177e4SLinus Torvalds * NCR5380_print - print scsi bus signals 3221da177e4SLinus Torvalds * @instance: adapter state to dump 3231da177e4SLinus Torvalds * 3241da177e4SLinus Torvalds * Print the SCSI bus signals for debugging purposes 3251da177e4SLinus Torvalds */ 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds static void NCR5380_print(struct Scsi_Host *instance) 3281da177e4SLinus Torvalds { 3291da177e4SLinus Torvalds unsigned char status, data, basr, mr, icr, i; 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds data = NCR5380_read(CURRENT_SCSI_DATA_REG); 3321da177e4SLinus Torvalds status = NCR5380_read(STATUS_REG); 3331da177e4SLinus Torvalds mr = NCR5380_read(MODE_REG); 3341da177e4SLinus Torvalds icr = NCR5380_read(INITIATOR_COMMAND_REG); 3351da177e4SLinus Torvalds basr = NCR5380_read(BUS_AND_STATUS_REG); 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds printk("STATUS_REG: %02x ", status); 3381da177e4SLinus Torvalds for (i = 0; signals[i].mask; ++i) 3391da177e4SLinus Torvalds if (status & signals[i].mask) 3401da177e4SLinus Torvalds printk(",%s", signals[i].name); 3411da177e4SLinus Torvalds printk("\nBASR: %02x ", basr); 3421da177e4SLinus Torvalds for (i = 0; basrs[i].mask; ++i) 3431da177e4SLinus Torvalds if (basr & basrs[i].mask) 3441da177e4SLinus Torvalds printk(",%s", basrs[i].name); 3451da177e4SLinus Torvalds printk("\nICR: %02x ", icr); 3461da177e4SLinus Torvalds for (i = 0; icrs[i].mask; ++i) 3471da177e4SLinus Torvalds if (icr & icrs[i].mask) 3481da177e4SLinus Torvalds printk(",%s", icrs[i].name); 3491da177e4SLinus Torvalds printk("\nMODE: %02x ", mr); 3501da177e4SLinus Torvalds for (i = 0; mrs[i].mask; ++i) 3511da177e4SLinus Torvalds if (mr & mrs[i].mask) 3521da177e4SLinus Torvalds printk(",%s", mrs[i].name); 3531da177e4SLinus Torvalds printk("\n"); 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds 357*c16df32eSFinn Thain /** 3581da177e4SLinus Torvalds * NCR5380_print_phase - show SCSI phase 3591da177e4SLinus Torvalds * @instance: adapter to dump 3601da177e4SLinus Torvalds * 3611da177e4SLinus Torvalds * Print the current SCSI phase for debugging purposes 3621da177e4SLinus Torvalds */ 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds static void NCR5380_print_phase(struct Scsi_Host *instance) 3651da177e4SLinus Torvalds { 3661da177e4SLinus Torvalds unsigned char status; 3671da177e4SLinus Torvalds int i; 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds status = NCR5380_read(STATUS_REG); 3701da177e4SLinus Torvalds if (!(status & SR_REQ)) 3716a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "REQ not asserted, phase unknown.\n"); 3721da177e4SLinus Torvalds else { 3731da177e4SLinus Torvalds for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); 3746a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "phase %s\n", phases[i].name); 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds #endif 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds 380d5f7e65dSFinn Thain static int probe_irq __initdata; 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds /** 3831da177e4SLinus Torvalds * probe_intr - helper for IRQ autoprobe 3841da177e4SLinus Torvalds * @irq: interrupt number 3851da177e4SLinus Torvalds * @dev_id: unused 3861da177e4SLinus Torvalds * @regs: unused 3871da177e4SLinus Torvalds * 3881da177e4SLinus Torvalds * Set a flag to indicate the IRQ in question was received. This is 3891da177e4SLinus Torvalds * used by the IRQ probe code. 3901da177e4SLinus Torvalds */ 3911da177e4SLinus Torvalds 3927d12e780SDavid Howells static irqreturn_t __init probe_intr(int irq, void *dev_id) 3931da177e4SLinus Torvalds { 3941da177e4SLinus Torvalds probe_irq = irq; 3951da177e4SLinus Torvalds return IRQ_HANDLED; 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds /** 3991da177e4SLinus Torvalds * NCR5380_probe_irq - find the IRQ of an NCR5380 4001da177e4SLinus Torvalds * @instance: NCR5380 controller 4011da177e4SLinus Torvalds * @possible: bitmask of ISA IRQ lines 4021da177e4SLinus Torvalds * 4031da177e4SLinus Torvalds * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ 4041da177e4SLinus Torvalds * and then looking to see what interrupt actually turned up. 4051da177e4SLinus Torvalds */ 4061da177e4SLinus Torvalds 407702809ceSAndrew Morton static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance, 408702809ceSAndrew Morton int possible) 4091da177e4SLinus Torvalds { 410e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 4111da177e4SLinus Torvalds unsigned long timeout; 4121da177e4SLinus Torvalds int trying_irqs, i, mask; 4131da177e4SLinus Torvalds 41422f5f10dSFinn Thain for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1) 4154909cc2bSMichael Opdenacker if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0)) 4161da177e4SLinus Torvalds trying_irqs |= mask; 4171da177e4SLinus Torvalds 4184e5a800cSNicholas Mc Guire timeout = jiffies + msecs_to_jiffies(250); 41922f5f10dSFinn Thain probe_irq = NO_IRQ; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds /* 4221da177e4SLinus Torvalds * A interrupt is triggered whenever BSY = false, SEL = true 4231da177e4SLinus Torvalds * and a bit set in the SELECT_ENABLE_REG is asserted on the 4241da177e4SLinus Torvalds * SCSI bus. 4251da177e4SLinus Torvalds * 4261da177e4SLinus Torvalds * Note that the bus is only driven when the phase control signals 4271da177e4SLinus Torvalds * (I/O, C/D, and MSG) match those in the TCR, so we must reset that 4281da177e4SLinus Torvalds * to zero. 4291da177e4SLinus Torvalds */ 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 4321da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 4331da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); 4341da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); 4351da177e4SLinus Torvalds 43622f5f10dSFinn Thain while (probe_irq == NO_IRQ && time_before(jiffies, timeout)) 437a9a3047dSNishanth Aravamudan schedule_timeout_uninterruptible(1); 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 4401da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 4411da177e4SLinus Torvalds 44222f5f10dSFinn Thain for (i = 1, mask = 2; i < 16; ++i, mask <<= 1) 4431da177e4SLinus Torvalds if (trying_irqs & mask) 4441da177e4SLinus Torvalds free_irq(i, NULL); 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds return probe_irq; 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds /** 4508c32513bSFinn Thain * NCR58380_info - report driver and host information 4518c32513bSFinn Thain * @instance: relevant scsi host instance 4521da177e4SLinus Torvalds * 4538c32513bSFinn Thain * For use as the host template info() handler. 4541da177e4SLinus Torvalds */ 4551da177e4SLinus Torvalds 4568c32513bSFinn Thain static const char *NCR5380_info(struct Scsi_Host *instance) 4571da177e4SLinus Torvalds { 4588c32513bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 4598c32513bSFinn Thain 4608c32513bSFinn Thain return hostdata->info; 4618c32513bSFinn Thain } 4628c32513bSFinn Thain 4638c32513bSFinn Thain static void prepare_info(struct Scsi_Host *instance) 4648c32513bSFinn Thain { 4658c32513bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 4668c32513bSFinn Thain 4678c32513bSFinn Thain snprintf(hostdata->info, sizeof(hostdata->info), 4688c32513bSFinn Thain "%s, io_port 0x%lx, n_io_port %d, " 4698c32513bSFinn Thain "base 0x%lx, irq %d, " 4708c32513bSFinn Thain "can_queue %d, cmd_per_lun %d, " 4718c32513bSFinn Thain "sg_tablesize %d, this_id %d, " 472be3f4121SFinn Thain "flags { %s%s%s}, " 4738c32513bSFinn Thain "options { %s} ", 4748c32513bSFinn Thain instance->hostt->name, instance->io_port, instance->n_io_port, 4758c32513bSFinn Thain instance->base, instance->irq, 4768c32513bSFinn Thain instance->can_queue, instance->cmd_per_lun, 4778c32513bSFinn Thain instance->sg_tablesize, instance->this_id, 47855181be8SFinn Thain hostdata->flags & FLAG_NO_DMA_FIXUP ? "NO_DMA_FIXUP " : "", 4798c32513bSFinn Thain hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "", 4809c3f0e2bSFinn Thain hostdata->flags & FLAG_TOSHIBA_DELAY ? "TOSHIBA_DELAY " : "", 4811da177e4SLinus Torvalds #ifdef AUTOPROBE_IRQ 4821da177e4SLinus Torvalds "AUTOPROBE_IRQ " 4831da177e4SLinus Torvalds #endif 4841da177e4SLinus Torvalds #ifdef DIFFERENTIAL 4851da177e4SLinus Torvalds "DIFFERENTIAL " 4861da177e4SLinus Torvalds #endif 4871da177e4SLinus Torvalds #ifdef REAL_DMA 4888c32513bSFinn Thain "REAL_DMA " 4891da177e4SLinus Torvalds #endif 4901da177e4SLinus Torvalds #ifdef REAL_DMA_POLL 4918c32513bSFinn Thain "REAL_DMA_POLL " 4921da177e4SLinus Torvalds #endif 4931da177e4SLinus Torvalds #ifdef PARITY 4941da177e4SLinus Torvalds "PARITY " 4951da177e4SLinus Torvalds #endif 4961da177e4SLinus Torvalds #ifdef PSEUDO_DMA 4978c32513bSFinn Thain "PSEUDO_DMA " 4981da177e4SLinus Torvalds #endif 4998c32513bSFinn Thain ""); 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds 502a9c2dc43SFinn Thain #ifdef PSEUDO_DMA 503dd7ab71bSAl Viro static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance, 504dd7ab71bSAl Viro char *buffer, int length) 5051da177e4SLinus Torvalds { 506a9c2dc43SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 507a9c2dc43SFinn Thain 508a9c2dc43SFinn Thain hostdata->spin_max_r = 0; 509a9c2dc43SFinn Thain hostdata->spin_max_w = 0; 510a9c2dc43SFinn Thain return 0; 5111da177e4SLinus Torvalds } 512dd7ab71bSAl Viro 513dd7ab71bSAl Viro static int __maybe_unused NCR5380_show_info(struct seq_file *m, 514dd7ab71bSAl Viro struct Scsi_Host *instance) 515dd7ab71bSAl Viro { 516e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 517dd7ab71bSAl Viro 5180c3de38fSRasmus Villemoes seq_printf(m, "Highwater I/O busy spin counts: write %d, read %d\n", 519a9c2dc43SFinn Thain hostdata->spin_max_w, hostdata->spin_max_r); 5201da177e4SLinus Torvalds return 0; 5211da177e4SLinus Torvalds } 522e5c3fddfSFinn Thain #endif 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds /** 5251da177e4SLinus Torvalds * NCR5380_init - initialise an NCR5380 5261da177e4SLinus Torvalds * @instance: adapter to configure 5271da177e4SLinus Torvalds * @flags: control flags 5281da177e4SLinus Torvalds * 5291da177e4SLinus Torvalds * Initializes *instance and corresponding 5380 chip, 5301da177e4SLinus Torvalds * with flags OR'd into the initial flags value. 5311da177e4SLinus Torvalds * 5321da177e4SLinus Torvalds * Notes : I assume that the host, hostno, and id bits have been 5331da177e4SLinus Torvalds * set correctly. I don't care about the irq and other fields. 5341da177e4SLinus Torvalds * 5351da177e4SLinus Torvalds * Returns 0 for success 5361da177e4SLinus Torvalds */ 5371da177e4SLinus Torvalds 5386f039790SGreg Kroah-Hartman static int NCR5380_init(struct Scsi_Host *instance, int flags) 5391da177e4SLinus Torvalds { 540e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 541b6488f97SFinn Thain int i; 5422f854b82SFinn Thain unsigned long deadline; 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds if(in_interrupt()) 5451da177e4SLinus Torvalds printk(KERN_ERR "NCR5380_init called with interrupts off!\n"); 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds hostdata->id_mask = 1 << instance->this_id; 5481da177e4SLinus Torvalds for (i = hostdata->id_mask; i <= 0x80; i <<= 1) 5491da177e4SLinus Torvalds if (i > hostdata->id_mask) 5501da177e4SLinus Torvalds hostdata->id_higher_mask |= i; 5511da177e4SLinus Torvalds for (i = 0; i < 8; ++i) 5521da177e4SLinus Torvalds hostdata->busy[i] = 0; 5531da177e4SLinus Torvalds #ifdef REAL_DMA 5541da177e4SLinus Torvalds hostdata->dmalen = 0; 5551da177e4SLinus Torvalds #endif 55611d2f63bSFinn Thain spin_lock_init(&hostdata->lock); 5571da177e4SLinus Torvalds hostdata->connected = NULL; 558f27db8ebSFinn Thain hostdata->sensing = NULL; 559f27db8ebSFinn Thain INIT_LIST_HEAD(&hostdata->autosense); 56032b26a10SFinn Thain INIT_LIST_HEAD(&hostdata->unissued); 56132b26a10SFinn Thain INIT_LIST_HEAD(&hostdata->disconnected); 56232b26a10SFinn Thain 56355181be8SFinn Thain hostdata->flags = flags; 5641da177e4SLinus Torvalds 5658d8601a7SFinn Thain INIT_WORK(&hostdata->main_task, NCR5380_main); 5660ad0eff9SFinn Thain hostdata->work_q = alloc_workqueue("ncr5380_%d", 5670ad0eff9SFinn Thain WQ_UNBOUND | WQ_MEM_RECLAIM, 5680ad0eff9SFinn Thain 1, instance->host_no); 5690ad0eff9SFinn Thain if (!hostdata->work_q) 5700ad0eff9SFinn Thain return -ENOMEM; 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds hostdata->host = instance; 5731da177e4SLinus Torvalds 5748c32513bSFinn Thain prepare_info(instance); 5758c32513bSFinn Thain 5761da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 5771da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 5781da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 5791da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 5802f854b82SFinn Thain 5812f854b82SFinn Thain /* Calibrate register polling loop */ 5822f854b82SFinn Thain i = 0; 5832f854b82SFinn Thain deadline = jiffies + 1; 5842f854b82SFinn Thain do { 5852f854b82SFinn Thain cpu_relax(); 5862f854b82SFinn Thain } while (time_is_after_jiffies(deadline)); 5872f854b82SFinn Thain deadline += msecs_to_jiffies(256); 5882f854b82SFinn Thain do { 5892f854b82SFinn Thain NCR5380_read(STATUS_REG); 5902f854b82SFinn Thain ++i; 5912f854b82SFinn Thain cpu_relax(); 5922f854b82SFinn Thain } while (time_is_after_jiffies(deadline)); 5932f854b82SFinn Thain hostdata->accesses_per_ms = i / 256; 5942f854b82SFinn Thain 595b6488f97SFinn Thain return 0; 596b6488f97SFinn Thain } 5971da177e4SLinus Torvalds 598b6488f97SFinn Thain /** 599b6488f97SFinn Thain * NCR5380_maybe_reset_bus - Detect and correct bus wedge problems. 600b6488f97SFinn Thain * @instance: adapter to check 6011da177e4SLinus Torvalds * 602b6488f97SFinn Thain * If the system crashed, it may have crashed with a connected target and 603b6488f97SFinn Thain * the SCSI bus busy. Check for BUS FREE phase. If not, try to abort the 604b6488f97SFinn Thain * currently established nexus, which we know nothing about. Failing that 605b6488f97SFinn Thain * do a bus reset. 6061da177e4SLinus Torvalds * 607b6488f97SFinn Thain * Note that a bus reset will cause the chip to assert IRQ. 608b6488f97SFinn Thain * 609b6488f97SFinn Thain * Returns 0 if successful, otherwise -ENXIO. 6101da177e4SLinus Torvalds */ 6111da177e4SLinus Torvalds 612b6488f97SFinn Thain static int NCR5380_maybe_reset_bus(struct Scsi_Host *instance) 613b6488f97SFinn Thain { 6149c3f0e2bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 615b6488f97SFinn Thain int pass; 616b6488f97SFinn Thain 6171da177e4SLinus Torvalds for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) { 6181da177e4SLinus Torvalds switch (pass) { 6191da177e4SLinus Torvalds case 1: 6201da177e4SLinus Torvalds case 3: 6211da177e4SLinus Torvalds case 5: 622636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "SCSI bus busy, waiting up to five seconds\n"); 623636b1ec8SFinn Thain NCR5380_poll_politely(instance, 624636b1ec8SFinn Thain STATUS_REG, SR_BSY, 0, 5 * HZ); 6251da177e4SLinus Torvalds break; 6261da177e4SLinus Torvalds case 2: 627636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus busy, attempting abort\n"); 6281da177e4SLinus Torvalds do_abort(instance); 6291da177e4SLinus Torvalds break; 6301da177e4SLinus Torvalds case 4: 631636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus busy, attempting reset\n"); 6321da177e4SLinus Torvalds do_reset(instance); 6339c3f0e2bSFinn Thain /* Wait after a reset; the SCSI standard calls for 6349c3f0e2bSFinn Thain * 250ms, we wait 500ms to be on the safe side. 6359c3f0e2bSFinn Thain * But some Toshiba CD-ROMs need ten times that. 6369c3f0e2bSFinn Thain */ 6379c3f0e2bSFinn Thain if (hostdata->flags & FLAG_TOSHIBA_DELAY) 6389c3f0e2bSFinn Thain msleep(2500); 6399c3f0e2bSFinn Thain else 6409c3f0e2bSFinn Thain msleep(500); 6411da177e4SLinus Torvalds break; 6421da177e4SLinus Torvalds case 6: 643636b1ec8SFinn Thain shost_printk(KERN_ERR, instance, "bus locked solid\n"); 6441da177e4SLinus Torvalds return -ENXIO; 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds return 0; 6481da177e4SLinus Torvalds } 6491da177e4SLinus Torvalds 6501da177e4SLinus Torvalds /** 6511da177e4SLinus Torvalds * NCR5380_exit - remove an NCR5380 6521da177e4SLinus Torvalds * @instance: adapter to remove 6531da177e4SLinus Torvalds */ 6541da177e4SLinus Torvalds 655a43cf0f3SRandy Dunlap static void NCR5380_exit(struct Scsi_Host *instance) 6561da177e4SLinus Torvalds { 657e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 6581da177e4SLinus Torvalds 6598d8601a7SFinn Thain cancel_work_sync(&hostdata->main_task); 6600ad0eff9SFinn Thain destroy_workqueue(hostdata->work_q); 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds /** 664677e0194SFinn Thain * complete_cmd - finish processing a command and return it to the SCSI ML 665677e0194SFinn Thain * @instance: the host instance 666677e0194SFinn Thain * @cmd: command to complete 667677e0194SFinn Thain */ 668677e0194SFinn Thain 669677e0194SFinn Thain static void complete_cmd(struct Scsi_Host *instance, 670677e0194SFinn Thain struct scsi_cmnd *cmd) 671677e0194SFinn Thain { 672677e0194SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 673677e0194SFinn Thain 674677e0194SFinn Thain dsprintk(NDEBUG_QUEUES, instance, "complete_cmd: cmd %p\n", cmd); 675677e0194SFinn Thain 676f27db8ebSFinn Thain if (hostdata->sensing == cmd) { 677f27db8ebSFinn Thain /* Autosense processing ends here */ 678f27db8ebSFinn Thain if ((cmd->result & 0xff) != SAM_STAT_GOOD) { 679f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 680f27db8ebSFinn Thain set_host_byte(cmd, DID_ERROR); 681f27db8ebSFinn Thain } else 682f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 683f27db8ebSFinn Thain hostdata->sensing = NULL; 684f27db8ebSFinn Thain } 685f27db8ebSFinn Thain 686677e0194SFinn Thain hostdata->busy[scmd_id(cmd)] &= ~(1 << cmd->device->lun); 687677e0194SFinn Thain 688677e0194SFinn Thain cmd->scsi_done(cmd); 689677e0194SFinn Thain } 690677e0194SFinn Thain 691677e0194SFinn Thain /** 6921da177e4SLinus Torvalds * NCR5380_queue_command - queue a command 6931bb40589SFinn Thain * @instance: the relevant SCSI adapter 6941da177e4SLinus Torvalds * @cmd: SCSI command 6951da177e4SLinus Torvalds * 6961bb40589SFinn Thain * cmd is added to the per-instance issue queue, with minor 6971da177e4SLinus Torvalds * twiddling done to the host specific fields of cmd. If the 6981da177e4SLinus Torvalds * main coroutine is not running, it is restarted. 6991da177e4SLinus Torvalds */ 7001da177e4SLinus Torvalds 7011bb40589SFinn Thain static int NCR5380_queue_command(struct Scsi_Host *instance, 7021bb40589SFinn Thain struct scsi_cmnd *cmd) 7031da177e4SLinus Torvalds { 7041bb40589SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 70532b26a10SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 7061bb40589SFinn Thain unsigned long flags; 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_WRITE) 7091da177e4SLinus Torvalds switch (cmd->cmnd[0]) { 7101da177e4SLinus Torvalds case WRITE_6: 7111da177e4SLinus Torvalds case WRITE_10: 712dbb6b350SFinn Thain shost_printk(KERN_DEBUG, instance, "WRITE attempted with NDEBUG_NO_WRITE set\n"); 7131da177e4SLinus Torvalds cmd->result = (DID_ERROR << 16); 7141bb40589SFinn Thain cmd->scsi_done(cmd); 7151da177e4SLinus Torvalds return 0; 7161da177e4SLinus Torvalds } 7171da177e4SLinus Torvalds #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ 7181da177e4SLinus Torvalds 7191da177e4SLinus Torvalds cmd->result = 0; 7201da177e4SLinus Torvalds 72111d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 7221bb40589SFinn Thain 7231da177e4SLinus Torvalds /* 7241da177e4SLinus Torvalds * Insert the cmd into the issue queue. Note that REQUEST SENSE 7251da177e4SLinus Torvalds * commands are added to the head of the queue since any command will 7261da177e4SLinus Torvalds * clear the contingent allegiance condition that exists and the 7271da177e4SLinus Torvalds * sense data is only guaranteed to be valid while the condition exists. 7281da177e4SLinus Torvalds */ 7291da177e4SLinus Torvalds 73032b26a10SFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 73132b26a10SFinn Thain list_add(&ncmd->list, &hostdata->unissued); 73232b26a10SFinn Thain else 73332b26a10SFinn Thain list_add_tail(&ncmd->list, &hostdata->unissued); 73432b26a10SFinn Thain 73511d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 7361bb40589SFinn Thain 737dbb6b350SFinn Thain dsprintk(NDEBUG_QUEUES, instance, "command %p added to %s of queue\n", 738dbb6b350SFinn Thain cmd, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds /* Kick off command processing */ 7418d8601a7SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 7421da177e4SLinus Torvalds return 0; 7431da177e4SLinus Torvalds } 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds /** 746f27db8ebSFinn Thain * dequeue_next_cmd - dequeue a command for processing 747f27db8ebSFinn Thain * @instance: the scsi host instance 748f27db8ebSFinn Thain * 749f27db8ebSFinn Thain * Priority is given to commands on the autosense queue. These commands 750f27db8ebSFinn Thain * need autosense because of a CHECK CONDITION result. 751f27db8ebSFinn Thain * 752f27db8ebSFinn Thain * Returns a command pointer if a command is found for a target that is 753f27db8ebSFinn Thain * not already busy. Otherwise returns NULL. 754f27db8ebSFinn Thain */ 755f27db8ebSFinn Thain 756f27db8ebSFinn Thain static struct scsi_cmnd *dequeue_next_cmd(struct Scsi_Host *instance) 757f27db8ebSFinn Thain { 758f27db8ebSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 759f27db8ebSFinn Thain struct NCR5380_cmd *ncmd; 760f27db8ebSFinn Thain struct scsi_cmnd *cmd; 761f27db8ebSFinn Thain 762f27db8ebSFinn Thain if (list_empty(&hostdata->autosense)) { 763f27db8ebSFinn Thain list_for_each_entry(ncmd, &hostdata->unissued, list) { 764f27db8ebSFinn Thain cmd = NCR5380_to_scmd(ncmd); 765f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, "dequeue: cmd=%p target=%d busy=0x%02x lun=%llu\n", 766f27db8ebSFinn Thain cmd, scmd_id(cmd), hostdata->busy[scmd_id(cmd)], cmd->device->lun); 767f27db8ebSFinn Thain 768f27db8ebSFinn Thain if (!(hostdata->busy[scmd_id(cmd)] & (1 << cmd->device->lun))) { 769f27db8ebSFinn Thain list_del(&ncmd->list); 770f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, 771f27db8ebSFinn Thain "dequeue: removed %p from issue queue\n", cmd); 772f27db8ebSFinn Thain return cmd; 773f27db8ebSFinn Thain } 774f27db8ebSFinn Thain } 775f27db8ebSFinn Thain } else { 776f27db8ebSFinn Thain /* Autosense processing begins here */ 777f27db8ebSFinn Thain ncmd = list_first_entry(&hostdata->autosense, 778f27db8ebSFinn Thain struct NCR5380_cmd, list); 779f27db8ebSFinn Thain list_del(&ncmd->list); 780f27db8ebSFinn Thain cmd = NCR5380_to_scmd(ncmd); 781f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, 782f27db8ebSFinn Thain "dequeue: removed %p from autosense queue\n", cmd); 783f27db8ebSFinn Thain scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); 784f27db8ebSFinn Thain hostdata->sensing = cmd; 785f27db8ebSFinn Thain return cmd; 786f27db8ebSFinn Thain } 787f27db8ebSFinn Thain return NULL; 788f27db8ebSFinn Thain } 789f27db8ebSFinn Thain 790f27db8ebSFinn Thain static void requeue_cmd(struct Scsi_Host *instance, struct scsi_cmnd *cmd) 791f27db8ebSFinn Thain { 792f27db8ebSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 793f27db8ebSFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 794f27db8ebSFinn Thain 795f27db8ebSFinn Thain if (hostdata->sensing) { 796f27db8ebSFinn Thain scsi_eh_restore_cmnd(cmd, &hostdata->ses); 797f27db8ebSFinn Thain list_add(&ncmd->list, &hostdata->autosense); 798f27db8ebSFinn Thain hostdata->sensing = NULL; 799f27db8ebSFinn Thain } else 800f27db8ebSFinn Thain list_add(&ncmd->list, &hostdata->unissued); 801f27db8ebSFinn Thain } 802f27db8ebSFinn Thain 803f27db8ebSFinn Thain /** 8041da177e4SLinus Torvalds * NCR5380_main - NCR state machines 8051da177e4SLinus Torvalds * 8061da177e4SLinus Torvalds * NCR5380_main is a coroutine that runs as long as more work can 8071da177e4SLinus Torvalds * be done on the NCR5380 host adapters in a system. Both 8081da177e4SLinus Torvalds * NCR5380_queue_command() and NCR5380_intr() will try to start it 8091da177e4SLinus Torvalds * in case it is not running. 8101da177e4SLinus Torvalds */ 8111da177e4SLinus Torvalds 812c4028958SDavid Howells static void NCR5380_main(struct work_struct *work) 8131da177e4SLinus Torvalds { 814c4028958SDavid Howells struct NCR5380_hostdata *hostdata = 8158d8601a7SFinn Thain container_of(work, struct NCR5380_hostdata, main_task); 8161da177e4SLinus Torvalds struct Scsi_Host *instance = hostdata->host; 817f27db8ebSFinn Thain struct scsi_cmnd *cmd; 8181da177e4SLinus Torvalds int done; 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds do { 8211da177e4SLinus Torvalds done = 1; 82211d2f63bSFinn Thain 8230a4e3612SFinn Thain spin_lock_irq(&hostdata->lock); 824f27db8ebSFinn Thain while (!hostdata->connected && 825f27db8ebSFinn Thain (cmd = dequeue_next_cmd(instance))) { 82632b26a10SFinn Thain 827f27db8ebSFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: dequeued %p\n", cmd); 8281da177e4SLinus Torvalds 8291da177e4SLinus Torvalds /* 8301da177e4SLinus Torvalds * Attempt to establish an I_T_L nexus here. 8311da177e4SLinus Torvalds * On success, instance->hostdata->connected is set. 8321da177e4SLinus Torvalds * On failure, we must add the command back to the 8331da177e4SLinus Torvalds * issue queue so we can keep trying. 8341da177e4SLinus Torvalds */ 8351da177e4SLinus Torvalds /* 8361da177e4SLinus Torvalds * REQUEST SENSE commands are issued without tagged 8371da177e4SLinus Torvalds * queueing, even on SCSI-II devices because the 8381da177e4SLinus Torvalds * contingent allegiance condition exists for the 8391da177e4SLinus Torvalds * entire unit. 8401da177e4SLinus Torvalds */ 84176f13b93SFinn Thain 842707d62b3SFinn Thain cmd = NCR5380_select(instance, cmd); 843707d62b3SFinn Thain if (!cmd) { 844707d62b3SFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: select complete\n"); 8451da177e4SLinus Torvalds } else { 846f27db8ebSFinn Thain dsprintk(NDEBUG_MAIN | NDEBUG_QUEUES, instance, 847f27db8ebSFinn Thain "main: select failed, returning %p to queue\n", cmd); 848f27db8ebSFinn Thain requeue_cmd(instance, cmd); 8491da177e4SLinus Torvalds } 850f27db8ebSFinn Thain } 8511da177e4SLinus Torvalds if (hostdata->connected 8521da177e4SLinus Torvalds #ifdef REAL_DMA 8531da177e4SLinus Torvalds && !hostdata->dmalen 8541da177e4SLinus Torvalds #endif 8551da177e4SLinus Torvalds ) { 856b746545fSFinn Thain dsprintk(NDEBUG_MAIN, instance, "main: performing information transfer\n"); 8571da177e4SLinus Torvalds NCR5380_information_transfer(instance); 8581da177e4SLinus Torvalds done = 0; 8591d3db59dSFinn Thain } 86011d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 8610a4e3612SFinn Thain if (!done) 8620a4e3612SFinn Thain cond_resched(); 8630a4e3612SFinn Thain } while (!done); 8641da177e4SLinus Torvalds } 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds #ifndef DONT_USE_INTR 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds /** 8691da177e4SLinus Torvalds * NCR5380_intr - generic NCR5380 irq handler 8701da177e4SLinus Torvalds * @irq: interrupt number 8711da177e4SLinus Torvalds * @dev_id: device info 8721da177e4SLinus Torvalds * 8731da177e4SLinus Torvalds * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses 8741da177e4SLinus Torvalds * from the disconnected queue, and restarting NCR5380_main() 8751da177e4SLinus Torvalds * as required. 8761da177e4SLinus Torvalds * 877cd400825SFinn Thain * The chip can assert IRQ in any of six different conditions. The IRQ flag 878cd400825SFinn Thain * is then cleared by reading the Reset Parity/Interrupt Register (RPIR). 879cd400825SFinn Thain * Three of these six conditions are latched in the Bus and Status Register: 880cd400825SFinn Thain * - End of DMA (cleared by ending DMA Mode) 881cd400825SFinn Thain * - Parity error (cleared by reading RPIR) 882cd400825SFinn Thain * - Loss of BSY (cleared by reading RPIR) 883cd400825SFinn Thain * Two conditions have flag bits that are not latched: 884cd400825SFinn Thain * - Bus phase mismatch (non-maskable in DMA Mode, cleared by ending DMA Mode) 885cd400825SFinn Thain * - Bus reset (non-maskable) 886cd400825SFinn Thain * The remaining condition has no flag bit at all: 887cd400825SFinn Thain * - Selection/reselection 888cd400825SFinn Thain * 889cd400825SFinn Thain * Hence, establishing the cause(s) of any interrupt is partly guesswork. 890cd400825SFinn Thain * In "The DP8490 and DP5380 Comparison Guide", National Semiconductor 891cd400825SFinn Thain * claimed that "the design of the [DP8490] interrupt logic ensures 892cd400825SFinn Thain * interrupts will not be lost (they can be on the DP5380)." 893cd400825SFinn Thain * The L5380/53C80 datasheet from LOGIC Devices has more details. 894cd400825SFinn Thain * 895cd400825SFinn Thain * Checking for bus reset by reading RST is futile because of interrupt 896cd400825SFinn Thain * latency, but a bus reset will reset chip logic. Checking for parity error 897cd400825SFinn Thain * is unnecessary because that interrupt is never enabled. A Loss of BSY 898cd400825SFinn Thain * condition will clear DMA Mode. We can tell when this occurs because the 899cd400825SFinn Thain * the Busy Monitor interrupt is enabled together with DMA Mode. 9001da177e4SLinus Torvalds */ 9011da177e4SLinus Torvalds 902cd400825SFinn Thain static irqreturn_t NCR5380_intr(int irq, void *dev_id) 9031da177e4SLinus Torvalds { 904baa9aac6SJeff Garzik struct Scsi_Host *instance = dev_id; 905cd400825SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 906cd400825SFinn Thain int handled = 0; 9071da177e4SLinus Torvalds unsigned char basr; 9081da177e4SLinus Torvalds unsigned long flags; 9091da177e4SLinus Torvalds 91011d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 911cd400825SFinn Thain 9121da177e4SLinus Torvalds basr = NCR5380_read(BUS_AND_STATUS_REG); 9131da177e4SLinus Torvalds if (basr & BASR_IRQ) { 914cd400825SFinn Thain unsigned char mr = NCR5380_read(MODE_REG); 915cd400825SFinn Thain unsigned char sr = NCR5380_read(STATUS_REG); 916cd400825SFinn Thain 917b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "IRQ %d, BASR 0x%02x, SR 0x%02x, MR 0x%02x\n", 918b746545fSFinn Thain irq, basr, sr, mr); 919cd400825SFinn Thain 9201da177e4SLinus Torvalds #if defined(REAL_DMA) 921cd400825SFinn Thain if ((mr & MR_DMA_MODE) || (mr & MR_MONITOR_BSY)) { 922cd400825SFinn Thain /* Probably End of DMA, Phase Mismatch or Loss of BSY. 923cd400825SFinn Thain * We ack IRQ after clearing Mode Register. Workarounds 924cd400825SFinn Thain * for End of DMA errata need to happen in DMA Mode. 9251da177e4SLinus Torvalds */ 9261da177e4SLinus Torvalds 927b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt in DMA mode\n"); 928cd400825SFinn Thain 92925985edcSLucas De Marchi int transferred; 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds if (!hostdata->connected) 932cd400825SFinn Thain panic("scsi%d : DMA interrupt with no connected cmd\n", 933cd400825SFinn Thain instance->hostno); 9341da177e4SLinus Torvalds 935cd400825SFinn Thain transferred = hostdata->dmalen - NCR5380_dma_residual(instance); 9361da177e4SLinus Torvalds hostdata->connected->SCp.this_residual -= transferred; 9371da177e4SLinus Torvalds hostdata->connected->SCp.ptr += transferred; 9381da177e4SLinus Torvalds hostdata->dmalen = 0; 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds /* FIXME: we need to poll briefly then defer a workqueue task ! */ 9411da177e4SLinus Torvalds NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2 * HZ); 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 944cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 945cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 946cd400825SFinn Thain } else 947cd400825SFinn Thain #endif /* REAL_DMA */ 948cd400825SFinn Thain if ((NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_mask) && 949cd400825SFinn Thain (sr & (SR_SEL | SR_IO | SR_BSY | SR_RST)) == (SR_SEL | SR_IO)) { 950cd400825SFinn Thain /* Probably reselected */ 951cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 952cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 953cd400825SFinn Thain 954b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "interrupt with SEL and IO\n"); 955cd400825SFinn Thain 956cd400825SFinn Thain if (!hostdata->connected) { 957cd400825SFinn Thain NCR5380_reselect(instance); 9588d8601a7SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 959cd400825SFinn Thain } 960cd400825SFinn Thain if (!hostdata->connected) 961cd400825SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 962cd400825SFinn Thain } else { 963cd400825SFinn Thain /* Probably Bus Reset */ 964cd400825SFinn Thain NCR5380_read(RESET_PARITY_INTERRUPT_REG); 965cd400825SFinn Thain 966b746545fSFinn Thain dsprintk(NDEBUG_INTR, instance, "unknown interrupt\n"); 967cd400825SFinn Thain } 968cd400825SFinn Thain handled = 1; 969cd400825SFinn Thain } else { 970cd400825SFinn Thain shost_printk(KERN_NOTICE, instance, "interrupt without IRQ bit\n"); 971cd400825SFinn Thain } 972cd400825SFinn Thain 97311d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 974cd400825SFinn Thain 975cd400825SFinn Thain return IRQ_RETVAL(handled); 9761da177e4SLinus Torvalds } 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds #endif 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds /* 981710ddd0dSFinn Thain * Function : int NCR5380_select(struct Scsi_Host *instance, 982710ddd0dSFinn Thain * struct scsi_cmnd *cmd) 9831da177e4SLinus Torvalds * 9841da177e4SLinus Torvalds * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, 9851da177e4SLinus Torvalds * including ARBITRATION, SELECTION, and initial message out for 9861da177e4SLinus Torvalds * IDENTIFY and queue messages. 9871da177e4SLinus Torvalds * 9881da177e4SLinus Torvalds * Inputs : instance - instantiation of the 5380 driver on which this 98976f13b93SFinn Thain * target lives, cmd - SCSI command to execute. 9901da177e4SLinus Torvalds * 991707d62b3SFinn Thain * Returns cmd if selection failed but should be retried, 992707d62b3SFinn Thain * NULL if selection failed and should not be retried, or 993707d62b3SFinn Thain * NULL if selection succeeded (hostdata->connected == cmd). 9941da177e4SLinus Torvalds * 9951da177e4SLinus Torvalds * Side effects : 9961da177e4SLinus Torvalds * If bus busy, arbitration failed, etc, NCR5380_select() will exit 9971da177e4SLinus Torvalds * with registers as they should have been on entry - ie 9981da177e4SLinus Torvalds * SELECT_ENABLE will be set appropriately, the NCR5380 9991da177e4SLinus Torvalds * will cease to drive any SCSI bus signals. 10001da177e4SLinus Torvalds * 10011da177e4SLinus Torvalds * If successful : I_T_L or I_T_L_Q nexus will be established, 10021da177e4SLinus Torvalds * instance->connected will be set to cmd. 10031da177e4SLinus Torvalds * SELECT interrupt will be disabled. 10041da177e4SLinus Torvalds * 10051da177e4SLinus Torvalds * If failed (no target) : cmd->scsi_done() will be called, and the 10061da177e4SLinus Torvalds * cmd->result host byte set to DID_BAD_TARGET. 10071da177e4SLinus Torvalds */ 10081da177e4SLinus Torvalds 1009707d62b3SFinn Thain static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance, 1010707d62b3SFinn Thain struct scsi_cmnd *cmd) 10111da177e4SLinus Torvalds { 1012e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 10131da177e4SLinus Torvalds unsigned char tmp[3], phase; 10141da177e4SLinus Torvalds unsigned char *data; 10151da177e4SLinus Torvalds int len; 10161da177e4SLinus Torvalds int err; 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_ARBITRATION, instance); 1019b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n", 1020b746545fSFinn Thain instance->this_id); 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds /* 1023707d62b3SFinn Thain * Arbitration and selection phases are slow and involve dropping the 1024707d62b3SFinn Thain * lock, so we have to watch out for EH. An exception handler may 1025707d62b3SFinn Thain * change 'selecting' to NULL. This function will then return NULL 1026707d62b3SFinn Thain * so that the caller will forget about 'cmd'. (During information 1027707d62b3SFinn Thain * transfer phases, EH may change 'connected' to NULL.) 1028707d62b3SFinn Thain */ 1029707d62b3SFinn Thain hostdata->selecting = cmd; 1030707d62b3SFinn Thain 1031707d62b3SFinn Thain /* 10321da177e4SLinus Torvalds * Set the phase bits to 0, otherwise the NCR5380 won't drive the 10331da177e4SLinus Torvalds * data bus during SELECTION. 10341da177e4SLinus Torvalds */ 10351da177e4SLinus Torvalds 10361da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds /* 10391da177e4SLinus Torvalds * Start arbitration. 10401da177e4SLinus Torvalds */ 10411da177e4SLinus Torvalds 10421da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); 10431da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_ARBITRATE); 10441da177e4SLinus Torvalds 104555500d9bSFinn Thain /* The chip now waits for BUS FREE phase. Then after the 800 ns 104655500d9bSFinn Thain * Bus Free Delay, arbitration will begin. 10471da177e4SLinus Torvalds */ 10481da177e4SLinus Torvalds 104911d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 1050b32ade12SFinn Thain err = NCR5380_poll_politely2(instance, MODE_REG, MR_ARBITRATE, 0, 1051b32ade12SFinn Thain INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, 1052b32ade12SFinn Thain ICR_ARBITRATION_PROGRESS, HZ); 105311d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 105455500d9bSFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) { 105555500d9bSFinn Thain /* Reselection interrupt */ 1056707d62b3SFinn Thain goto out; 105755500d9bSFinn Thain } 1058b32ade12SFinn Thain if (err < 0) { 1059b32ade12SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1060b32ade12SFinn Thain shost_printk(KERN_ERR, instance, 1061b32ade12SFinn Thain "select: arbitration timeout\n"); 1062707d62b3SFinn Thain goto out; 106355500d9bSFinn Thain } 106411d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 106555500d9bSFinn Thain 106655500d9bSFinn Thain /* The SCSI-2 arbitration delay is 2.4 us */ 10671da177e4SLinus Torvalds udelay(3); 10681da177e4SLinus Torvalds 10691da177e4SLinus Torvalds /* Check for lost arbitration */ 10701da177e4SLinus Torvalds if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { 10711da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 1072b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "lost arbitration, deasserting MR_ARBITRATE\n"); 107311d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1074707d62b3SFinn Thain goto out; 10751da177e4SLinus Torvalds } 1076cf13b083SFinn Thain 1077cf13b083SFinn Thain /* After/during arbitration, BSY should be asserted. 1078cf13b083SFinn Thain * IBM DPES-31080 Version S31Q works now 1079cf13b083SFinn Thain * Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) 1080cf13b083SFinn Thain */ 1081cf13b083SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, 1082cf13b083SFinn Thain ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY); 10831da177e4SLinus Torvalds 10841da177e4SLinus Torvalds /* 10851da177e4SLinus Torvalds * Again, bus clear + bus settle time is 1.2us, however, this is 10861da177e4SLinus Torvalds * a minimum so we'll udelay ceil(1.2) 10871da177e4SLinus Torvalds */ 10881da177e4SLinus Torvalds 10899c3f0e2bSFinn Thain if (hostdata->flags & FLAG_TOSHIBA_DELAY) 10909c3f0e2bSFinn Thain udelay(15); 10919c3f0e2bSFinn Thain else 10921da177e4SLinus Torvalds udelay(2); 10931da177e4SLinus Torvalds 109411d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 109511d2f63bSFinn Thain 109672064a78SFinn Thain /* NCR5380_reselect() clears MODE_REG after a reselection interrupt */ 109772064a78SFinn Thain if (!(NCR5380_read(MODE_REG) & MR_ARBITRATE)) 1098707d62b3SFinn Thain goto out; 1099707d62b3SFinn Thain 1100707d62b3SFinn Thain if (!hostdata->selecting) { 1101707d62b3SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 1102707d62b3SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1103707d62b3SFinn Thain goto out; 1104707d62b3SFinn Thain } 110572064a78SFinn Thain 1106b746545fSFinn Thain dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n"); 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds /* 11091da177e4SLinus Torvalds * Now that we have won arbitration, start Selection process, asserting 11101da177e4SLinus Torvalds * the host and target ID's on the SCSI bus. 11111da177e4SLinus Torvalds */ 11121da177e4SLinus Torvalds 1113422c0d61SJeff Garzik NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << scmd_id(cmd)))); 11141da177e4SLinus Torvalds 11151da177e4SLinus Torvalds /* 11161da177e4SLinus Torvalds * Raise ATN while SEL is true before BSY goes false from arbitration, 11171da177e4SLinus Torvalds * since this is the only way to guarantee that we'll get a MESSAGE OUT 11181da177e4SLinus Torvalds * phase immediately after selection. 11191da177e4SLinus Torvalds */ 11201da177e4SLinus Torvalds 11211da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); 11221da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 11231da177e4SLinus Torvalds 11241da177e4SLinus Torvalds /* 11251da177e4SLinus Torvalds * Reselect interrupts must be turned off prior to the dropping of BSY, 11261da177e4SLinus Torvalds * otherwise we will trigger an interrupt. 11271da177e4SLinus Torvalds */ 11281da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, 0); 11291da177e4SLinus Torvalds 113011d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 113111d2f63bSFinn Thain 11321da177e4SLinus Torvalds /* 11331da177e4SLinus Torvalds * The initiator shall then wait at least two deskew delays and release 11341da177e4SLinus Torvalds * the BSY signal. 11351da177e4SLinus Torvalds */ 11361da177e4SLinus Torvalds udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ 11371da177e4SLinus Torvalds 11381da177e4SLinus Torvalds /* Reset BSY */ 11391da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); 11401da177e4SLinus Torvalds 11411da177e4SLinus Torvalds /* 11421da177e4SLinus Torvalds * Something weird happens when we cease to drive BSY - looks 11431da177e4SLinus Torvalds * like the board/chip is letting us do another read before the 11441da177e4SLinus Torvalds * appropriate propagation delay has expired, and we're confusing 11451da177e4SLinus Torvalds * a BSY signal from ourselves as the target's response to SELECTION. 11461da177e4SLinus Torvalds * 11471da177e4SLinus Torvalds * A small delay (the 'C++' frontend breaks the pipeline with an 11481da177e4SLinus Torvalds * unnecessary jump, making it work on my 386-33/Trantor T128, the 11491da177e4SLinus Torvalds * tighter 'C' code breaks and requires this) solves the problem - 11501da177e4SLinus Torvalds * the 1 us delay is arbitrary, and only used because this delay will 11511da177e4SLinus Torvalds * be the same on other platforms and since it works here, it should 11521da177e4SLinus Torvalds * work there. 11531da177e4SLinus Torvalds * 11541da177e4SLinus Torvalds * wingel suggests that this could be due to failing to wait 11551da177e4SLinus Torvalds * one deskew delay. 11561da177e4SLinus Torvalds */ 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds udelay(1); 11591da177e4SLinus Torvalds 1160b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "selecting target %d\n", scmd_id(cmd)); 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds /* 11631da177e4SLinus Torvalds * The SCSI specification calls for a 250 ms timeout for the actual 11641da177e4SLinus Torvalds * selection. 11651da177e4SLinus Torvalds */ 11661da177e4SLinus Torvalds 1167ae753a33SFinn Thain err = NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, SR_BSY, 1168ae753a33SFinn Thain msecs_to_jiffies(250)); 11691da177e4SLinus Torvalds 11701da177e4SLinus Torvalds if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { 117111d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 11721da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 11731da177e4SLinus Torvalds NCR5380_reselect(instance); 1174cd400825SFinn Thain if (!hostdata->connected) 11751da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 11766a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n"); 1177707d62b3SFinn Thain goto out; 11781da177e4SLinus Torvalds } 1179ae753a33SFinn Thain 1180ae753a33SFinn Thain if (err < 0) { 118111d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 1182ae753a33SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1183707d62b3SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1184707d62b3SFinn Thain /* Can't touch cmd if it has been reclaimed by the scsi ML */ 1185707d62b3SFinn Thain if (hostdata->selecting) { 1186ae753a33SFinn Thain cmd->result = DID_BAD_TARGET << 16; 1187677e0194SFinn Thain complete_cmd(instance, cmd); 1188707d62b3SFinn Thain dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n"); 1189707d62b3SFinn Thain cmd = NULL; 1190707d62b3SFinn Thain } 1191707d62b3SFinn Thain goto out; 1192ae753a33SFinn Thain } 1193ae753a33SFinn Thain 11941da177e4SLinus Torvalds /* 11951da177e4SLinus Torvalds * No less than two deskew delays after the initiator detects the 11961da177e4SLinus Torvalds * BSY signal is true, it shall release the SEL signal and may 11971da177e4SLinus Torvalds * change the DATA BUS. -wingel 11981da177e4SLinus Torvalds */ 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds udelay(1); 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds /* 12051da177e4SLinus Torvalds * Since we followed the SCSI spec, and raised ATN while SEL 12061da177e4SLinus Torvalds * was true but before BSY was false during selection, the information 12071da177e4SLinus Torvalds * transfer phase should be a MESSAGE OUT phase so that we can send the 12081da177e4SLinus Torvalds * IDENTIFY message. 12091da177e4SLinus Torvalds * 12101da177e4SLinus Torvalds * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG 12111da177e4SLinus Torvalds * message (2 bytes) with a tag ID that we increment with every command 12121da177e4SLinus Torvalds * until it wraps back to 0. 12131da177e4SLinus Torvalds * 12141da177e4SLinus Torvalds * XXX - it turns out that there are some broken SCSI-II devices, 12151da177e4SLinus Torvalds * which claim to support tagged queuing but fail when more than 12161da177e4SLinus Torvalds * some number of commands are issued at once. 12171da177e4SLinus Torvalds */ 12181da177e4SLinus Torvalds 12191da177e4SLinus Torvalds /* Wait for start of REQ/ACK handshake */ 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ); 122211d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 12231cc160e1SFinn Thain if (err < 0) { 122455500d9bSFinn Thain shost_printk(KERN_ERR, instance, "select: REQ timeout\n"); 122555500d9bSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 12261da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 1227707d62b3SFinn Thain goto out; 1228707d62b3SFinn Thain } 1229707d62b3SFinn Thain if (!hostdata->selecting) { 1230707d62b3SFinn Thain do_abort(instance); 1231707d62b3SFinn Thain goto out; 12321da177e4SLinus Torvalds } 12331da177e4SLinus Torvalds 1234b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n", 1235b746545fSFinn Thain scmd_id(cmd)); 123622f5f10dSFinn Thain tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun); 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds len = 1; 12391da177e4SLinus Torvalds cmd->tag = 0; 12401da177e4SLinus Torvalds 12411da177e4SLinus Torvalds /* Send message(s) */ 12421da177e4SLinus Torvalds data = tmp; 12431da177e4SLinus Torvalds phase = PHASE_MSGOUT; 12441da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 1245b746545fSFinn Thain dsprintk(NDEBUG_SELECTION, instance, "nexus established.\n"); 12461da177e4SLinus Torvalds /* XXX need to handle errors here */ 124711d2f63bSFinn Thain 12481da177e4SLinus Torvalds hostdata->connected = cmd; 12499cb78c16SHannes Reinecke hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF)); 12501da177e4SLinus Torvalds 12511da177e4SLinus Torvalds initialize_SCp(cmd); 12521da177e4SLinus Torvalds 1253707d62b3SFinn Thain cmd = NULL; 1254707d62b3SFinn Thain 1255707d62b3SFinn Thain out: 1256707d62b3SFinn Thain if (!hostdata->selecting) 1257707d62b3SFinn Thain return NULL; 1258707d62b3SFinn Thain hostdata->selecting = NULL; 1259707d62b3SFinn Thain return cmd; 12601da177e4SLinus Torvalds } 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds /* 12631da177e4SLinus Torvalds * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 12641da177e4SLinus Torvalds * unsigned char *phase, int *count, unsigned char **data) 12651da177e4SLinus Torvalds * 12661da177e4SLinus Torvalds * Purpose : transfers data in given phase using polled I/O 12671da177e4SLinus Torvalds * 12681da177e4SLinus Torvalds * Inputs : instance - instance of driver, *phase - pointer to 12691da177e4SLinus Torvalds * what phase is expected, *count - pointer to number of 12701da177e4SLinus Torvalds * bytes to transfer, **data - pointer to data pointer. 12711da177e4SLinus Torvalds * 12721da177e4SLinus Torvalds * Returns : -1 when different phase is entered without transferring 127325985edcSLucas De Marchi * maximum number of bytes, 0 if all bytes or transferred or exit 12741da177e4SLinus Torvalds * is in same phase. 12751da177e4SLinus Torvalds * 12761da177e4SLinus Torvalds * Also, *phase, *count, *data are modified in place. 12771da177e4SLinus Torvalds * 12781da177e4SLinus Torvalds * XXX Note : handling for bus free may be useful. 12791da177e4SLinus Torvalds */ 12801da177e4SLinus Torvalds 12811da177e4SLinus Torvalds /* 12821da177e4SLinus Torvalds * Note : this code is not as quick as it could be, however it 12831da177e4SLinus Torvalds * IS 100% reliable, and for the actual data transfer where speed 12841da177e4SLinus Torvalds * counts, we will always do a pseudo DMA or DMA transfer. 12851da177e4SLinus Torvalds */ 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { 12881da177e4SLinus Torvalds unsigned char p = *phase, tmp; 12891da177e4SLinus Torvalds int c = *count; 12901da177e4SLinus Torvalds unsigned char *d = *data; 12911da177e4SLinus Torvalds 12921da177e4SLinus Torvalds /* 12931da177e4SLinus Torvalds * The NCR5380 chip will only drive the SCSI bus when the 12941da177e4SLinus Torvalds * phase specified in the appropriate bits of the TARGET COMMAND 12951da177e4SLinus Torvalds * REGISTER match the STATUS REGISTER 12961da177e4SLinus Torvalds */ 12971da177e4SLinus Torvalds 12981da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds do { 13011da177e4SLinus Torvalds /* 13021da177e4SLinus Torvalds * Wait for assertion of REQ, after which the phase bits will be 13031da177e4SLinus Torvalds * valid 13041da177e4SLinus Torvalds */ 13051da177e4SLinus Torvalds 1306686f3990SFinn Thain if (NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ) < 0) 13071da177e4SLinus Torvalds break; 13081da177e4SLinus Torvalds 1309b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ asserted\n"); 13101da177e4SLinus Torvalds 13111da177e4SLinus Torvalds /* Check for phase mismatch */ 1312686f3990SFinn Thain if ((NCR5380_read(STATUS_REG) & PHASE_MASK) != p) { 1313b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "phase mismatch\n"); 1314b746545fSFinn Thain NCR5380_dprint_phase(NDEBUG_PIO, instance); 13151da177e4SLinus Torvalds break; 13161da177e4SLinus Torvalds } 13171da177e4SLinus Torvalds /* Do actual transfer from SCSI bus to / from memory */ 13181da177e4SLinus Torvalds if (!(p & SR_IO)) 13191da177e4SLinus Torvalds NCR5380_write(OUTPUT_DATA_REG, *d); 13201da177e4SLinus Torvalds else 13211da177e4SLinus Torvalds *d = NCR5380_read(CURRENT_SCSI_DATA_REG); 13221da177e4SLinus Torvalds 13231da177e4SLinus Torvalds ++d; 13241da177e4SLinus Torvalds 13251da177e4SLinus Torvalds /* 13261da177e4SLinus Torvalds * The SCSI standard suggests that in MSGOUT phase, the initiator 13271da177e4SLinus Torvalds * should drop ATN on the last byte of the message phase 13281da177e4SLinus Torvalds * after REQ has been asserted for the handshake but before 13291da177e4SLinus Torvalds * the initiator raises ACK. 13301da177e4SLinus Torvalds */ 13311da177e4SLinus Torvalds 13321da177e4SLinus Torvalds if (!(p & SR_IO)) { 13331da177e4SLinus Torvalds if (!((p & SR_MSG) && c > 1)) { 13341da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 13351da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 13361da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK); 13371da177e4SLinus Torvalds } else { 13381da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN); 13391da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 13401da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 13411da177e4SLinus Torvalds } 13421da177e4SLinus Torvalds } else { 13431da177e4SLinus Torvalds NCR5380_dprint(NDEBUG_PIO, instance); 13441da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); 13451da177e4SLinus Torvalds } 13461da177e4SLinus Torvalds 1347a2edc4a6SFinn Thain if (NCR5380_poll_politely(instance, 1348a2edc4a6SFinn Thain STATUS_REG, SR_REQ, 0, 5 * HZ) < 0) 1349a2edc4a6SFinn Thain break; 1350a2edc4a6SFinn Thain 1351b746545fSFinn Thain dsprintk(NDEBUG_HANDSHAKE, instance, "REQ negated, handshake complete\n"); 13521da177e4SLinus Torvalds 13531da177e4SLinus Torvalds /* 13541da177e4SLinus Torvalds * We have several special cases to consider during REQ/ACK handshaking : 13551da177e4SLinus Torvalds * 1. We were in MSGOUT phase, and we are on the last byte of the 13561da177e4SLinus Torvalds * message. ATN must be dropped as ACK is dropped. 13571da177e4SLinus Torvalds * 13581da177e4SLinus Torvalds * 2. We are in a MSGIN phase, and we are on the last byte of the 13591da177e4SLinus Torvalds * message. We must exit with ACK asserted, so that the calling 13601da177e4SLinus Torvalds * code may raise ATN before dropping ACK to reject the message. 13611da177e4SLinus Torvalds * 13621da177e4SLinus Torvalds * 3. ACK and ATN are clear and the target may proceed as normal. 13631da177e4SLinus Torvalds */ 13641da177e4SLinus Torvalds if (!(p == PHASE_MSGIN && c == 1)) { 13651da177e4SLinus Torvalds if (p == PHASE_MSGOUT && c > 1) 13661da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 13671da177e4SLinus Torvalds else 13681da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 13691da177e4SLinus Torvalds } 13701da177e4SLinus Torvalds } while (--c); 13711da177e4SLinus Torvalds 1372b746545fSFinn Thain dsprintk(NDEBUG_PIO, instance, "residual %d\n", c); 13731da177e4SLinus Torvalds 13741da177e4SLinus Torvalds *count = c; 13751da177e4SLinus Torvalds *data = d; 13761da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 1377a2edc4a6SFinn Thain /* The phase read from the bus is valid if either REQ is (already) 1378a2edc4a6SFinn Thain * asserted or if ACK hasn't been released yet. The latter applies if 1379a2edc4a6SFinn Thain * we're in MSG IN, DATA IN or STATUS and all bytes have been received. 1380a2edc4a6SFinn Thain */ 1381a2edc4a6SFinn Thain if ((tmp & SR_REQ) || ((tmp & SR_IO) && c == 0)) 13821da177e4SLinus Torvalds *phase = tmp & PHASE_MASK; 13831da177e4SLinus Torvalds else 13841da177e4SLinus Torvalds *phase = PHASE_UNKNOWN; 13851da177e4SLinus Torvalds 13861da177e4SLinus Torvalds if (!c || (*phase == p)) 13871da177e4SLinus Torvalds return 0; 13881da177e4SLinus Torvalds else 13891da177e4SLinus Torvalds return -1; 13901da177e4SLinus Torvalds } 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds /** 13931da177e4SLinus Torvalds * do_reset - issue a reset command 1394636b1ec8SFinn Thain * @instance: adapter to reset 13951da177e4SLinus Torvalds * 13961da177e4SLinus Torvalds * Issue a reset sequence to the NCR5380 and try and get the bus 13971da177e4SLinus Torvalds * back into sane shape. 13981da177e4SLinus Torvalds * 1399636b1ec8SFinn Thain * This clears the reset interrupt flag because there may be no handler for 1400636b1ec8SFinn Thain * it. When the driver is initialized, the NCR5380_intr() handler has not yet 1401636b1ec8SFinn Thain * been installed. And when in EH we may have released the ST DMA interrupt. 14021da177e4SLinus Torvalds */ 14031da177e4SLinus Torvalds 140454d8fe44SFinn Thain static void do_reset(struct Scsi_Host *instance) 140554d8fe44SFinn Thain { 1406636b1ec8SFinn Thain unsigned long flags; 1407636b1ec8SFinn Thain 1408636b1ec8SFinn Thain local_irq_save(flags); 1409636b1ec8SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 1410636b1ec8SFinn Thain PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); 14111da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); 1412636b1ec8SFinn Thain udelay(50); 14131da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 1414636b1ec8SFinn Thain (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); 1415636b1ec8SFinn Thain local_irq_restore(flags); 14161da177e4SLinus Torvalds } 14171da177e4SLinus Torvalds 141880d3eb6dSFinn Thain /** 141980d3eb6dSFinn Thain * do_abort - abort the currently established nexus by going to 142080d3eb6dSFinn Thain * MESSAGE OUT phase and sending an ABORT message. 142180d3eb6dSFinn Thain * @instance: relevant scsi host instance 14221da177e4SLinus Torvalds * 142380d3eb6dSFinn Thain * Returns 0 on success, -1 on failure. 14241da177e4SLinus Torvalds */ 14251da177e4SLinus Torvalds 142654d8fe44SFinn Thain static int do_abort(struct Scsi_Host *instance) 142754d8fe44SFinn Thain { 14281da177e4SLinus Torvalds unsigned char *msgptr, phase, tmp; 14291da177e4SLinus Torvalds int len; 14301da177e4SLinus Torvalds int rc; 14311da177e4SLinus Torvalds 14321da177e4SLinus Torvalds /* Request message out phase */ 14331da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 14341da177e4SLinus Torvalds 14351da177e4SLinus Torvalds /* 14361da177e4SLinus Torvalds * Wait for the target to indicate a valid phase by asserting 14371da177e4SLinus Torvalds * REQ. Once this happens, we'll have either a MSGOUT phase 14381da177e4SLinus Torvalds * and can immediately send the ABORT message, or we'll have some 14391da177e4SLinus Torvalds * other phase and will have to source/sink data. 14401da177e4SLinus Torvalds * 14411da177e4SLinus Torvalds * We really don't care what value was on the bus or what value 14421da177e4SLinus Torvalds * the target sees, so we just handshake. 14431da177e4SLinus Torvalds */ 14441da177e4SLinus Torvalds 144580d3eb6dSFinn Thain rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ); 14461da177e4SLinus Torvalds if (rc < 0) 144780d3eb6dSFinn Thain goto timeout; 14481da177e4SLinus Torvalds 1449f35d3474SFinn Thain tmp = NCR5380_read(STATUS_REG) & PHASE_MASK; 14501da177e4SLinus Torvalds 14511da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 14521da177e4SLinus Torvalds 1453f35d3474SFinn Thain if (tmp != PHASE_MSGOUT) { 14541da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 145554d8fe44SFinn Thain rc = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 3 * HZ); 14561cc160e1SFinn Thain if (rc < 0) 145780d3eb6dSFinn Thain goto timeout; 145880d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 14591da177e4SLinus Torvalds } 14601da177e4SLinus Torvalds tmp = ABORT; 14611da177e4SLinus Torvalds msgptr = &tmp; 14621da177e4SLinus Torvalds len = 1; 14631da177e4SLinus Torvalds phase = PHASE_MSGOUT; 146454d8fe44SFinn Thain NCR5380_transfer_pio(instance, &phase, &len, &msgptr); 14651da177e4SLinus Torvalds 14661da177e4SLinus Torvalds /* 14671da177e4SLinus Torvalds * If we got here, and the command completed successfully, 14681da177e4SLinus Torvalds * we're about to go into bus free state. 14691da177e4SLinus Torvalds */ 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds return len ? -1 : 0; 147280d3eb6dSFinn Thain 147380d3eb6dSFinn Thain timeout: 147480d3eb6dSFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 147580d3eb6dSFinn Thain return -1; 14761da177e4SLinus Torvalds } 14771da177e4SLinus Torvalds 14781da177e4SLinus Torvalds #if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL) 14791da177e4SLinus Torvalds /* 14801da177e4SLinus Torvalds * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 14811da177e4SLinus Torvalds * unsigned char *phase, int *count, unsigned char **data) 14821da177e4SLinus Torvalds * 14831da177e4SLinus Torvalds * Purpose : transfers data in given phase using either real 14841da177e4SLinus Torvalds * or pseudo DMA. 14851da177e4SLinus Torvalds * 14861da177e4SLinus Torvalds * Inputs : instance - instance of driver, *phase - pointer to 14871da177e4SLinus Torvalds * what phase is expected, *count - pointer to number of 14881da177e4SLinus Torvalds * bytes to transfer, **data - pointer to data pointer. 14891da177e4SLinus Torvalds * 14901da177e4SLinus Torvalds * Returns : -1 when different phase is entered without transferring 149125985edcSLucas De Marchi * maximum number of bytes, 0 if all bytes or transferred or exit 14921da177e4SLinus Torvalds * is in same phase. 14931da177e4SLinus Torvalds * 14941da177e4SLinus Torvalds * Also, *phase, *count, *data are modified in place. 14951da177e4SLinus Torvalds */ 14961da177e4SLinus Torvalds 14971da177e4SLinus Torvalds 14981da177e4SLinus Torvalds static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { 14991da177e4SLinus Torvalds register int c = *count; 15001da177e4SLinus Torvalds register unsigned char p = *phase; 15011da177e4SLinus Torvalds register unsigned char *d = *data; 15021da177e4SLinus Torvalds unsigned char tmp; 15031da177e4SLinus Torvalds int foo; 15041da177e4SLinus Torvalds #if defined(REAL_DMA_POLL) 15051da177e4SLinus Torvalds int cnt, toPIO; 15061da177e4SLinus Torvalds unsigned char saved_data = 0, overrun = 0, residue; 15071da177e4SLinus Torvalds #endif 15081da177e4SLinus Torvalds 1509e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 15101da177e4SLinus Torvalds 15111da177e4SLinus Torvalds if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { 15121da177e4SLinus Torvalds *phase = tmp; 15131da177e4SLinus Torvalds return -1; 15141da177e4SLinus Torvalds } 15151da177e4SLinus Torvalds #if defined(REAL_DMA) || defined(REAL_DMA_POLL) 15161da177e4SLinus Torvalds if (p & SR_IO) { 15179db6024eSFinn Thain if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS)) 15181da177e4SLinus Torvalds c -= 2; 15191da177e4SLinus Torvalds } 15201da177e4SLinus Torvalds hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); 1521b746545fSFinn Thain 1522b746545fSFinn Thain dsprintk(NDEBUG_DMA, instance, "initializing DMA %s: length %d, address %p\n", 1523b746545fSFinn Thain (p & SR_IO) ? "receive" : "send", c, *data); 15241da177e4SLinus Torvalds #endif 15251da177e4SLinus Torvalds 15261da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); 15271da177e4SLinus Torvalds 15281da177e4SLinus Torvalds #ifdef REAL_DMA 1529cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY | 1530cd400825SFinn Thain MR_ENABLE_EOP_INTR); 15311da177e4SLinus Torvalds #elif defined(REAL_DMA_POLL) 1532cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY); 15331da177e4SLinus Torvalds #else 15341da177e4SLinus Torvalds /* 15351da177e4SLinus Torvalds * Note : on my sample board, watch-dog timeouts occurred when interrupts 15361da177e4SLinus Torvalds * were not disabled for the duration of a single DMA transfer, from 15371da177e4SLinus Torvalds * before the setting of DMA mode to after transfer of the last byte. 15381da177e4SLinus Torvalds */ 15391da177e4SLinus Torvalds 154055181be8SFinn Thain if (hostdata->flags & FLAG_NO_DMA_FIXUP) 1541cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY | 1542cd400825SFinn Thain MR_ENABLE_EOP_INTR); 15431da177e4SLinus Torvalds else 1544cd400825SFinn Thain NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_MONITOR_BSY); 15451da177e4SLinus Torvalds #endif /* def REAL_DMA */ 15461da177e4SLinus Torvalds 154752a6a1cbSFinn Thain dprintk(NDEBUG_DMA, "scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); 15481da177e4SLinus Torvalds 15491da177e4SLinus Torvalds /* 15501da177e4SLinus Torvalds * On the PAS16 at least I/O recovery delays are not needed here. 15511da177e4SLinus Torvalds * Everyone else seems to want them. 15521da177e4SLinus Torvalds */ 15531da177e4SLinus Torvalds 15541da177e4SLinus Torvalds if (p & SR_IO) { 15551da177e4SLinus Torvalds io_recovery_delay(1); 15561da177e4SLinus Torvalds NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); 15571da177e4SLinus Torvalds } else { 15581da177e4SLinus Torvalds io_recovery_delay(1); 15591da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); 15601da177e4SLinus Torvalds io_recovery_delay(1); 15611da177e4SLinus Torvalds NCR5380_write(START_DMA_SEND_REG, 0); 15621da177e4SLinus Torvalds io_recovery_delay(1); 15631da177e4SLinus Torvalds } 15641da177e4SLinus Torvalds 15651da177e4SLinus Torvalds #if defined(REAL_DMA_POLL) 15661da177e4SLinus Torvalds do { 15671da177e4SLinus Torvalds tmp = NCR5380_read(BUS_AND_STATUS_REG); 15681da177e4SLinus Torvalds } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER))); 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds /* 1571*c16df32eSFinn Thain * At this point, either we've completed DMA, or we have a phase mismatch, 1572*c16df32eSFinn Thain * or we've unexpectedly lost BUSY (which is a real error). 1573*c16df32eSFinn Thain * 1574*c16df32eSFinn Thain * For DMA sends, we want to wait until the last byte has been 1575*c16df32eSFinn Thain * transferred out over the bus before we turn off DMA mode. Alas, there 1576*c16df32eSFinn Thain * seems to be no terribly good way of doing this on a 5380 under all 1577*c16df32eSFinn Thain * conditions. For non-scatter-gather operations, we can wait until REQ 1578*c16df32eSFinn Thain * and ACK both go false, or until a phase mismatch occurs. Gather-sends 1579*c16df32eSFinn Thain * are nastier, since the device will be expecting more data than we 1580*c16df32eSFinn Thain * are prepared to send it, and REQ will remain asserted. On a 53C8[01] we 1581*c16df32eSFinn Thain * could test Last Byte Sent to assure transfer (I imagine this is precisely 1582*c16df32eSFinn Thain * why this signal was added to the newer chips) but on the older 538[01] 1583*c16df32eSFinn Thain * this signal does not exist. The workaround for this lack is a watchdog; 1584*c16df32eSFinn Thain * we bail out of the wait-loop after a modest amount of wait-time if 1585*c16df32eSFinn Thain * the usual exit conditions are not met. Not a terribly clean or 1586*c16df32eSFinn Thain * correct solution :-% 1587*c16df32eSFinn Thain * 1588*c16df32eSFinn Thain * DMA receive is equally tricky due to a nasty characteristic of the NCR5380. 1589*c16df32eSFinn Thain * If the chip is in DMA receive mode, it will respond to a target's 1590*c16df32eSFinn Thain * REQ by latching the SCSI data into the INPUT DATA register and asserting 1591*c16df32eSFinn Thain * ACK, even if it has _already_ been notified by the DMA controller that 1592*c16df32eSFinn Thain * the current DMA transfer has completed! If the NCR5380 is then taken 1593*c16df32eSFinn Thain * out of DMA mode, this already-acknowledged byte is lost. This is 1594*c16df32eSFinn Thain * not a problem for "one DMA transfer per READ command", because 1595*c16df32eSFinn Thain * the situation will never arise... either all of the data is DMA'ed 1596*c16df32eSFinn Thain * properly, or the target switches to MESSAGE IN phase to signal a 1597*c16df32eSFinn Thain * disconnection (either operation bringing the DMA to a clean halt). 1598*c16df32eSFinn Thain * However, in order to handle scatter-receive, we must work around the 1599*c16df32eSFinn Thain * problem. The chosen fix is to DMA N-2 bytes, then check for the 1600*c16df32eSFinn Thain * condition before taking the NCR5380 out of DMA mode. One or two extra 1601*c16df32eSFinn Thain * bytes are transferred via PIO as necessary to fill out the original 1602*c16df32eSFinn Thain * request. 16031da177e4SLinus Torvalds */ 16041da177e4SLinus Torvalds 16051da177e4SLinus Torvalds if (p & SR_IO) { 16069db6024eSFinn Thain if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS)) { 16071da177e4SLinus Torvalds udelay(10); 16089db6024eSFinn Thain if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == 16099db6024eSFinn Thain (BASR_PHASE_MATCH | BASR_ACK)) { 16101da177e4SLinus Torvalds saved_data = NCR5380_read(INPUT_DATA_REGISTER); 16111da177e4SLinus Torvalds overrun = 1; 16121da177e4SLinus Torvalds } 16139db6024eSFinn Thain } 16141da177e4SLinus Torvalds } else { 16151da177e4SLinus Torvalds int limit = 100; 16161da177e4SLinus Torvalds while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) { 16171da177e4SLinus Torvalds if (!(tmp & BASR_PHASE_MATCH)) 16181da177e4SLinus Torvalds break; 16191da177e4SLinus Torvalds if (--limit < 0) 16201da177e4SLinus Torvalds break; 16211da177e4SLinus Torvalds } 16221da177e4SLinus Torvalds } 16231da177e4SLinus Torvalds 1624b746545fSFinn Thain dsprintk(NDEBUG_DMA, "polled DMA transfer complete, basr 0x%02x, sr 0x%02x\n", 1625b746545fSFinn Thain tmp, NCR5380_read(STATUS_REG)); 16261da177e4SLinus Torvalds 16271da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 16281da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 16291da177e4SLinus Torvalds 16301da177e4SLinus Torvalds residue = NCR5380_dma_residual(instance); 16311da177e4SLinus Torvalds c -= residue; 16321da177e4SLinus Torvalds *count -= c; 16331da177e4SLinus Torvalds *data += c; 16341da177e4SLinus Torvalds *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; 16351da177e4SLinus Torvalds 16369db6024eSFinn Thain if (!(hostdata->flags & FLAG_NO_DMA_FIXUPS) && 16379db6024eSFinn Thain *phase == p && (p & SR_IO) && residue == 0) { 16381da177e4SLinus Torvalds if (overrun) { 163952a6a1cbSFinn Thain dprintk(NDEBUG_DMA, "Got an input overrun, using saved byte\n"); 16401da177e4SLinus Torvalds **data = saved_data; 16411da177e4SLinus Torvalds *data += 1; 16421da177e4SLinus Torvalds *count -= 1; 16431da177e4SLinus Torvalds cnt = toPIO = 1; 16441da177e4SLinus Torvalds } else { 16451da177e4SLinus Torvalds printk("No overrun??\n"); 16461da177e4SLinus Torvalds cnt = toPIO = 2; 16471da177e4SLinus Torvalds } 164852a6a1cbSFinn Thain dprintk(NDEBUG_DMA, "Doing %d-byte PIO to 0x%X\n", cnt, *data); 16491da177e4SLinus Torvalds NCR5380_transfer_pio(instance, phase, &cnt, data); 16501da177e4SLinus Torvalds *count -= toPIO - cnt; 16511da177e4SLinus Torvalds } 16521da177e4SLinus Torvalds 165352a6a1cbSFinn Thain dprintk(NDEBUG_DMA, "Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count)); 16541da177e4SLinus Torvalds return 0; 16551da177e4SLinus Torvalds 16561da177e4SLinus Torvalds #elif defined(REAL_DMA) 16571da177e4SLinus Torvalds return 0; 16581da177e4SLinus Torvalds #else /* defined(REAL_DMA_POLL) */ 16591da177e4SLinus Torvalds if (p & SR_IO) { 166055181be8SFinn Thain foo = NCR5380_pread(instance, d, 166155181be8SFinn Thain hostdata->flags & FLAG_NO_DMA_FIXUP ? c : c - 1); 166255181be8SFinn Thain if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) { 16631da177e4SLinus Torvalds /* 16641da177e4SLinus Torvalds * We can't disable DMA mode after successfully transferring 16651da177e4SLinus Torvalds * what we plan to be the last byte, since that would open up 16661da177e4SLinus Torvalds * a race condition where if the target asserted REQ before 16671da177e4SLinus Torvalds * we got the DMA mode reset, the NCR5380 would have latched 16681da177e4SLinus Torvalds * an additional byte into the INPUT DATA register and we'd 16691da177e4SLinus Torvalds * have dropped it. 16701da177e4SLinus Torvalds * 16711da177e4SLinus Torvalds * The workaround was to transfer one fewer bytes than we 16721da177e4SLinus Torvalds * intended to with the pseudo-DMA read function, wait for 16731da177e4SLinus Torvalds * the chip to latch the last byte, read it, and then disable 16741da177e4SLinus Torvalds * pseudo-DMA mode. 16751da177e4SLinus Torvalds * 16761da177e4SLinus Torvalds * After REQ is asserted, the NCR5380 asserts DRQ and ACK. 16771da177e4SLinus Torvalds * REQ is deasserted when ACK is asserted, and not reasserted 16781da177e4SLinus Torvalds * until ACK goes false. Since the NCR5380 won't lower ACK 16791da177e4SLinus Torvalds * until DACK is asserted, which won't happen unless we twiddle 16801da177e4SLinus Torvalds * the DMA port or we take the NCR5380 out of DMA mode, we 16811da177e4SLinus Torvalds * can guarantee that we won't handshake another extra 16821da177e4SLinus Torvalds * byte. 16831da177e4SLinus Torvalds */ 16841da177e4SLinus Torvalds 168555181be8SFinn Thain if (NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, 168655181be8SFinn Thain BASR_DRQ, BASR_DRQ, HZ) < 0) { 168755181be8SFinn Thain foo = -1; 168855181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA read: DRQ timeout\n"); 168955181be8SFinn Thain } 169055181be8SFinn Thain if (NCR5380_poll_politely(instance, STATUS_REG, 169155181be8SFinn Thain SR_REQ, 0, HZ) < 0) { 169255181be8SFinn Thain foo = -1; 169355181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA read: !REQ timeout\n"); 169455181be8SFinn Thain } 16951da177e4SLinus Torvalds d[c - 1] = NCR5380_read(INPUT_DATA_REG); 16961da177e4SLinus Torvalds } 16971da177e4SLinus Torvalds } else { 16981da177e4SLinus Torvalds foo = NCR5380_pwrite(instance, d, c); 169955181be8SFinn Thain if (!foo && !(hostdata->flags & FLAG_NO_DMA_FIXUP)) { 17001da177e4SLinus Torvalds /* 17011da177e4SLinus Torvalds * Wait for the last byte to be sent. If REQ is being asserted for 17021da177e4SLinus Torvalds * the byte we're interested, we'll ACK it and it will go false. 17031da177e4SLinus Torvalds */ 170455181be8SFinn Thain if (NCR5380_poll_politely2(instance, 170555181be8SFinn Thain BUS_AND_STATUS_REG, BASR_DRQ, BASR_DRQ, 170655181be8SFinn Thain BUS_AND_STATUS_REG, BASR_PHASE_MATCH, 0, HZ) < 0) { 170755181be8SFinn Thain foo = -1; 170855181be8SFinn Thain shost_printk(KERN_ERR, instance, "PDMA write: DRQ and phase timeout\n"); 17091da177e4SLinus Torvalds } 17101da177e4SLinus Torvalds } 17111da177e4SLinus Torvalds } 17121da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 17131da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 17141da177e4SLinus Torvalds NCR5380_read(RESET_PARITY_INTERRUPT_REG); 17151da177e4SLinus Torvalds *data = d + c; 17161da177e4SLinus Torvalds *count = 0; 17171da177e4SLinus Torvalds *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; 17181da177e4SLinus Torvalds return foo; 17191da177e4SLinus Torvalds #endif /* def REAL_DMA */ 17201da177e4SLinus Torvalds } 17211da177e4SLinus Torvalds #endif /* defined(REAL_DMA) | defined(PSEUDO_DMA) */ 17221da177e4SLinus Torvalds 17231da177e4SLinus Torvalds /* 17241da177e4SLinus Torvalds * Function : NCR5380_information_transfer (struct Scsi_Host *instance) 17251da177e4SLinus Torvalds * 17261da177e4SLinus Torvalds * Purpose : run through the various SCSI phases and do as the target 17271da177e4SLinus Torvalds * directs us to. Operates on the currently connected command, 17281da177e4SLinus Torvalds * instance->connected. 17291da177e4SLinus Torvalds * 17301da177e4SLinus Torvalds * Inputs : instance, instance for which we are doing commands 17311da177e4SLinus Torvalds * 17321da177e4SLinus Torvalds * Side effects : SCSI things happen, the disconnected queue will be 17331da177e4SLinus Torvalds * modified if a command disconnects, *instance->connected will 17341da177e4SLinus Torvalds * change. 17351da177e4SLinus Torvalds * 17361da177e4SLinus Torvalds * XXX Note : we need to watch for bus free or a reset condition here 17371da177e4SLinus Torvalds * to recover from an unexpected bus free condition. 17381da177e4SLinus Torvalds */ 17391da177e4SLinus Torvalds 17401da177e4SLinus Torvalds static void NCR5380_information_transfer(struct Scsi_Host *instance) { 1741e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 17421da177e4SLinus Torvalds unsigned char msgout = NOP; 17431da177e4SLinus Torvalds int sink = 0; 17441da177e4SLinus Torvalds int len; 17451da177e4SLinus Torvalds #if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) 17461da177e4SLinus Torvalds int transfersize; 17471da177e4SLinus Torvalds #endif 17481da177e4SLinus Torvalds unsigned char *data; 17491da177e4SLinus Torvalds unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; 175011d2f63bSFinn Thain struct scsi_cmnd *cmd; 17511da177e4SLinus Torvalds 175211d2f63bSFinn Thain while ((cmd = hostdata->connected)) { 175332b26a10SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 175432b26a10SFinn Thain 17551da177e4SLinus Torvalds tmp = NCR5380_read(STATUS_REG); 17561da177e4SLinus Torvalds /* We only have a valid SCSI phase when REQ is asserted */ 17571da177e4SLinus Torvalds if (tmp & SR_REQ) { 17581da177e4SLinus Torvalds phase = (tmp & PHASE_MASK); 17591da177e4SLinus Torvalds if (phase != old_phase) { 17601da177e4SLinus Torvalds old_phase = phase; 17611da177e4SLinus Torvalds NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); 17621da177e4SLinus Torvalds } 17631da177e4SLinus Torvalds if (sink && (phase != PHASE_MSGOUT)) { 17641da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); 17651da177e4SLinus Torvalds 17661da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); 17671da177e4SLinus Torvalds while (NCR5380_read(STATUS_REG) & SR_REQ); 17681da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 17691da177e4SLinus Torvalds sink = 0; 17701da177e4SLinus Torvalds continue; 17711da177e4SLinus Torvalds } 17721da177e4SLinus Torvalds switch (phase) { 17731da177e4SLinus Torvalds case PHASE_DATAOUT: 17741da177e4SLinus Torvalds #if (NDEBUG & NDEBUG_NO_DATAOUT) 17756a6ff4acSFinn Thain shost_printk(KERN_DEBUG, instance, "NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n"); 17761da177e4SLinus Torvalds sink = 1; 17771da177e4SLinus Torvalds do_abort(instance); 17781da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 1779677e0194SFinn Thain complete_cmd(instance, cmd); 17801da177e4SLinus Torvalds return; 17811da177e4SLinus Torvalds #endif 1782bf1a0c6fSFinn Thain case PHASE_DATAIN: 17831da177e4SLinus Torvalds /* 17841da177e4SLinus Torvalds * If there is no room left in the current buffer in the 17851da177e4SLinus Torvalds * scatter-gather list, move onto the next one. 17861da177e4SLinus Torvalds */ 17871da177e4SLinus Torvalds 17881da177e4SLinus Torvalds if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { 17891da177e4SLinus Torvalds ++cmd->SCp.buffer; 17901da177e4SLinus Torvalds --cmd->SCp.buffers_residual; 17911da177e4SLinus Torvalds cmd->SCp.this_residual = cmd->SCp.buffer->length; 179245711f1aSJens Axboe cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); 1793b746545fSFinn Thain dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n", 1794b746545fSFinn Thain cmd->SCp.this_residual, 1795b746545fSFinn Thain cmd->SCp.buffers_residual); 17961da177e4SLinus Torvalds } 17971da177e4SLinus Torvalds /* 17981da177e4SLinus Torvalds * The preferred transfer method is going to be 17991da177e4SLinus Torvalds * PSEUDO-DMA for systems that are strictly PIO, 18001da177e4SLinus Torvalds * since we can let the hardware do the handshaking. 18011da177e4SLinus Torvalds * 18021da177e4SLinus Torvalds * For this to work, we need to know the transfersize 18031da177e4SLinus Torvalds * ahead of time, since the pseudo-DMA code will sit 18041da177e4SLinus Torvalds * in an unconditional loop. 18051da177e4SLinus Torvalds */ 18061da177e4SLinus Torvalds 18071da177e4SLinus Torvalds #if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) 1808ff3d4578SFinn Thain transfersize = 0; 1809ff3d4578SFinn Thain if (!cmd->device->borken && 1810ff3d4578SFinn Thain !(hostdata->flags & FLAG_NO_PSEUDO_DMA)) 1811ff3d4578SFinn Thain transfersize = NCR5380_dma_xfer_len(instance, cmd, phase); 18121da177e4SLinus Torvalds 1813ff3d4578SFinn Thain if (transfersize) { 18141da177e4SLinus Torvalds len = transfersize; 18151da177e4SLinus Torvalds if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) { 18161da177e4SLinus Torvalds /* 18171da177e4SLinus Torvalds * If the watchdog timer fires, all future accesses to this 18181da177e4SLinus Torvalds * device will use the polled-IO. 18191da177e4SLinus Torvalds */ 1820017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 1821017560fcSJeff Garzik "switching to slow handshake\n"); 18221da177e4SLinus Torvalds cmd->device->borken = 1; 18231da177e4SLinus Torvalds sink = 1; 18241da177e4SLinus Torvalds do_abort(instance); 18251da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 1826677e0194SFinn Thain complete_cmd(instance, cmd); 18271da177e4SLinus Torvalds /* XXX - need to source or sink data here, as appropriate */ 18281da177e4SLinus Torvalds } else 18291da177e4SLinus Torvalds cmd->SCp.this_residual -= transfersize - len; 18301da177e4SLinus Torvalds } else 18311da177e4SLinus Torvalds #endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */ 183211d2f63bSFinn Thain { 183311d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 18341da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **) 18351da177e4SLinus Torvalds &cmd->SCp.ptr); 183611d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 183711d2f63bSFinn Thain } 18381da177e4SLinus Torvalds break; 18391da177e4SLinus Torvalds case PHASE_MSGIN: 18401da177e4SLinus Torvalds len = 1; 18411da177e4SLinus Torvalds data = &tmp; 18421da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 18431da177e4SLinus Torvalds cmd->SCp.Message = tmp; 18441da177e4SLinus Torvalds 18451da177e4SLinus Torvalds switch (tmp) { 18461da177e4SLinus Torvalds case ABORT: 18471da177e4SLinus Torvalds case COMMAND_COMPLETE: 18481da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18491da177e4SLinus Torvalds sink = 1; 18501da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18510d3d9a42SFinn Thain dsprintk(NDEBUG_QUEUES, instance, 18520d3d9a42SFinn Thain "COMMAND COMPLETE %p target %d lun %llu\n", 18530d3d9a42SFinn Thain cmd, scmd_id(cmd), cmd->device->lun); 18540d3d9a42SFinn Thain 18551da177e4SLinus Torvalds hostdata->connected = NULL; 18561da177e4SLinus Torvalds 1857f27db8ebSFinn Thain cmd->result &= ~0xffff; 1858f27db8ebSFinn Thain cmd->result |= cmd->SCp.Status; 1859f27db8ebSFinn Thain cmd->result |= cmd->SCp.Message << 8; 18601da177e4SLinus Torvalds 1861f27db8ebSFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 1862f27db8ebSFinn Thain complete_cmd(instance, cmd); 1863f27db8ebSFinn Thain else { 1864f27db8ebSFinn Thain if (cmd->SCp.Status == SAM_STAT_CHECK_CONDITION || 1865f27db8ebSFinn Thain cmd->SCp.Status == SAM_STAT_COMMAND_TERMINATED) { 1866f27db8ebSFinn Thain dsprintk(NDEBUG_QUEUES, instance, "autosense: adding cmd %p to tail of autosense queue\n", 1867dbb6b350SFinn Thain cmd); 1868f27db8ebSFinn Thain list_add_tail(&ncmd->list, 1869f27db8ebSFinn Thain &hostdata->autosense); 1870f27db8ebSFinn Thain } else 1871677e0194SFinn Thain complete_cmd(instance, cmd); 18721da177e4SLinus Torvalds } 18731da177e4SLinus Torvalds 18741da177e4SLinus Torvalds /* 18751da177e4SLinus Torvalds * Restore phase bits to 0 so an interrupted selection, 18761da177e4SLinus Torvalds * arbitration can resume. 18771da177e4SLinus Torvalds */ 18781da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 187972064a78SFinn Thain 188072064a78SFinn Thain /* Enable reselect interrupts */ 188172064a78SFinn Thain NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 18821da177e4SLinus Torvalds return; 18831da177e4SLinus Torvalds case MESSAGE_REJECT: 18841da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18851da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 18861da177e4SLinus Torvalds switch (hostdata->last_message) { 18871da177e4SLinus Torvalds case HEAD_OF_QUEUE_TAG: 18881da177e4SLinus Torvalds case ORDERED_QUEUE_TAG: 18891da177e4SLinus Torvalds case SIMPLE_QUEUE_TAG: 18901da177e4SLinus Torvalds cmd->device->simple_tags = 0; 18919cb78c16SHannes Reinecke hostdata->busy[cmd->device->id] |= (1 << (cmd->device->lun & 0xFF)); 18921da177e4SLinus Torvalds break; 18931da177e4SLinus Torvalds default: 18941da177e4SLinus Torvalds break; 18951da177e4SLinus Torvalds } 1896340b9612SFinn Thain break; 18971da177e4SLinus Torvalds case DISCONNECT:{ 18981da177e4SLinus Torvalds /* Accept message by clearing ACK */ 18991da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 19001da177e4SLinus Torvalds hostdata->connected = NULL; 190132b26a10SFinn Thain list_add(&ncmd->list, &hostdata->disconnected); 19020d3d9a42SFinn Thain dsprintk(NDEBUG_INFORMATION | NDEBUG_QUEUES, 19030d3d9a42SFinn Thain instance, "connected command %p for target %d lun %llu moved to disconnected queue\n", 19040d3d9a42SFinn Thain cmd, scmd_id(cmd), cmd->device->lun); 19050d3d9a42SFinn Thain 19061da177e4SLinus Torvalds /* 19071da177e4SLinus Torvalds * Restore phase bits to 0 so an interrupted selection, 19081da177e4SLinus Torvalds * arbitration can resume. 19091da177e4SLinus Torvalds */ 19101da177e4SLinus Torvalds NCR5380_write(TARGET_COMMAND_REG, 0); 19111da177e4SLinus Torvalds 19121da177e4SLinus Torvalds /* Enable reselect interrupts */ 19131da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 19141da177e4SLinus Torvalds return; 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds /* 19171da177e4SLinus Torvalds * The SCSI data pointer is *IMPLICITLY* saved on a disconnect 19181da177e4SLinus Torvalds * operation, in violation of the SCSI spec so we can safely 19191da177e4SLinus Torvalds * ignore SAVE/RESTORE pointers calls. 19201da177e4SLinus Torvalds * 19211da177e4SLinus Torvalds * Unfortunately, some disks violate the SCSI spec and 19221da177e4SLinus Torvalds * don't issue the required SAVE_POINTERS message before 19231da177e4SLinus Torvalds * disconnecting, and we have to break spec to remain 19241da177e4SLinus Torvalds * compatible. 19251da177e4SLinus Torvalds */ 19261da177e4SLinus Torvalds case SAVE_POINTERS: 19271da177e4SLinus Torvalds case RESTORE_POINTERS: 19281da177e4SLinus Torvalds /* Accept message by clearing ACK */ 19291da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 19301da177e4SLinus Torvalds break; 19311da177e4SLinus Torvalds case EXTENDED_MESSAGE: 19321da177e4SLinus Torvalds /* 1933*c16df32eSFinn Thain * Start the message buffer with the EXTENDED_MESSAGE 19341abfd370SMatthew Wilcox * byte, since spi_print_msg() wants the whole thing. 19351da177e4SLinus Torvalds */ 19361da177e4SLinus Torvalds extended_msg[0] = EXTENDED_MESSAGE; 19371da177e4SLinus Torvalds /* Accept first byte by clearing ACK */ 19381da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 193911d2f63bSFinn Thain 194011d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 194111d2f63bSFinn Thain 1942b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "receiving extended message\n"); 19431da177e4SLinus Torvalds 19441da177e4SLinus Torvalds len = 2; 19451da177e4SLinus Torvalds data = extended_msg + 1; 19461da177e4SLinus Torvalds phase = PHASE_MSGIN; 19471da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 1948b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "length %d, code 0x%02x\n", 1949b746545fSFinn Thain (int)extended_msg[1], 1950b746545fSFinn Thain (int)extended_msg[2]); 19511da177e4SLinus Torvalds 1952e0783ed3SFinn Thain if (!len && extended_msg[1] > 0 && 1953e0783ed3SFinn Thain extended_msg[1] <= sizeof(extended_msg) - 2) { 19541da177e4SLinus Torvalds /* Accept third byte by clearing ACK */ 19551da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 19561da177e4SLinus Torvalds len = extended_msg[1] - 1; 19571da177e4SLinus Torvalds data = extended_msg + 3; 19581da177e4SLinus Torvalds phase = PHASE_MSGIN; 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 1961b746545fSFinn Thain dsprintk(NDEBUG_EXTENDED, instance, "message received, residual %d\n", 1962b746545fSFinn Thain len); 19631da177e4SLinus Torvalds 19641da177e4SLinus Torvalds switch (extended_msg[2]) { 19651da177e4SLinus Torvalds case EXTENDED_SDTR: 19661da177e4SLinus Torvalds case EXTENDED_WDTR: 19671da177e4SLinus Torvalds case EXTENDED_MODIFY_DATA_POINTER: 19681da177e4SLinus Torvalds case EXTENDED_EXTENDED_IDENTIFY: 19691da177e4SLinus Torvalds tmp = 0; 19701da177e4SLinus Torvalds } 19711da177e4SLinus Torvalds } else if (len) { 19726a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "error receiving extended message\n"); 19731da177e4SLinus Torvalds tmp = 0; 19741da177e4SLinus Torvalds } else { 19756a6ff4acSFinn Thain shost_printk(KERN_NOTICE, instance, "extended message code %02x length %d is too long\n", 19766a6ff4acSFinn Thain extended_msg[2], extended_msg[1]); 19771da177e4SLinus Torvalds tmp = 0; 19781da177e4SLinus Torvalds } 197911d2f63bSFinn Thain 198011d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 198111d2f63bSFinn Thain if (!hostdata->connected) 198211d2f63bSFinn Thain return; 198311d2f63bSFinn Thain 19841da177e4SLinus Torvalds /* Fall through to reject message */ 19851da177e4SLinus Torvalds 19861da177e4SLinus Torvalds /* 19871da177e4SLinus Torvalds * If we get something weird that we aren't expecting, 19881da177e4SLinus Torvalds * reject it. 19891da177e4SLinus Torvalds */ 19901da177e4SLinus Torvalds default: 19911da177e4SLinus Torvalds if (!tmp) { 19926a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "rejecting message "); 19931abfd370SMatthew Wilcox spi_print_msg(extended_msg); 19941da177e4SLinus Torvalds printk("\n"); 19951da177e4SLinus Torvalds } else if (tmp != EXTENDED_MESSAGE) 1996017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 1997017560fcSJeff Garzik "rejecting unknown message %02x\n",tmp); 19981da177e4SLinus Torvalds else 1999017560fcSJeff Garzik scmd_printk(KERN_INFO, cmd, 2000017560fcSJeff Garzik "rejecting unknown extended message code %02x, length %d\n", extended_msg[1], extended_msg[0]); 20011da177e4SLinus Torvalds 20021da177e4SLinus Torvalds msgout = MESSAGE_REJECT; 20031da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); 20041da177e4SLinus Torvalds break; 20051da177e4SLinus Torvalds } /* switch (tmp) */ 20061da177e4SLinus Torvalds break; 20071da177e4SLinus Torvalds case PHASE_MSGOUT: 20081da177e4SLinus Torvalds len = 1; 20091da177e4SLinus Torvalds data = &msgout; 20101da177e4SLinus Torvalds hostdata->last_message = msgout; 20111da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 20121da177e4SLinus Torvalds if (msgout == ABORT) { 20131da177e4SLinus Torvalds hostdata->connected = NULL; 20141da177e4SLinus Torvalds cmd->result = DID_ERROR << 16; 2015677e0194SFinn Thain complete_cmd(instance, cmd); 20161da177e4SLinus Torvalds NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); 20171da177e4SLinus Torvalds return; 20181da177e4SLinus Torvalds } 20191da177e4SLinus Torvalds msgout = NOP; 20201da177e4SLinus Torvalds break; 20211da177e4SLinus Torvalds case PHASE_CMDOUT: 20221da177e4SLinus Torvalds len = cmd->cmd_len; 20231da177e4SLinus Torvalds data = cmd->cmnd; 20241da177e4SLinus Torvalds /* 20251da177e4SLinus Torvalds * XXX for performance reasons, on machines with a 20261da177e4SLinus Torvalds * PSEUDO-DMA architecture we should probably 20271da177e4SLinus Torvalds * use the dma transfer function. 20281da177e4SLinus Torvalds */ 20291da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 20301da177e4SLinus Torvalds break; 20311da177e4SLinus Torvalds case PHASE_STATIN: 20321da177e4SLinus Torvalds len = 1; 20331da177e4SLinus Torvalds data = &tmp; 20341da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 20351da177e4SLinus Torvalds cmd->SCp.Status = tmp; 20361da177e4SLinus Torvalds break; 20371da177e4SLinus Torvalds default: 20386a6ff4acSFinn Thain shost_printk(KERN_ERR, instance, "unknown phase\n"); 20394dde8f7dSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 20401da177e4SLinus Torvalds } /* switch(phase) */ 2041686f3990SFinn Thain } else { 204211d2f63bSFinn Thain spin_unlock_irq(&hostdata->lock); 2043686f3990SFinn Thain NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ); 204411d2f63bSFinn Thain spin_lock_irq(&hostdata->lock); 20451da177e4SLinus Torvalds } 204611d2f63bSFinn Thain } 20471da177e4SLinus Torvalds } 20481da177e4SLinus Torvalds 20491da177e4SLinus Torvalds /* 20501da177e4SLinus Torvalds * Function : void NCR5380_reselect (struct Scsi_Host *instance) 20511da177e4SLinus Torvalds * 20521da177e4SLinus Torvalds * Purpose : does reselection, initializing the instance->connected 2053710ddd0dSFinn Thain * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q 20541da177e4SLinus Torvalds * nexus has been reestablished, 20551da177e4SLinus Torvalds * 20561da177e4SLinus Torvalds * Inputs : instance - this instance of the NCR5380. 20571da177e4SLinus Torvalds */ 20581da177e4SLinus Torvalds 20591da177e4SLinus Torvalds static void NCR5380_reselect(struct Scsi_Host *instance) { 2060e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 20611da177e4SLinus Torvalds unsigned char target_mask; 20621da177e4SLinus Torvalds unsigned char lun, phase; 20631da177e4SLinus Torvalds int len; 20641da177e4SLinus Torvalds unsigned char msg[3]; 20651da177e4SLinus Torvalds unsigned char *data; 206632b26a10SFinn Thain struct NCR5380_cmd *ncmd; 206732b26a10SFinn Thain struct scsi_cmnd *tmp; 20681da177e4SLinus Torvalds 20691da177e4SLinus Torvalds /* 20701da177e4SLinus Torvalds * Disable arbitration, etc. since the host adapter obviously 20711da177e4SLinus Torvalds * lost, and tell an interrupted NCR5380_select() to restart. 20721da177e4SLinus Torvalds */ 20731da177e4SLinus Torvalds 20741da177e4SLinus Torvalds NCR5380_write(MODE_REG, MR_BASE); 20751da177e4SLinus Torvalds 20761da177e4SLinus Torvalds target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); 2077b746545fSFinn Thain 2078b746545fSFinn Thain dsprintk(NDEBUG_RESELECTION, instance, "reselect\n"); 20791da177e4SLinus Torvalds 20801da177e4SLinus Torvalds /* 20811da177e4SLinus Torvalds * At this point, we have detected that our SCSI ID is on the bus, 20821da177e4SLinus Torvalds * SEL is true and BSY was false for at least one bus settle delay 20831da177e4SLinus Torvalds * (400 ns). 20841da177e4SLinus Torvalds * 20851da177e4SLinus Torvalds * We must assert BSY ourselves, until the target drops the SEL 20861da177e4SLinus Torvalds * signal. 20871da177e4SLinus Torvalds */ 20881da177e4SLinus Torvalds 20891da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); 209072064a78SFinn Thain if (NCR5380_poll_politely(instance, 209172064a78SFinn Thain STATUS_REG, SR_SEL, 0, 2 * HZ) < 0) { 209272064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 209372064a78SFinn Thain return; 209472064a78SFinn Thain } 20951da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 20961da177e4SLinus Torvalds 20971da177e4SLinus Torvalds /* 20981da177e4SLinus Torvalds * Wait for target to go into MSGIN. 20991da177e4SLinus Torvalds */ 21001da177e4SLinus Torvalds 21011cc160e1SFinn Thain if (NCR5380_poll_politely(instance, 210272064a78SFinn Thain STATUS_REG, SR_REQ, SR_REQ, 2 * HZ) < 0) { 210372064a78SFinn Thain do_abort(instance); 210472064a78SFinn Thain return; 210572064a78SFinn Thain } 21061da177e4SLinus Torvalds 21071da177e4SLinus Torvalds len = 1; 21081da177e4SLinus Torvalds data = msg; 21091da177e4SLinus Torvalds phase = PHASE_MSGIN; 21101da177e4SLinus Torvalds NCR5380_transfer_pio(instance, &phase, &len, &data); 21111da177e4SLinus Torvalds 211272064a78SFinn Thain if (len) { 211372064a78SFinn Thain do_abort(instance); 211472064a78SFinn Thain return; 211572064a78SFinn Thain } 211672064a78SFinn Thain 21171da177e4SLinus Torvalds if (!(msg[0] & 0x80)) { 211872064a78SFinn Thain shost_printk(KERN_ERR, instance, "expecting IDENTIFY message, got "); 21191abfd370SMatthew Wilcox spi_print_msg(msg); 212072064a78SFinn Thain printk("\n"); 212172064a78SFinn Thain do_abort(instance); 212272064a78SFinn Thain return; 212372064a78SFinn Thain } 212472064a78SFinn Thain lun = msg[0] & 0x07; 21251da177e4SLinus Torvalds 21261da177e4SLinus Torvalds /* 21271da177e4SLinus Torvalds * We need to add code for SCSI-II to track which devices have 21281da177e4SLinus Torvalds * I_T_L_Q nexuses established, and which have simple I_T_L 21291da177e4SLinus Torvalds * nexuses so we can chose to do additional data transfer. 21301da177e4SLinus Torvalds */ 21311da177e4SLinus Torvalds 21321da177e4SLinus Torvalds /* 21331da177e4SLinus Torvalds * Find the command corresponding to the I_T_L or I_T_L_Q nexus we 21341da177e4SLinus Torvalds * just reestablished, and remove it from the disconnected queue. 21351da177e4SLinus Torvalds */ 21361da177e4SLinus Torvalds 213732b26a10SFinn Thain tmp = NULL; 213832b26a10SFinn Thain list_for_each_entry(ncmd, &hostdata->disconnected, list) { 213932b26a10SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 214032b26a10SFinn Thain 214132b26a10SFinn Thain if (target_mask == (1 << scmd_id(cmd)) && 214232b26a10SFinn Thain lun == (u8)cmd->device->lun) { 214332b26a10SFinn Thain list_del(&ncmd->list); 214432b26a10SFinn Thain tmp = cmd; 21451da177e4SLinus Torvalds break; 21461da177e4SLinus Torvalds } 214772064a78SFinn Thain } 21480d3d9a42SFinn Thain 21490d3d9a42SFinn Thain if (tmp) { 21500d3d9a42SFinn Thain dsprintk(NDEBUG_RESELECTION | NDEBUG_QUEUES, instance, 21510d3d9a42SFinn Thain "reselect: removed %p from disconnected queue\n", tmp); 21520d3d9a42SFinn Thain } else { 215372064a78SFinn Thain shost_printk(KERN_ERR, instance, "target bitmask 0x%02x lun %d not in disconnected queue.\n", 215472064a78SFinn Thain target_mask, lun); 21551da177e4SLinus Torvalds /* 21561da177e4SLinus Torvalds * Since we have an established nexus that we can't do anything with, 21571da177e4SLinus Torvalds * we must abort it. 21581da177e4SLinus Torvalds */ 215972064a78SFinn Thain do_abort(instance); 216072064a78SFinn Thain return; 21611da177e4SLinus Torvalds } 21621da177e4SLinus Torvalds 216372064a78SFinn Thain /* Accept message by clearing ACK */ 216472064a78SFinn Thain NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 216572064a78SFinn Thain 21661da177e4SLinus Torvalds hostdata->connected = tmp; 2167b746545fSFinn Thain dsprintk(NDEBUG_RESELECTION, instance, "nexus established, target %d, lun %llu, tag %d\n", 2168b746545fSFinn Thain scmd_id(tmp), tmp->device->lun, tmp->tag); 21691da177e4SLinus Torvalds } 21701da177e4SLinus Torvalds 21711da177e4SLinus Torvalds /* 21721da177e4SLinus Torvalds * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) 21731da177e4SLinus Torvalds * 21741da177e4SLinus Torvalds * Purpose : called by interrupt handler when DMA finishes or a phase 21751da177e4SLinus Torvalds * mismatch occurs (which would finish the DMA transfer). 21761da177e4SLinus Torvalds * 21771da177e4SLinus Torvalds * Inputs : instance - this instance of the NCR5380. 21781da177e4SLinus Torvalds * 2179710ddd0dSFinn Thain * Returns : pointer to the scsi_cmnd structure for which the I_T_L 21801da177e4SLinus Torvalds * nexus has been reestablished, on failure NULL is returned. 21811da177e4SLinus Torvalds */ 21821da177e4SLinus Torvalds 21831da177e4SLinus Torvalds #ifdef REAL_DMA 21841da177e4SLinus Torvalds static void NCR5380_dma_complete(NCR5380_instance * instance) { 2185e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 21861da177e4SLinus Torvalds int transferred; 21871da177e4SLinus Torvalds 21881da177e4SLinus Torvalds /* 21891da177e4SLinus Torvalds * XXX this might not be right. 21901da177e4SLinus Torvalds * 21911da177e4SLinus Torvalds * Wait for final byte to transfer, ie wait for ACK to go false. 21921da177e4SLinus Torvalds * 21931da177e4SLinus Torvalds * We should use the Last Byte Sent bit, unfortunately this is 21941da177e4SLinus Torvalds * not available on the 5380/5381 (only the various CMOS chips) 21951da177e4SLinus Torvalds * 21961da177e4SLinus Torvalds * FIXME: timeout, and need to handle long timeout/irq case 21971da177e4SLinus Torvalds */ 21981da177e4SLinus Torvalds 21991da177e4SLinus Torvalds NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, BASR_ACK, 0, 5*HZ); 22001da177e4SLinus Torvalds 22011da177e4SLinus Torvalds NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); 22021da177e4SLinus Torvalds 22031da177e4SLinus Torvalds /* 22041da177e4SLinus Torvalds * The only places we should see a phase mismatch and have to send 22051da177e4SLinus Torvalds * data from the same set of pointers will be the data transfer 22061da177e4SLinus Torvalds * phases. So, residual, requested length are only important here. 22071da177e4SLinus Torvalds */ 22081da177e4SLinus Torvalds 22091da177e4SLinus Torvalds if (!(hostdata->connected->SCp.phase & SR_CD)) { 22101da177e4SLinus Torvalds transferred = instance->dmalen - NCR5380_dma_residual(); 22111da177e4SLinus Torvalds hostdata->connected->SCp.this_residual -= transferred; 22121da177e4SLinus Torvalds hostdata->connected->SCp.ptr += transferred; 22131da177e4SLinus Torvalds } 22141da177e4SLinus Torvalds } 22151da177e4SLinus Torvalds #endif /* def REAL_DMA */ 22161da177e4SLinus Torvalds 22178b00c3d5SFinn Thain /** 22188b00c3d5SFinn Thain * list_find_cmd - test for presence of a command in a linked list 22198b00c3d5SFinn Thain * @haystack: list of commands 22208b00c3d5SFinn Thain * @needle: command to search for 22218b00c3d5SFinn Thain */ 22228b00c3d5SFinn Thain 22238b00c3d5SFinn Thain static bool list_find_cmd(struct list_head *haystack, 22248b00c3d5SFinn Thain struct scsi_cmnd *needle) 22258b00c3d5SFinn Thain { 22268b00c3d5SFinn Thain struct NCR5380_cmd *ncmd; 22278b00c3d5SFinn Thain 22288b00c3d5SFinn Thain list_for_each_entry(ncmd, haystack, list) 22298b00c3d5SFinn Thain if (NCR5380_to_scmd(ncmd) == needle) 22308b00c3d5SFinn Thain return true; 22318b00c3d5SFinn Thain return false; 22328b00c3d5SFinn Thain } 22338b00c3d5SFinn Thain 22348b00c3d5SFinn Thain /** 22358b00c3d5SFinn Thain * list_remove_cmd - remove a command from linked list 22368b00c3d5SFinn Thain * @haystack: list of commands 22378b00c3d5SFinn Thain * @needle: command to remove 22388b00c3d5SFinn Thain */ 22398b00c3d5SFinn Thain 22408b00c3d5SFinn Thain static bool list_del_cmd(struct list_head *haystack, 22418b00c3d5SFinn Thain struct scsi_cmnd *needle) 22428b00c3d5SFinn Thain { 22438b00c3d5SFinn Thain if (list_find_cmd(haystack, needle)) { 22448b00c3d5SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(needle); 22458b00c3d5SFinn Thain 22468b00c3d5SFinn Thain list_del(&ncmd->list); 22478b00c3d5SFinn Thain return true; 22488b00c3d5SFinn Thain } 22498b00c3d5SFinn Thain return false; 22508b00c3d5SFinn Thain } 22518b00c3d5SFinn Thain 22528b00c3d5SFinn Thain /** 22538b00c3d5SFinn Thain * NCR5380_abort - scsi host eh_abort_handler() method 22548b00c3d5SFinn Thain * @cmd: the command to be aborted 22551da177e4SLinus Torvalds * 22568b00c3d5SFinn Thain * Try to abort a given command by removing it from queues and/or sending 22578b00c3d5SFinn Thain * the target an abort message. This may not succeed in causing a target 22588b00c3d5SFinn Thain * to abort the command. Nonetheless, the low-level driver must forget about 22598b00c3d5SFinn Thain * the command because the mid-layer reclaims it and it may be re-issued. 22601da177e4SLinus Torvalds * 22618b00c3d5SFinn Thain * The normal path taken by a command is as follows. For EH we trace this 22628b00c3d5SFinn Thain * same path to locate and abort the command. 22631da177e4SLinus Torvalds * 22648b00c3d5SFinn Thain * unissued -> selecting -> [unissued -> selecting ->]... connected -> 22658b00c3d5SFinn Thain * [disconnected -> connected ->]... 22668b00c3d5SFinn Thain * [autosense -> connected ->] done 22671da177e4SLinus Torvalds * 22688b00c3d5SFinn Thain * If cmd is unissued then just remove it. 22698b00c3d5SFinn Thain * If cmd is disconnected, try to select the target. 22708b00c3d5SFinn Thain * If cmd is connected, try to send an abort message. 22718b00c3d5SFinn Thain * If cmd is waiting for autosense, give it a chance to complete but check 22728b00c3d5SFinn Thain * that it isn't left connected. 22738b00c3d5SFinn Thain * If cmd was not found at all then presumably it has already been completed, 22748b00c3d5SFinn Thain * in which case return SUCCESS to try to avoid further EH measures. 22758b00c3d5SFinn Thain * If the command has not completed yet, we must not fail to find it. 22761da177e4SLinus Torvalds */ 22771da177e4SLinus Torvalds 2278710ddd0dSFinn Thain static int NCR5380_abort(struct scsi_cmnd *cmd) 2279710ddd0dSFinn Thain { 22801da177e4SLinus Torvalds struct Scsi_Host *instance = cmd->device->host; 2281e8a60144SFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 228211d2f63bSFinn Thain unsigned long flags; 22838b00c3d5SFinn Thain int result = SUCCESS; 22841da177e4SLinus Torvalds 228511d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 228611d2f63bSFinn Thain 228732b26a10SFinn Thain #if (NDEBUG & NDEBUG_ANY) 22888b00c3d5SFinn Thain scmd_printk(KERN_INFO, cmd, __func__); 228932b26a10SFinn Thain #endif 2290e5c3fddfSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 2291e5c3fddfSFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 22921da177e4SLinus Torvalds 22938b00c3d5SFinn Thain if (list_del_cmd(&hostdata->unissued, cmd)) { 22948b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 22958b00c3d5SFinn Thain "abort: removed %p from issue queue\n", cmd); 22968b00c3d5SFinn Thain cmd->result = DID_ABORT << 16; 22978b00c3d5SFinn Thain cmd->scsi_done(cmd); /* No tag or busy flag to worry about */ 22988b00c3d5SFinn Thain } 22998b00c3d5SFinn Thain 2300707d62b3SFinn Thain if (hostdata->selecting == cmd) { 2301707d62b3SFinn Thain dsprintk(NDEBUG_ABORT, instance, 2302707d62b3SFinn Thain "abort: cmd %p == selecting\n", cmd); 2303707d62b3SFinn Thain hostdata->selecting = NULL; 2304707d62b3SFinn Thain cmd->result = DID_ABORT << 16; 2305707d62b3SFinn Thain complete_cmd(instance, cmd); 2306707d62b3SFinn Thain goto out; 2307707d62b3SFinn Thain } 2308707d62b3SFinn Thain 23098b00c3d5SFinn Thain if (list_del_cmd(&hostdata->disconnected, cmd)) { 23108b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 23118b00c3d5SFinn Thain "abort: removed %p from disconnected list\n", cmd); 23128b00c3d5SFinn Thain cmd->result = DID_ERROR << 16; 23138b00c3d5SFinn Thain if (!hostdata->connected) 23148b00c3d5SFinn Thain NCR5380_select(instance, cmd); 23158b00c3d5SFinn Thain if (hostdata->connected != cmd) { 23168b00c3d5SFinn Thain complete_cmd(instance, cmd); 23178b00c3d5SFinn Thain result = FAILED; 23188b00c3d5SFinn Thain goto out; 23198b00c3d5SFinn Thain } 23208b00c3d5SFinn Thain } 23218b00c3d5SFinn Thain 23228b00c3d5SFinn Thain if (hostdata->connected == cmd) { 23238b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); 23248b00c3d5SFinn Thain hostdata->connected = NULL; 23258b00c3d5SFinn Thain if (do_abort(instance)) { 23268b00c3d5SFinn Thain set_host_byte(cmd, DID_ERROR); 23278b00c3d5SFinn Thain complete_cmd(instance, cmd); 23288b00c3d5SFinn Thain result = FAILED; 23298b00c3d5SFinn Thain goto out; 23308b00c3d5SFinn Thain } 23318b00c3d5SFinn Thain set_host_byte(cmd, DID_ABORT); 23328b00c3d5SFinn Thain #ifdef REAL_DMA 23338b00c3d5SFinn Thain hostdata->dma_len = 0; 23348b00c3d5SFinn Thain #endif 23358b00c3d5SFinn Thain if (cmd->cmnd[0] == REQUEST_SENSE) 23368b00c3d5SFinn Thain complete_cmd(instance, cmd); 23378b00c3d5SFinn Thain else { 23388b00c3d5SFinn Thain struct NCR5380_cmd *ncmd = scsi_cmd_priv(cmd); 23398b00c3d5SFinn Thain 23408b00c3d5SFinn Thain /* Perform autosense for this command */ 23418b00c3d5SFinn Thain list_add(&ncmd->list, &hostdata->autosense); 23428b00c3d5SFinn Thain } 23438b00c3d5SFinn Thain } 23448b00c3d5SFinn Thain 23458b00c3d5SFinn Thain if (list_find_cmd(&hostdata->autosense, cmd)) { 23468b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 23478b00c3d5SFinn Thain "abort: found %p on sense queue\n", cmd); 23488b00c3d5SFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 23498b00c3d5SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 23508b00c3d5SFinn Thain msleep(1000); 23518b00c3d5SFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 23528b00c3d5SFinn Thain if (list_del_cmd(&hostdata->autosense, cmd)) { 23538b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, 23548b00c3d5SFinn Thain "abort: removed %p from sense queue\n", cmd); 23558b00c3d5SFinn Thain set_host_byte(cmd, DID_ABORT); 23568b00c3d5SFinn Thain complete_cmd(instance, cmd); 23578b00c3d5SFinn Thain goto out; 23588b00c3d5SFinn Thain } 23598b00c3d5SFinn Thain } 23608b00c3d5SFinn Thain 23618b00c3d5SFinn Thain if (hostdata->connected == cmd) { 23628b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); 23638b00c3d5SFinn Thain hostdata->connected = NULL; 23648b00c3d5SFinn Thain if (do_abort(instance)) { 23658b00c3d5SFinn Thain set_host_byte(cmd, DID_ERROR); 23668b00c3d5SFinn Thain complete_cmd(instance, cmd); 23678b00c3d5SFinn Thain result = FAILED; 23688b00c3d5SFinn Thain goto out; 23698b00c3d5SFinn Thain } 23708b00c3d5SFinn Thain set_host_byte(cmd, DID_ABORT); 23718b00c3d5SFinn Thain #ifdef REAL_DMA 23728b00c3d5SFinn Thain hostdata->dma_len = 0; 23738b00c3d5SFinn Thain #endif 23748b00c3d5SFinn Thain complete_cmd(instance, cmd); 23758b00c3d5SFinn Thain } 23768b00c3d5SFinn Thain 23778b00c3d5SFinn Thain out: 23788b00c3d5SFinn Thain if (result == FAILED) 23798b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: failed to abort %p\n", cmd); 23808b00c3d5SFinn Thain else 23818b00c3d5SFinn Thain dsprintk(NDEBUG_ABORT, instance, "abort: successfully aborted %p\n", cmd); 23828b00c3d5SFinn Thain 23838b00c3d5SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 238411d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 23851da177e4SLinus Torvalds 23868b00c3d5SFinn Thain return result; 23871da177e4SLinus Torvalds } 23881da177e4SLinus Torvalds 23891da177e4SLinus Torvalds 23903be1b3eaSFinn Thain /** 23913be1b3eaSFinn Thain * NCR5380_bus_reset - reset the SCSI bus 23923be1b3eaSFinn Thain * @cmd: SCSI command undergoing EH 23931da177e4SLinus Torvalds * 23943be1b3eaSFinn Thain * Returns SUCCESS 23951da177e4SLinus Torvalds */ 23961da177e4SLinus Torvalds 2397710ddd0dSFinn Thain static int NCR5380_bus_reset(struct scsi_cmnd *cmd) 239868b3aa7cSJeff Garzik { 239968b3aa7cSJeff Garzik struct Scsi_Host *instance = cmd->device->host; 240011d2f63bSFinn Thain struct NCR5380_hostdata *hostdata = shost_priv(instance); 240162717f53SFinn Thain int i; 240211d2f63bSFinn Thain unsigned long flags; 240362717f53SFinn Thain struct NCR5380_cmd *ncmd; 24041da177e4SLinus Torvalds 240511d2f63bSFinn Thain spin_lock_irqsave(&hostdata->lock, flags); 24063be1b3eaSFinn Thain 24073be1b3eaSFinn Thain #if (NDEBUG & NDEBUG_ANY) 240862717f53SFinn Thain scmd_printk(KERN_INFO, cmd, __func__); 24093be1b3eaSFinn Thain #endif 2410e5c3fddfSFinn Thain NCR5380_dprint(NDEBUG_ANY, instance); 2411e5c3fddfSFinn Thain NCR5380_dprint_phase(NDEBUG_ANY, instance); 24123be1b3eaSFinn Thain 241368b3aa7cSJeff Garzik do_reset(instance); 24143be1b3eaSFinn Thain 241562717f53SFinn Thain /* reset NCR registers */ 241662717f53SFinn Thain NCR5380_write(MODE_REG, MR_BASE); 241762717f53SFinn Thain NCR5380_write(TARGET_COMMAND_REG, 0); 241862717f53SFinn Thain NCR5380_write(SELECT_ENABLE_REG, 0); 241962717f53SFinn Thain 242062717f53SFinn Thain /* After the reset, there are no more connected or disconnected commands 242162717f53SFinn Thain * and no busy units; so clear the low-level status here to avoid 242262717f53SFinn Thain * conflicts when the mid-level code tries to wake up the affected 242362717f53SFinn Thain * commands! 242462717f53SFinn Thain */ 242562717f53SFinn Thain 242662717f53SFinn Thain hostdata->selecting = NULL; 242762717f53SFinn Thain 242862717f53SFinn Thain list_for_each_entry(ncmd, &hostdata->disconnected, list) { 242962717f53SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 243062717f53SFinn Thain 243162717f53SFinn Thain set_host_byte(cmd, DID_RESET); 243262717f53SFinn Thain cmd->scsi_done(cmd); 243362717f53SFinn Thain } 243462717f53SFinn Thain 243562717f53SFinn Thain list_for_each_entry(ncmd, &hostdata->autosense, list) { 243662717f53SFinn Thain struct scsi_cmnd *cmd = NCR5380_to_scmd(ncmd); 243762717f53SFinn Thain 243862717f53SFinn Thain set_host_byte(cmd, DID_RESET); 243962717f53SFinn Thain cmd->scsi_done(cmd); 244062717f53SFinn Thain } 244162717f53SFinn Thain 244262717f53SFinn Thain if (hostdata->connected) { 244362717f53SFinn Thain set_host_byte(hostdata->connected, DID_RESET); 244462717f53SFinn Thain complete_cmd(instance, hostdata->connected); 244562717f53SFinn Thain hostdata->connected = NULL; 244662717f53SFinn Thain } 244762717f53SFinn Thain 244862717f53SFinn Thain if (hostdata->sensing) { 244962717f53SFinn Thain set_host_byte(hostdata->connected, DID_RESET); 245062717f53SFinn Thain complete_cmd(instance, hostdata->sensing); 245162717f53SFinn Thain hostdata->sensing = NULL; 245262717f53SFinn Thain } 245362717f53SFinn Thain 245462717f53SFinn Thain for (i = 0; i < 8; ++i) 245562717f53SFinn Thain hostdata->busy[i] = 0; 245662717f53SFinn Thain #ifdef REAL_DMA 245762717f53SFinn Thain hostdata->dma_len = 0; 245862717f53SFinn Thain #endif 245962717f53SFinn Thain 246062717f53SFinn Thain queue_work(hostdata->work_q, &hostdata->main_task); 246111d2f63bSFinn Thain spin_unlock_irqrestore(&hostdata->lock, flags); 246268b3aa7cSJeff Garzik 24631da177e4SLinus Torvalds return SUCCESS; 24641da177e4SLinus Torvalds } 2465