162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* NCR (or Symbios) 53c700 and 53c700-66 Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com 662306a36Sopenharmony_ci**----------------------------------------------------------------------------- 762306a36Sopenharmony_ci** 862306a36Sopenharmony_ci** 962306a36Sopenharmony_ci**----------------------------------------------------------------------------- 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* Notes: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This driver is designed exclusively for these chips (virtually the 1562306a36Sopenharmony_ci * earliest of the scripts engine chips). They need their own drivers 1662306a36Sopenharmony_ci * because they are missing so many of the scripts and snazzy register 1762306a36Sopenharmony_ci * features of their elder brothers (the 710, 720 and 770). 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * The 700 is the lowliest of the line, it can only do async SCSI. 2062306a36Sopenharmony_ci * The 700-66 can at least do synchronous SCSI up to 10MHz. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * The 700 chip has no host bus interface logic of its own. However, 2362306a36Sopenharmony_ci * it is usually mapped to a location with well defined register 2462306a36Sopenharmony_ci * offsets. Therefore, if you can determine the base address and the 2562306a36Sopenharmony_ci * irq your board incorporating this chip uses, you can probably use 2662306a36Sopenharmony_ci * this driver to run it (although you'll probably have to write a 2762306a36Sopenharmony_ci * minimal wrapper for the purpose---see the NCR_D700 driver for 2862306a36Sopenharmony_ci * details about how to do this). 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * TODO List: 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * 1. Better statistics in the proc fs 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * 2. Implement message queue (queues SCSI messages like commands) and make 3662306a36Sopenharmony_ci * the abort and device reset functions use them. 3762306a36Sopenharmony_ci * */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* CHANGELOG 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * Version 2.8 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * Fixed bad bug affecting tag starvation processing (previously the 4462306a36Sopenharmony_ci * driver would hang the system if too many tags starved. Also fixed 4562306a36Sopenharmony_ci * bad bug having to do with 10 byte command processing and REQUEST 4662306a36Sopenharmony_ci * SENSE (the command would loop forever getting a transfer length 4762306a36Sopenharmony_ci * mismatch in the CMD phase). 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * Version 2.7 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * Fixed scripts problem which caused certain devices (notably CDRWs) 5262306a36Sopenharmony_ci * to hang on initial INQUIRY. Updated NCR_700_readl/writel to use 5362306a36Sopenharmony_ci * __raw_readl/writel for parisc compatibility (Thomas 5462306a36Sopenharmony_ci * Bogendoerfer). Added missing SCp->request_bufflen initialisation 5562306a36Sopenharmony_ci * for sense requests (Ryan Bradetich). 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * Version 2.6 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Following test of the 64 bit parisc kernel by Richard Hirst, 6062306a36Sopenharmony_ci * several problems have now been corrected. Also adds support for 6162306a36Sopenharmony_ci * consistent memory allocation. 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * Version 2.5 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * More Compatibility changes for 710 (now actually works). Enhanced 6662306a36Sopenharmony_ci * support for odd clock speeds which constrain SDTR negotiations. 6762306a36Sopenharmony_ci * correct cacheline separation for scsi messages and status for 6862306a36Sopenharmony_ci * incoherent architectures. Use of the pci mapping functions on 6962306a36Sopenharmony_ci * buffers to begin support for 64 bit drivers. 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Version 2.4 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * Added support for the 53c710 chip (in 53c700 emulation mode only---no 7462306a36Sopenharmony_ci * special 53c710 instructions or registers are used). 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * Version 2.3 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * More endianness/cache coherency changes. 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * Better bad device handling (handles devices lying about tag 8162306a36Sopenharmony_ci * queueing support and devices which fail to provide sense data on 8262306a36Sopenharmony_ci * contingent allegiance conditions) 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * Many thanks to Richard Hirst <rhirst@linuxcare.com> for patiently 8562306a36Sopenharmony_ci * debugging this driver on the parisc architecture and suggesting 8662306a36Sopenharmony_ci * many improvements and bug fixes. 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * Thanks also go to Linuxcare Inc. for providing several PARISC 8962306a36Sopenharmony_ci * machines for me to debug the driver on. 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * Version 2.2 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * Made the driver mem or io mapped; added endian invariance; added 9462306a36Sopenharmony_ci * dma cache flushing operations for architectures which need it; 9562306a36Sopenharmony_ci * added support for more varied clocking speeds. 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * Version 2.1 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * Initial modularisation from the D700. See NCR_D700.c for the rest of 10062306a36Sopenharmony_ci * the changelog. 10162306a36Sopenharmony_ci * */ 10262306a36Sopenharmony_ci#define NCR_700_VERSION "2.8" 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#include <linux/kernel.h> 10562306a36Sopenharmony_ci#include <linux/types.h> 10662306a36Sopenharmony_ci#include <linux/string.h> 10762306a36Sopenharmony_ci#include <linux/slab.h> 10862306a36Sopenharmony_ci#include <linux/ioport.h> 10962306a36Sopenharmony_ci#include <linux/delay.h> 11062306a36Sopenharmony_ci#include <linux/spinlock.h> 11162306a36Sopenharmony_ci#include <linux/completion.h> 11262306a36Sopenharmony_ci#include <linux/init.h> 11362306a36Sopenharmony_ci#include <linux/proc_fs.h> 11462306a36Sopenharmony_ci#include <linux/blkdev.h> 11562306a36Sopenharmony_ci#include <linux/module.h> 11662306a36Sopenharmony_ci#include <linux/interrupt.h> 11762306a36Sopenharmony_ci#include <linux/device.h> 11862306a36Sopenharmony_ci#include <linux/pgtable.h> 11962306a36Sopenharmony_ci#include <asm/dma.h> 12062306a36Sopenharmony_ci#include <asm/io.h> 12162306a36Sopenharmony_ci#include <asm/byteorder.h> 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#include <scsi/scsi.h> 12462306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 12562306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 12662306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 12762306a36Sopenharmony_ci#include <scsi/scsi_host.h> 12862306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 12962306a36Sopenharmony_ci#include <scsi/scsi_transport.h> 13062306a36Sopenharmony_ci#include <scsi/scsi_transport_spi.h> 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#include "53c700.h" 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* NOTE: For 64 bit drivers there are points in the code where we use 13562306a36Sopenharmony_ci * a non dereferenceable pointer to point to a structure in dma-able 13662306a36Sopenharmony_ci * memory (which is 32 bits) so that we can use all of the structure 13762306a36Sopenharmony_ci * operations but take the address at the end. This macro allows us 13862306a36Sopenharmony_ci * to truncate the 64 bit pointer down to 32 bits without the compiler 13962306a36Sopenharmony_ci * complaining */ 14062306a36Sopenharmony_ci#define to32bit(x) ((__u32)((unsigned long)(x))) 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 14362306a36Sopenharmony_ci#define STATIC 14462306a36Sopenharmony_ci#else 14562306a36Sopenharmony_ci#define STATIC static 14662306a36Sopenharmony_ci#endif 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ciMODULE_AUTHOR("James Bottomley"); 14962306a36Sopenharmony_ciMODULE_DESCRIPTION("53c700 and 53c700-66 Driver"); 15062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* This is the script */ 15362306a36Sopenharmony_ci#include "53c700_d.h" 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciSTATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *); 15762306a36Sopenharmony_ciSTATIC int NCR_700_abort(struct scsi_cmnd * SCpnt); 15862306a36Sopenharmony_ciSTATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt); 15962306a36Sopenharmony_ciSTATIC void NCR_700_chip_setup(struct Scsi_Host *host); 16062306a36Sopenharmony_ciSTATIC void NCR_700_chip_reset(struct Scsi_Host *host); 16162306a36Sopenharmony_ciSTATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt); 16262306a36Sopenharmony_ciSTATIC int NCR_700_slave_configure(struct scsi_device *SDpnt); 16362306a36Sopenharmony_ciSTATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt); 16462306a36Sopenharmony_cistatic int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciSTATIC const struct attribute_group *NCR_700_dev_groups[]; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciSTATIC struct scsi_transport_template *NCR_700_transport_template = NULL; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic char *NCR_700_phase[] = { 17162306a36Sopenharmony_ci "", 17262306a36Sopenharmony_ci "after selection", 17362306a36Sopenharmony_ci "before command phase", 17462306a36Sopenharmony_ci "after command phase", 17562306a36Sopenharmony_ci "after status phase", 17662306a36Sopenharmony_ci "after data in phase", 17762306a36Sopenharmony_ci "after data out phase", 17862306a36Sopenharmony_ci "during data phase", 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic char *NCR_700_condition[] = { 18262306a36Sopenharmony_ci "", 18362306a36Sopenharmony_ci "NOT MSG_OUT", 18462306a36Sopenharmony_ci "UNEXPECTED PHASE", 18562306a36Sopenharmony_ci "NOT MSG_IN", 18662306a36Sopenharmony_ci "UNEXPECTED MSG", 18762306a36Sopenharmony_ci "MSG_IN", 18862306a36Sopenharmony_ci "SDTR_MSG RECEIVED", 18962306a36Sopenharmony_ci "REJECT_MSG RECEIVED", 19062306a36Sopenharmony_ci "DISCONNECT_MSG RECEIVED", 19162306a36Sopenharmony_ci "MSG_OUT", 19262306a36Sopenharmony_ci "DATA_IN", 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic char *NCR_700_fatal_messages[] = { 19762306a36Sopenharmony_ci "unexpected message after reselection", 19862306a36Sopenharmony_ci "still MSG_OUT after message injection", 19962306a36Sopenharmony_ci "not MSG_IN after selection", 20062306a36Sopenharmony_ci "Illegal message length received", 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic char *NCR_700_SBCL_bits[] = { 20462306a36Sopenharmony_ci "IO ", 20562306a36Sopenharmony_ci "CD ", 20662306a36Sopenharmony_ci "MSG ", 20762306a36Sopenharmony_ci "ATN ", 20862306a36Sopenharmony_ci "SEL ", 20962306a36Sopenharmony_ci "BSY ", 21062306a36Sopenharmony_ci "ACK ", 21162306a36Sopenharmony_ci "REQ ", 21262306a36Sopenharmony_ci}; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic char *NCR_700_SBCL_to_phase[] = { 21562306a36Sopenharmony_ci "DATA_OUT", 21662306a36Sopenharmony_ci "DATA_IN", 21762306a36Sopenharmony_ci "CMD_OUT", 21862306a36Sopenharmony_ci "STATE", 21962306a36Sopenharmony_ci "ILLEGAL PHASE", 22062306a36Sopenharmony_ci "ILLEGAL PHASE", 22162306a36Sopenharmony_ci "MSG OUT", 22262306a36Sopenharmony_ci "MSG IN", 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* This translates the SDTR message offset and period to a value 22662306a36Sopenharmony_ci * which can be loaded into the SXFER_REG. 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * NOTE: According to SCSI-2, the true transfer period (in ns) is 22962306a36Sopenharmony_ci * actually four times this period value */ 23062306a36Sopenharmony_cistatic inline __u8 23162306a36Sopenharmony_ciNCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, 23262306a36Sopenharmony_ci __u8 offset, __u8 period) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci int XFERP; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci __u8 min_xferp = (hostdata->chip710 23762306a36Sopenharmony_ci ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); 23862306a36Sopenharmony_ci __u8 max_offset = (hostdata->chip710 23962306a36Sopenharmony_ci ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if(offset == 0) 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if(period < hostdata->min_period) { 24562306a36Sopenharmony_ci printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_MIN_PERIOD*4); 24662306a36Sopenharmony_ci period = hostdata->min_period; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci XFERP = (period*4 * hostdata->sync_clock)/1000 - 4; 24962306a36Sopenharmony_ci if(offset > max_offset) { 25062306a36Sopenharmony_ci printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n", 25162306a36Sopenharmony_ci offset, max_offset); 25262306a36Sopenharmony_ci offset = max_offset; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci if(XFERP < min_xferp) { 25562306a36Sopenharmony_ci XFERP = min_xferp; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci return (offset & 0x0f) | (XFERP & 0x07)<<4; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic inline __u8 26162306a36Sopenharmony_ciNCR_700_get_SXFER(struct scsi_device *SDp) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 26462306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return NCR_700_offset_period_to_sxfer(hostdata, 26762306a36Sopenharmony_ci spi_offset(SDp->sdev_target), 26862306a36Sopenharmony_ci spi_period(SDp->sdev_target)); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic inline dma_addr_t virt_to_dma(struct NCR_700_Host_Parameters *h, void *p) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci return h->pScript + ((uintptr_t)p - (uintptr_t)h->script); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic inline void dma_sync_to_dev(struct NCR_700_Host_Parameters *h, 27762306a36Sopenharmony_ci void *addr, size_t size) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci if (h->noncoherent) 28062306a36Sopenharmony_ci dma_sync_single_for_device(h->dev, virt_to_dma(h, addr), 28162306a36Sopenharmony_ci size, DMA_BIDIRECTIONAL); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic inline void dma_sync_from_dev(struct NCR_700_Host_Parameters *h, 28562306a36Sopenharmony_ci void *addr, size_t size) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci if (h->noncoherent) 28862306a36Sopenharmony_ci dma_sync_single_for_device(h->dev, virt_to_dma(h, addr), size, 28962306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistruct Scsi_Host * 29362306a36Sopenharmony_ciNCR_700_detect(struct scsi_host_template *tpnt, 29462306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata, struct device *dev) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci dma_addr_t pScript, pSlots; 29762306a36Sopenharmony_ci __u8 *memory; 29862306a36Sopenharmony_ci __u32 *script; 29962306a36Sopenharmony_ci struct Scsi_Host *host; 30062306a36Sopenharmony_ci static int banner = 0; 30162306a36Sopenharmony_ci int j; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (tpnt->sdev_groups == NULL) 30462306a36Sopenharmony_ci tpnt->sdev_groups = NCR_700_dev_groups; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci memory = dma_alloc_coherent(dev, TOTAL_MEM_SIZE, &pScript, GFP_KERNEL); 30762306a36Sopenharmony_ci if (!memory) { 30862306a36Sopenharmony_ci hostdata->noncoherent = 1; 30962306a36Sopenharmony_ci memory = dma_alloc_noncoherent(dev, TOTAL_MEM_SIZE, &pScript, 31062306a36Sopenharmony_ci DMA_BIDIRECTIONAL, GFP_KERNEL); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci if (!memory) { 31362306a36Sopenharmony_ci printk(KERN_ERR "53c700: Failed to allocate memory for driver, detaching\n"); 31462306a36Sopenharmony_ci return NULL; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci script = (__u32 *)memory; 31862306a36Sopenharmony_ci hostdata->msgin = memory + MSGIN_OFFSET; 31962306a36Sopenharmony_ci hostdata->msgout = memory + MSGOUT_OFFSET; 32062306a36Sopenharmony_ci hostdata->status = memory + STATUS_OFFSET; 32162306a36Sopenharmony_ci hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET); 32262306a36Sopenharmony_ci hostdata->dev = dev; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci pSlots = pScript + SLOTS_OFFSET; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* Fill in the missing routines from the host template */ 32762306a36Sopenharmony_ci tpnt->queuecommand = NCR_700_queuecommand; 32862306a36Sopenharmony_ci tpnt->eh_abort_handler = NCR_700_abort; 32962306a36Sopenharmony_ci tpnt->eh_host_reset_handler = NCR_700_host_reset; 33062306a36Sopenharmony_ci tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST; 33162306a36Sopenharmony_ci tpnt->sg_tablesize = NCR_700_SG_SEGMENTS; 33262306a36Sopenharmony_ci tpnt->cmd_per_lun = NCR_700_CMD_PER_LUN; 33362306a36Sopenharmony_ci tpnt->slave_configure = NCR_700_slave_configure; 33462306a36Sopenharmony_ci tpnt->slave_destroy = NCR_700_slave_destroy; 33562306a36Sopenharmony_ci tpnt->slave_alloc = NCR_700_slave_alloc; 33662306a36Sopenharmony_ci tpnt->change_queue_depth = NCR_700_change_queue_depth; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if(tpnt->name == NULL) 33962306a36Sopenharmony_ci tpnt->name = "53c700"; 34062306a36Sopenharmony_ci if(tpnt->proc_name == NULL) 34162306a36Sopenharmony_ci tpnt->proc_name = "53c700"; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci host = scsi_host_alloc(tpnt, 4); 34462306a36Sopenharmony_ci if (!host) 34562306a36Sopenharmony_ci return NULL; 34662306a36Sopenharmony_ci memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) 34762306a36Sopenharmony_ci * NCR_700_COMMAND_SLOTS_PER_HOST); 34862306a36Sopenharmony_ci for (j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) { 34962306a36Sopenharmony_ci dma_addr_t offset = (dma_addr_t)((unsigned long)&hostdata->slots[j].SG[0] 35062306a36Sopenharmony_ci - (unsigned long)&hostdata->slots[0].SG[0]); 35162306a36Sopenharmony_ci hostdata->slots[j].pSG = (struct NCR_700_SG_List *)((unsigned long)(pSlots + offset)); 35262306a36Sopenharmony_ci if(j == 0) 35362306a36Sopenharmony_ci hostdata->free_list = &hostdata->slots[j]; 35462306a36Sopenharmony_ci else 35562306a36Sopenharmony_ci hostdata->slots[j-1].ITL_forw = &hostdata->slots[j]; 35662306a36Sopenharmony_ci hostdata->slots[j].state = NCR_700_SLOT_FREE; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(SCRIPT); j++) 36062306a36Sopenharmony_ci script[j] = bS_to_host(SCRIPT[j]); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* adjust all labels to be bus physical */ 36362306a36Sopenharmony_ci for (j = 0; j < PATCHES; j++) 36462306a36Sopenharmony_ci script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]); 36562306a36Sopenharmony_ci /* now patch up fixed addresses. */ 36662306a36Sopenharmony_ci script_patch_32(hostdata, script, MessageLocation, 36762306a36Sopenharmony_ci pScript + MSGOUT_OFFSET); 36862306a36Sopenharmony_ci script_patch_32(hostdata, script, StatusAddress, 36962306a36Sopenharmony_ci pScript + STATUS_OFFSET); 37062306a36Sopenharmony_ci script_patch_32(hostdata, script, ReceiveMsgAddress, 37162306a36Sopenharmony_ci pScript + MSGIN_OFFSET); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci hostdata->script = script; 37462306a36Sopenharmony_ci hostdata->pScript = pScript; 37562306a36Sopenharmony_ci dma_sync_single_for_device(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE); 37662306a36Sopenharmony_ci hostdata->state = NCR_700_HOST_FREE; 37762306a36Sopenharmony_ci hostdata->cmd = NULL; 37862306a36Sopenharmony_ci host->max_id = 8; 37962306a36Sopenharmony_ci host->max_lun = NCR_700_MAX_LUNS; 38062306a36Sopenharmony_ci BUG_ON(NCR_700_transport_template == NULL); 38162306a36Sopenharmony_ci host->transportt = NCR_700_transport_template; 38262306a36Sopenharmony_ci host->unique_id = (unsigned long)hostdata->base; 38362306a36Sopenharmony_ci hostdata->eh_complete = NULL; 38462306a36Sopenharmony_ci host->hostdata[0] = (unsigned long)hostdata; 38562306a36Sopenharmony_ci /* kick the chip */ 38662306a36Sopenharmony_ci NCR_700_writeb(0xff, host, CTEST9_REG); 38762306a36Sopenharmony_ci if (hostdata->chip710) 38862306a36Sopenharmony_ci hostdata->rev = (NCR_700_readb(host, CTEST8_REG)>>4) & 0x0f; 38962306a36Sopenharmony_ci else 39062306a36Sopenharmony_ci hostdata->rev = (NCR_700_readb(host, CTEST7_REG)>>4) & 0x0f; 39162306a36Sopenharmony_ci hostdata->fast = (NCR_700_readb(host, CTEST9_REG) == 0); 39262306a36Sopenharmony_ci if (banner == 0) { 39362306a36Sopenharmony_ci printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley@HansenPartnership.com\n"); 39462306a36Sopenharmony_ci banner = 1; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no, 39762306a36Sopenharmony_ci hostdata->chip710 ? "53c710" : 39862306a36Sopenharmony_ci (hostdata->fast ? "53c700-66" : "53c700"), 39962306a36Sopenharmony_ci hostdata->rev, hostdata->differential ? 40062306a36Sopenharmony_ci "(Differential)" : ""); 40162306a36Sopenharmony_ci /* reset the chip */ 40262306a36Sopenharmony_ci NCR_700_chip_reset(host); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (scsi_add_host(host, dev)) { 40562306a36Sopenharmony_ci dev_printk(KERN_ERR, dev, "53c700: scsi_add_host failed\n"); 40662306a36Sopenharmony_ci scsi_host_put(host); 40762306a36Sopenharmony_ci return NULL; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci spi_signalling(host) = hostdata->differential ? SPI_SIGNAL_HVD : 41162306a36Sopenharmony_ci SPI_SIGNAL_SE; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return host; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ciint 41762306a36Sopenharmony_ciNCR_700_release(struct Scsi_Host *host) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 42062306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)host->hostdata[0]; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (hostdata->noncoherent) 42362306a36Sopenharmony_ci dma_free_noncoherent(hostdata->dev, TOTAL_MEM_SIZE, 42462306a36Sopenharmony_ci hostdata->script, hostdata->pScript, 42562306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 42662306a36Sopenharmony_ci else 42762306a36Sopenharmony_ci dma_free_coherent(hostdata->dev, TOTAL_MEM_SIZE, 42862306a36Sopenharmony_ci hostdata->script, hostdata->pScript); 42962306a36Sopenharmony_ci return 1; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic inline __u8 43362306a36Sopenharmony_ciNCR_700_identify(int can_disconnect, __u8 lun) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci return IDENTIFY_BASE | 43662306a36Sopenharmony_ci ((can_disconnect) ? 0x40 : 0) | 43762306a36Sopenharmony_ci (lun & NCR_700_LUN_MASK); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/* 44162306a36Sopenharmony_ci * Function : static int data_residual (Scsi_Host *host) 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * Purpose : return residual data count of what's in the chip. If you 44462306a36Sopenharmony_ci * really want to know what this function is doing, it's almost a 44562306a36Sopenharmony_ci * direct transcription of the algorithm described in the 53c710 44662306a36Sopenharmony_ci * guide, except that the DBC and DFIFO registers are only 6 bits 44762306a36Sopenharmony_ci * wide on a 53c700. 44862306a36Sopenharmony_ci * 44962306a36Sopenharmony_ci * Inputs : host - SCSI host */ 45062306a36Sopenharmony_cistatic inline int 45162306a36Sopenharmony_ciNCR_700_data_residual (struct Scsi_Host *host) { 45262306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 45362306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)host->hostdata[0]; 45462306a36Sopenharmony_ci int count, synchronous = 0; 45562306a36Sopenharmony_ci unsigned int ddir; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if(hostdata->chip710) { 45862306a36Sopenharmony_ci count = ((NCR_700_readb(host, DFIFO_REG) & 0x7f) - 45962306a36Sopenharmony_ci (NCR_700_readl(host, DBC_REG) & 0x7f)) & 0x7f; 46062306a36Sopenharmony_ci } else { 46162306a36Sopenharmony_ci count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) - 46262306a36Sopenharmony_ci (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if(hostdata->fast) 46662306a36Sopenharmony_ci synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* get the data direction */ 46962306a36Sopenharmony_ci ddir = NCR_700_readb(host, CTEST0_REG) & 0x01; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (ddir) { 47262306a36Sopenharmony_ci /* Receive */ 47362306a36Sopenharmony_ci if (synchronous) 47462306a36Sopenharmony_ci count += (NCR_700_readb(host, SSTAT2_REG) & 0xf0) >> 4; 47562306a36Sopenharmony_ci else 47662306a36Sopenharmony_ci if (NCR_700_readb(host, SSTAT1_REG) & SIDL_REG_FULL) 47762306a36Sopenharmony_ci ++count; 47862306a36Sopenharmony_ci } else { 47962306a36Sopenharmony_ci /* Send */ 48062306a36Sopenharmony_ci __u8 sstat = NCR_700_readb(host, SSTAT1_REG); 48162306a36Sopenharmony_ci if (sstat & SODL_REG_FULL) 48262306a36Sopenharmony_ci ++count; 48362306a36Sopenharmony_ci if (synchronous && (sstat & SODR_REG_FULL)) 48462306a36Sopenharmony_ci ++count; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 48762306a36Sopenharmony_ci if(count) 48862306a36Sopenharmony_ci printk("RESIDUAL IS %d (ddir %d)\n", count, ddir); 48962306a36Sopenharmony_ci#endif 49062306a36Sopenharmony_ci return count; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci/* print out the SCSI wires and corresponding phase from the SBCL register 49462306a36Sopenharmony_ci * in the chip */ 49562306a36Sopenharmony_cistatic inline char * 49662306a36Sopenharmony_cisbcl_to_string(__u8 sbcl) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci int i; 49962306a36Sopenharmony_ci static char ret[256]; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci ret[0]='\0'; 50262306a36Sopenharmony_ci for(i=0; i<8; i++) { 50362306a36Sopenharmony_ci if((1<<i) & sbcl) 50462306a36Sopenharmony_ci strcat(ret, NCR_700_SBCL_bits[i]); 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci strcat(ret, NCR_700_SBCL_to_phase[sbcl & 0x07]); 50762306a36Sopenharmony_ci return ret; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic inline __u8 51162306a36Sopenharmony_cibitmap_to_number(__u8 bitmap) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci __u8 i; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci for(i=0; i<8 && !(bitmap &(1<<i)); i++) 51662306a36Sopenharmony_ci ; 51762306a36Sopenharmony_ci return i; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci/* Pull a slot off the free list */ 52162306a36Sopenharmony_ciSTATIC struct NCR_700_command_slot * 52262306a36Sopenharmony_cifind_empty_slot(struct NCR_700_Host_Parameters *hostdata) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct NCR_700_command_slot *slot = hostdata->free_list; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if(slot == NULL) { 52762306a36Sopenharmony_ci /* sanity check */ 52862306a36Sopenharmony_ci if(hostdata->command_slot_count != NCR_700_COMMAND_SLOTS_PER_HOST) 52962306a36Sopenharmony_ci printk(KERN_ERR "SLOTS FULL, but count is %d, should be %d\n", hostdata->command_slot_count, NCR_700_COMMAND_SLOTS_PER_HOST); 53062306a36Sopenharmony_ci return NULL; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if(slot->state != NCR_700_SLOT_FREE) 53462306a36Sopenharmony_ci /* should panic! */ 53562306a36Sopenharmony_ci printk(KERN_ERR "BUSY SLOT ON FREE LIST!!!\n"); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci hostdata->free_list = slot->ITL_forw; 53962306a36Sopenharmony_ci slot->ITL_forw = NULL; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* NOTE: set the state to busy here, not queued, since this 54362306a36Sopenharmony_ci * indicates the slot is in use and cannot be run by the IRQ 54462306a36Sopenharmony_ci * finish routine. If we cannot queue the command when it 54562306a36Sopenharmony_ci * is properly build, we then change to NCR_700_SLOT_QUEUED */ 54662306a36Sopenharmony_ci slot->state = NCR_700_SLOT_BUSY; 54762306a36Sopenharmony_ci slot->flags = 0; 54862306a36Sopenharmony_ci hostdata->command_slot_count++; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return slot; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ciSTATIC void 55462306a36Sopenharmony_cifree_slot(struct NCR_700_command_slot *slot, 55562306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) { 55862306a36Sopenharmony_ci printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci if(slot->state == NCR_700_SLOT_FREE) { 56162306a36Sopenharmony_ci printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci slot->resume_offset = 0; 56562306a36Sopenharmony_ci slot->cmnd = NULL; 56662306a36Sopenharmony_ci slot->state = NCR_700_SLOT_FREE; 56762306a36Sopenharmony_ci slot->ITL_forw = hostdata->free_list; 56862306a36Sopenharmony_ci hostdata->free_list = slot; 56962306a36Sopenharmony_ci hostdata->command_slot_count--; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/* This routine really does very little. The command is indexed on 57462306a36Sopenharmony_ci the ITL and (if tagged) the ITLQ lists in _queuecommand */ 57562306a36Sopenharmony_ciSTATIC void 57662306a36Sopenharmony_cisave_for_reselection(struct NCR_700_Host_Parameters *hostdata, 57762306a36Sopenharmony_ci struct scsi_cmnd *SCp, __u32 dsp) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci /* Its just possible that this gets executed twice */ 58062306a36Sopenharmony_ci if(SCp != NULL) { 58162306a36Sopenharmony_ci struct NCR_700_command_slot *slot = 58262306a36Sopenharmony_ci (struct NCR_700_command_slot *)SCp->host_scribble; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci slot->resume_offset = dsp; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci hostdata->state = NCR_700_HOST_FREE; 58762306a36Sopenharmony_ci hostdata->cmd = NULL; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ciSTATIC inline void 59162306a36Sopenharmony_ciNCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp, 59262306a36Sopenharmony_ci struct NCR_700_command_slot *slot) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci if(SCp->sc_data_direction != DMA_NONE && 59562306a36Sopenharmony_ci SCp->sc_data_direction != DMA_BIDIRECTIONAL) 59662306a36Sopenharmony_ci scsi_dma_unmap(SCp); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ciSTATIC inline void 60062306a36Sopenharmony_ciNCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, 60162306a36Sopenharmony_ci struct scsi_cmnd *SCp, int result) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci hostdata->state = NCR_700_HOST_FREE; 60462306a36Sopenharmony_ci hostdata->cmd = NULL; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if(SCp != NULL) { 60762306a36Sopenharmony_ci struct NCR_700_command_slot *slot = 60862306a36Sopenharmony_ci (struct NCR_700_command_slot *)SCp->host_scribble; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci dma_unmap_single(hostdata->dev, slot->pCmd, 61162306a36Sopenharmony_ci MAX_COMMAND_SIZE, DMA_TO_DEVICE); 61262306a36Sopenharmony_ci if (slot->flags == NCR_700_FLAG_AUTOSENSE) { 61362306a36Sopenharmony_ci char *cmnd = NCR_700_get_sense_cmnd(SCp->device); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci dma_unmap_single(hostdata->dev, slot->dma_handle, 61662306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); 61762306a36Sopenharmony_ci /* restore the old result if the request sense was 61862306a36Sopenharmony_ci * successful */ 61962306a36Sopenharmony_ci if (result == 0) 62062306a36Sopenharmony_ci result = cmnd[7]; 62162306a36Sopenharmony_ci /* restore the original length */ 62262306a36Sopenharmony_ci SCp->cmd_len = cmnd[8]; 62362306a36Sopenharmony_ci } else 62462306a36Sopenharmony_ci NCR_700_unmap(hostdata, SCp, slot); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci free_slot(slot, hostdata); 62762306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 62862306a36Sopenharmony_ci if(NCR_700_get_depth(SCp->device) == 0 || 62962306a36Sopenharmony_ci NCR_700_get_depth(SCp->device) > SCp->device->queue_depth) 63062306a36Sopenharmony_ci printk(KERN_ERR "Invalid depth in NCR_700_scsi_done(): %d\n", 63162306a36Sopenharmony_ci NCR_700_get_depth(SCp->device)); 63262306a36Sopenharmony_ci#endif /* NCR_700_DEBUG */ 63362306a36Sopenharmony_ci NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci SCp->host_scribble = NULL; 63662306a36Sopenharmony_ci SCp->result = result; 63762306a36Sopenharmony_ci scsi_done(SCp); 63862306a36Sopenharmony_ci } else { 63962306a36Sopenharmony_ci printk(KERN_ERR "53c700: SCSI DONE HAS NULL SCp\n"); 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ciSTATIC void 64562306a36Sopenharmony_ciNCR_700_internal_bus_reset(struct Scsi_Host *host) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci /* Bus reset */ 64862306a36Sopenharmony_ci NCR_700_writeb(ASSERT_RST, host, SCNTL1_REG); 64962306a36Sopenharmony_ci udelay(50); 65062306a36Sopenharmony_ci NCR_700_writeb(0, host, SCNTL1_REG); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ciSTATIC void 65562306a36Sopenharmony_ciNCR_700_chip_setup(struct Scsi_Host *host) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 65862306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)host->hostdata[0]; 65962306a36Sopenharmony_ci __u8 min_period; 66062306a36Sopenharmony_ci __u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if(hostdata->chip710) { 66362306a36Sopenharmony_ci __u8 burst_disable = 0; 66462306a36Sopenharmony_ci __u8 burst_length = 0; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci switch (hostdata->burst_length) { 66762306a36Sopenharmony_ci case 1: 66862306a36Sopenharmony_ci burst_length = BURST_LENGTH_1; 66962306a36Sopenharmony_ci break; 67062306a36Sopenharmony_ci case 2: 67162306a36Sopenharmony_ci burst_length = BURST_LENGTH_2; 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci case 4: 67462306a36Sopenharmony_ci burst_length = BURST_LENGTH_4; 67562306a36Sopenharmony_ci break; 67662306a36Sopenharmony_ci case 8: 67762306a36Sopenharmony_ci burst_length = BURST_LENGTH_8; 67862306a36Sopenharmony_ci break; 67962306a36Sopenharmony_ci default: 68062306a36Sopenharmony_ci burst_disable = BURST_DISABLE; 68162306a36Sopenharmony_ci break; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci hostdata->dcntl_extra |= COMPAT_700_MODE; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci NCR_700_writeb(hostdata->dcntl_extra, host, DCNTL_REG); 68662306a36Sopenharmony_ci NCR_700_writeb(burst_length | hostdata->dmode_extra, 68762306a36Sopenharmony_ci host, DMODE_710_REG); 68862306a36Sopenharmony_ci NCR_700_writeb(burst_disable | hostdata->ctest7_extra | 68962306a36Sopenharmony_ci (hostdata->differential ? DIFF : 0), 69062306a36Sopenharmony_ci host, CTEST7_REG); 69162306a36Sopenharmony_ci NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG); 69262306a36Sopenharmony_ci NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY 69362306a36Sopenharmony_ci | AUTO_ATN, host, SCNTL0_REG); 69462306a36Sopenharmony_ci } else { 69562306a36Sopenharmony_ci NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra, 69662306a36Sopenharmony_ci host, DMODE_700_REG); 69762306a36Sopenharmony_ci NCR_700_writeb(hostdata->differential ? 69862306a36Sopenharmony_ci DIFF : 0, host, CTEST7_REG); 69962306a36Sopenharmony_ci if(hostdata->fast) { 70062306a36Sopenharmony_ci /* this is for 700-66, does nothing on 700 */ 70162306a36Sopenharmony_ci NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION 70262306a36Sopenharmony_ci | GENERATE_RECEIVE_PARITY, host, 70362306a36Sopenharmony_ci CTEST8_REG); 70462306a36Sopenharmony_ci } else { 70562306a36Sopenharmony_ci NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY 70662306a36Sopenharmony_ci | PARITY | AUTO_ATN, host, SCNTL0_REG); 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci NCR_700_writeb(1 << host->this_id, host, SCID_REG); 71162306a36Sopenharmony_ci NCR_700_writeb(0, host, SBCL_REG); 71262306a36Sopenharmony_ci NCR_700_writeb(ASYNC_OPERATION, host, SXFER_REG); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci NCR_700_writeb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT 71562306a36Sopenharmony_ci | RST_INT | PAR_ERR_INT | SELECT_INT, host, SIEN_REG); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci NCR_700_writeb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host, DIEN_REG); 71862306a36Sopenharmony_ci NCR_700_writeb(ENABLE_SELECT, host, SCNTL1_REG); 71962306a36Sopenharmony_ci if(hostdata->clock > 75) { 72062306a36Sopenharmony_ci printk(KERN_ERR "53c700: Clock speed %dMHz is too high: 75Mhz is the maximum this chip can be driven at\n", hostdata->clock); 72162306a36Sopenharmony_ci /* do the best we can, but the async clock will be out 72262306a36Sopenharmony_ci * of spec: sync divider 2, async divider 3 */ 72362306a36Sopenharmony_ci DEBUG(("53c700: sync 2 async 3\n")); 72462306a36Sopenharmony_ci NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG); 72562306a36Sopenharmony_ci NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG); 72662306a36Sopenharmony_ci hostdata->sync_clock = hostdata->clock/2; 72762306a36Sopenharmony_ci } else if(hostdata->clock > 50 && hostdata->clock <= 75) { 72862306a36Sopenharmony_ci /* sync divider 1.5, async divider 3 */ 72962306a36Sopenharmony_ci DEBUG(("53c700: sync 1.5 async 3\n")); 73062306a36Sopenharmony_ci NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG); 73162306a36Sopenharmony_ci NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG); 73262306a36Sopenharmony_ci hostdata->sync_clock = hostdata->clock*2; 73362306a36Sopenharmony_ci hostdata->sync_clock /= 3; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci } else if(hostdata->clock > 37 && hostdata->clock <= 50) { 73662306a36Sopenharmony_ci /* sync divider 1, async divider 2 */ 73762306a36Sopenharmony_ci DEBUG(("53c700: sync 1 async 2\n")); 73862306a36Sopenharmony_ci NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); 73962306a36Sopenharmony_ci NCR_700_writeb(ASYNC_DIV_2_0 | hostdata->dcntl_extra, host, DCNTL_REG); 74062306a36Sopenharmony_ci hostdata->sync_clock = hostdata->clock; 74162306a36Sopenharmony_ci } else if(hostdata->clock > 25 && hostdata->clock <=37) { 74262306a36Sopenharmony_ci /* sync divider 1, async divider 1.5 */ 74362306a36Sopenharmony_ci DEBUG(("53c700: sync 1 async 1.5\n")); 74462306a36Sopenharmony_ci NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); 74562306a36Sopenharmony_ci NCR_700_writeb(ASYNC_DIV_1_5 | hostdata->dcntl_extra, host, DCNTL_REG); 74662306a36Sopenharmony_ci hostdata->sync_clock = hostdata->clock; 74762306a36Sopenharmony_ci } else { 74862306a36Sopenharmony_ci DEBUG(("53c700: sync 1 async 1\n")); 74962306a36Sopenharmony_ci NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); 75062306a36Sopenharmony_ci NCR_700_writeb(ASYNC_DIV_1_0 | hostdata->dcntl_extra, host, DCNTL_REG); 75162306a36Sopenharmony_ci /* sync divider 1, async divider 1 */ 75262306a36Sopenharmony_ci hostdata->sync_clock = hostdata->clock; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci /* Calculate the actual minimum period that can be supported 75562306a36Sopenharmony_ci * by our synchronous clock speed. See the 710 manual for 75662306a36Sopenharmony_ci * exact details of this calculation which is based on a 75762306a36Sopenharmony_ci * setting of the SXFER register */ 75862306a36Sopenharmony_ci min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock); 75962306a36Sopenharmony_ci hostdata->min_period = NCR_700_MIN_PERIOD; 76062306a36Sopenharmony_ci if(min_period > NCR_700_MIN_PERIOD) 76162306a36Sopenharmony_ci hostdata->min_period = min_period; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ciSTATIC void 76562306a36Sopenharmony_ciNCR_700_chip_reset(struct Scsi_Host *host) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 76862306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)host->hostdata[0]; 76962306a36Sopenharmony_ci if(hostdata->chip710) { 77062306a36Sopenharmony_ci NCR_700_writeb(SOFTWARE_RESET_710, host, ISTAT_REG); 77162306a36Sopenharmony_ci udelay(100); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci NCR_700_writeb(0, host, ISTAT_REG); 77462306a36Sopenharmony_ci } else { 77562306a36Sopenharmony_ci NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG); 77662306a36Sopenharmony_ci udelay(100); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci NCR_700_writeb(0, host, DCNTL_REG); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci mdelay(1000); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci NCR_700_chip_setup(host); 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/* The heart of the message processing engine is that the instruction 78762306a36Sopenharmony_ci * immediately after the INT is the normal case (and so must be CLEAR 78862306a36Sopenharmony_ci * ACK). If we want to do something else, we call that routine in 78962306a36Sopenharmony_ci * scripts and set temp to be the normal case + 8 (skipping the CLEAR 79062306a36Sopenharmony_ci * ACK) so that the routine returns correctly to resume its activity 79162306a36Sopenharmony_ci * */ 79262306a36Sopenharmony_ciSTATIC __u32 79362306a36Sopenharmony_ciprocess_extended_message(struct Scsi_Host *host, 79462306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata, 79562306a36Sopenharmony_ci struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci __u32 resume_offset = dsp, temp = dsp + 8; 79862306a36Sopenharmony_ci __u8 pun = 0xff, lun = 0xff; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if(SCp != NULL) { 80162306a36Sopenharmony_ci pun = SCp->device->id; 80262306a36Sopenharmony_ci lun = SCp->device->lun; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci switch(hostdata->msgin[2]) { 80662306a36Sopenharmony_ci case A_SDTR_MSG: 80762306a36Sopenharmony_ci if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { 80862306a36Sopenharmony_ci struct scsi_target *starget = SCp->device->sdev_target; 80962306a36Sopenharmony_ci __u8 period = hostdata->msgin[3]; 81062306a36Sopenharmony_ci __u8 offset = hostdata->msgin[4]; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if(offset == 0 || period == 0) { 81362306a36Sopenharmony_ci offset = 0; 81462306a36Sopenharmony_ci period = 0; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci spi_offset(starget) = offset; 81862306a36Sopenharmony_ci spi_period(starget) = period; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) { 82162306a36Sopenharmony_ci spi_display_xfer_agreement(starget); 82262306a36Sopenharmony_ci NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); 82662306a36Sopenharmony_ci NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci NCR_700_writeb(NCR_700_get_SXFER(SCp->device), 82962306a36Sopenharmony_ci host, SXFER_REG); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci } else { 83262306a36Sopenharmony_ci /* SDTR message out of the blue, reject it */ 83362306a36Sopenharmony_ci shost_printk(KERN_WARNING, host, 83462306a36Sopenharmony_ci "Unexpected SDTR msg\n"); 83562306a36Sopenharmony_ci hostdata->msgout[0] = A_REJECT_MSG; 83662306a36Sopenharmony_ci dma_sync_to_dev(hostdata, hostdata->msgout, 1); 83762306a36Sopenharmony_ci script_patch_16(hostdata, hostdata->script, 83862306a36Sopenharmony_ci MessageCount, 1); 83962306a36Sopenharmony_ci /* SendMsgOut returns, so set up the return 84062306a36Sopenharmony_ci * address */ 84162306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_SendMessageWithATN; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci break; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci case A_WDTR_MSG: 84662306a36Sopenharmony_ci printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n", 84762306a36Sopenharmony_ci host->host_no, pun, lun); 84862306a36Sopenharmony_ci hostdata->msgout[0] = A_REJECT_MSG; 84962306a36Sopenharmony_ci dma_sync_to_dev(hostdata, hostdata->msgout, 1); 85062306a36Sopenharmony_ci script_patch_16(hostdata, hostdata->script, MessageCount, 1); 85162306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_SendMessageWithATN; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci break; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci default: 85662306a36Sopenharmony_ci printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ", 85762306a36Sopenharmony_ci host->host_no, pun, lun, 85862306a36Sopenharmony_ci NCR_700_phase[(dsps & 0xf00) >> 8]); 85962306a36Sopenharmony_ci spi_print_msg(hostdata->msgin); 86062306a36Sopenharmony_ci printk("\n"); 86162306a36Sopenharmony_ci /* just reject it */ 86262306a36Sopenharmony_ci hostdata->msgout[0] = A_REJECT_MSG; 86362306a36Sopenharmony_ci dma_sync_to_dev(hostdata, hostdata->msgout, 1); 86462306a36Sopenharmony_ci script_patch_16(hostdata, hostdata->script, MessageCount, 1); 86562306a36Sopenharmony_ci /* SendMsgOut returns, so set up the return 86662306a36Sopenharmony_ci * address */ 86762306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_SendMessageWithATN; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci NCR_700_writel(temp, host, TEMP_REG); 87062306a36Sopenharmony_ci return resume_offset; 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ciSTATIC __u32 87462306a36Sopenharmony_ciprocess_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata, 87562306a36Sopenharmony_ci struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci /* work out where to return to */ 87862306a36Sopenharmony_ci __u32 temp = dsp + 8, resume_offset = dsp; 87962306a36Sopenharmony_ci __u8 pun = 0xff, lun = 0xff; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if(SCp != NULL) { 88262306a36Sopenharmony_ci pun = SCp->device->id; 88362306a36Sopenharmony_ci lun = SCp->device->lun; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 88762306a36Sopenharmony_ci printk("scsi%d (%d:%d): message %s: ", host->host_no, pun, lun, 88862306a36Sopenharmony_ci NCR_700_phase[(dsps & 0xf00) >> 8]); 88962306a36Sopenharmony_ci spi_print_msg(hostdata->msgin); 89062306a36Sopenharmony_ci printk("\n"); 89162306a36Sopenharmony_ci#endif 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci switch(hostdata->msgin[0]) { 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci case A_EXTENDED_MSG: 89662306a36Sopenharmony_ci resume_offset = process_extended_message(host, hostdata, SCp, 89762306a36Sopenharmony_ci dsp, dsps); 89862306a36Sopenharmony_ci break; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci case A_REJECT_MSG: 90162306a36Sopenharmony_ci if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { 90262306a36Sopenharmony_ci /* Rejected our sync negotiation attempt */ 90362306a36Sopenharmony_ci spi_period(SCp->device->sdev_target) = 90462306a36Sopenharmony_ci spi_offset(SCp->device->sdev_target) = 0; 90562306a36Sopenharmony_ci NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); 90662306a36Sopenharmony_ci NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); 90762306a36Sopenharmony_ci } else if(SCp != NULL && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION) { 90862306a36Sopenharmony_ci /* rejected our first simple tag message */ 90962306a36Sopenharmony_ci scmd_printk(KERN_WARNING, SCp, 91062306a36Sopenharmony_ci "Rejected first tag queue attempt, turning off tag queueing\n"); 91162306a36Sopenharmony_ci /* we're done negotiating */ 91262306a36Sopenharmony_ci NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION); 91362306a36Sopenharmony_ci hostdata->tag_negotiated &= ~(1<<scmd_id(SCp)); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci SCp->device->tagged_supported = 0; 91662306a36Sopenharmony_ci SCp->device->simple_tags = 0; 91762306a36Sopenharmony_ci scsi_change_queue_depth(SCp->device, host->cmd_per_lun); 91862306a36Sopenharmony_ci } else { 91962306a36Sopenharmony_ci shost_printk(KERN_WARNING, host, 92062306a36Sopenharmony_ci "(%d:%d) Unexpected REJECT Message %s\n", 92162306a36Sopenharmony_ci pun, lun, 92262306a36Sopenharmony_ci NCR_700_phase[(dsps & 0xf00) >> 8]); 92362306a36Sopenharmony_ci /* however, just ignore it */ 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci break; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci case A_PARITY_ERROR_MSG: 92862306a36Sopenharmony_ci printk(KERN_ERR "scsi%d (%d:%d) Parity Error!\n", host->host_no, 92962306a36Sopenharmony_ci pun, lun); 93062306a36Sopenharmony_ci NCR_700_internal_bus_reset(host); 93162306a36Sopenharmony_ci break; 93262306a36Sopenharmony_ci case A_SIMPLE_TAG_MSG: 93362306a36Sopenharmony_ci printk(KERN_INFO "scsi%d (%d:%d) SIMPLE TAG %d %s\n", host->host_no, 93462306a36Sopenharmony_ci pun, lun, hostdata->msgin[1], 93562306a36Sopenharmony_ci NCR_700_phase[(dsps & 0xf00) >> 8]); 93662306a36Sopenharmony_ci /* just ignore it */ 93762306a36Sopenharmony_ci break; 93862306a36Sopenharmony_ci default: 93962306a36Sopenharmony_ci printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ", 94062306a36Sopenharmony_ci host->host_no, pun, lun, 94162306a36Sopenharmony_ci NCR_700_phase[(dsps & 0xf00) >> 8]); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci spi_print_msg(hostdata->msgin); 94462306a36Sopenharmony_ci printk("\n"); 94562306a36Sopenharmony_ci /* just reject it */ 94662306a36Sopenharmony_ci hostdata->msgout[0] = A_REJECT_MSG; 94762306a36Sopenharmony_ci dma_sync_to_dev(hostdata, hostdata->msgout, 1); 94862306a36Sopenharmony_ci script_patch_16(hostdata, hostdata->script, MessageCount, 1); 94962306a36Sopenharmony_ci /* SendMsgOut returns, so set up the return 95062306a36Sopenharmony_ci * address */ 95162306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_SendMessageWithATN; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci NCR_700_writel(temp, host, TEMP_REG); 95662306a36Sopenharmony_ci /* set us up to receive another message */ 95762306a36Sopenharmony_ci dma_sync_from_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE); 95862306a36Sopenharmony_ci return resume_offset; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ciSTATIC __u32 96262306a36Sopenharmony_ciprocess_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, 96362306a36Sopenharmony_ci struct Scsi_Host *host, 96462306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci __u32 resume_offset = 0; 96762306a36Sopenharmony_ci __u8 pun = 0xff, lun=0xff; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if(SCp != NULL) { 97062306a36Sopenharmony_ci pun = SCp->device->id; 97162306a36Sopenharmony_ci lun = SCp->device->lun; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if(dsps == A_GOOD_STATUS_AFTER_STATUS) { 97562306a36Sopenharmony_ci DEBUG((" COMMAND COMPLETE, status=%02x\n", 97662306a36Sopenharmony_ci hostdata->status[0])); 97762306a36Sopenharmony_ci /* OK, if TCQ still under negotiation, we now know it works */ 97862306a36Sopenharmony_ci if (NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION) 97962306a36Sopenharmony_ci NCR_700_set_tag_neg_state(SCp->device, 98062306a36Sopenharmony_ci NCR_700_FINISHED_TAG_NEGOTIATION); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* check for contingent allegiance conditions */ 98362306a36Sopenharmony_ci if (hostdata->status[0] == SAM_STAT_CHECK_CONDITION || 98462306a36Sopenharmony_ci hostdata->status[0] == SAM_STAT_COMMAND_TERMINATED) { 98562306a36Sopenharmony_ci struct NCR_700_command_slot *slot = 98662306a36Sopenharmony_ci (struct NCR_700_command_slot *)SCp->host_scribble; 98762306a36Sopenharmony_ci if(slot->flags == NCR_700_FLAG_AUTOSENSE) { 98862306a36Sopenharmony_ci /* OOPS: bad device, returning another 98962306a36Sopenharmony_ci * contingent allegiance condition */ 99062306a36Sopenharmony_ci scmd_printk(KERN_ERR, SCp, 99162306a36Sopenharmony_ci "broken device is looping in contingent allegiance: ignoring\n"); 99262306a36Sopenharmony_ci NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); 99362306a36Sopenharmony_ci } else { 99462306a36Sopenharmony_ci char *cmnd = 99562306a36Sopenharmony_ci NCR_700_get_sense_cmnd(SCp->device); 99662306a36Sopenharmony_ci#ifdef NCR_DEBUG 99762306a36Sopenharmony_ci scsi_print_command(SCp); 99862306a36Sopenharmony_ci printk(" cmd %p has status %d, requesting sense\n", 99962306a36Sopenharmony_ci SCp, hostdata->status[0]); 100062306a36Sopenharmony_ci#endif 100162306a36Sopenharmony_ci /* we can destroy the command here 100262306a36Sopenharmony_ci * because the contingent allegiance 100362306a36Sopenharmony_ci * condition will cause a retry which 100462306a36Sopenharmony_ci * will re-copy the command from the 100562306a36Sopenharmony_ci * saved data_cmnd. We also unmap any 100662306a36Sopenharmony_ci * data associated with the command 100762306a36Sopenharmony_ci * here */ 100862306a36Sopenharmony_ci NCR_700_unmap(hostdata, SCp, slot); 100962306a36Sopenharmony_ci dma_unmap_single(hostdata->dev, slot->pCmd, 101062306a36Sopenharmony_ci MAX_COMMAND_SIZE, 101162306a36Sopenharmony_ci DMA_TO_DEVICE); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci cmnd[0] = REQUEST_SENSE; 101462306a36Sopenharmony_ci cmnd[1] = (lun & 0x7) << 5; 101562306a36Sopenharmony_ci cmnd[2] = 0; 101662306a36Sopenharmony_ci cmnd[3] = 0; 101762306a36Sopenharmony_ci cmnd[4] = SCSI_SENSE_BUFFERSIZE; 101862306a36Sopenharmony_ci cmnd[5] = 0; 101962306a36Sopenharmony_ci /* Here's a quiet hack: the 102062306a36Sopenharmony_ci * REQUEST_SENSE command is six bytes, 102162306a36Sopenharmony_ci * so store a flag indicating that 102262306a36Sopenharmony_ci * this was an internal sense request 102362306a36Sopenharmony_ci * and the original status at the end 102462306a36Sopenharmony_ci * of the command */ 102562306a36Sopenharmony_ci cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; 102662306a36Sopenharmony_ci cmnd[7] = hostdata->status[0]; 102762306a36Sopenharmony_ci cmnd[8] = SCp->cmd_len; 102862306a36Sopenharmony_ci SCp->cmd_len = 6; /* command length for 102962306a36Sopenharmony_ci * REQUEST_SENSE */ 103062306a36Sopenharmony_ci slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE); 103162306a36Sopenharmony_ci slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); 103262306a36Sopenharmony_ci slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | SCSI_SENSE_BUFFERSIZE); 103362306a36Sopenharmony_ci slot->SG[0].pAddr = bS_to_host(slot->dma_handle); 103462306a36Sopenharmony_ci slot->SG[1].ins = bS_to_host(SCRIPT_RETURN); 103562306a36Sopenharmony_ci slot->SG[1].pAddr = 0; 103662306a36Sopenharmony_ci slot->resume_offset = hostdata->pScript; 103762306a36Sopenharmony_ci dma_sync_to_dev(hostdata, slot->SG, sizeof(slot->SG[0])*2); 103862306a36Sopenharmony_ci dma_sync_from_dev(hostdata, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* queue the command for reissue */ 104162306a36Sopenharmony_ci slot->state = NCR_700_SLOT_QUEUED; 104262306a36Sopenharmony_ci slot->flags = NCR_700_FLAG_AUTOSENSE; 104362306a36Sopenharmony_ci hostdata->state = NCR_700_HOST_FREE; 104462306a36Sopenharmony_ci hostdata->cmd = NULL; 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci } else { 104762306a36Sopenharmony_ci // Currently rely on the mid layer evaluation 104862306a36Sopenharmony_ci // of the tag queuing capability 104962306a36Sopenharmony_ci // 105062306a36Sopenharmony_ci //if(status_byte(hostdata->status[0]) == GOOD && 105162306a36Sopenharmony_ci // SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) { 105262306a36Sopenharmony_ci // /* Piggy back the tag queueing support 105362306a36Sopenharmony_ci // * on this command */ 105462306a36Sopenharmony_ci // dma_sync_single_for_cpu(hostdata->dev, 105562306a36Sopenharmony_ci // slot->dma_handle, 105662306a36Sopenharmony_ci // SCp->request_bufflen, 105762306a36Sopenharmony_ci // DMA_FROM_DEVICE); 105862306a36Sopenharmony_ci // if(((char *)SCp->request_buffer)[7] & 0x02) { 105962306a36Sopenharmony_ci // scmd_printk(KERN_INFO, SCp, 106062306a36Sopenharmony_ci // "Enabling Tag Command Queuing\n"); 106162306a36Sopenharmony_ci // hostdata->tag_negotiated |= (1<<scmd_id(SCp)); 106262306a36Sopenharmony_ci // NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); 106362306a36Sopenharmony_ci // } else { 106462306a36Sopenharmony_ci // NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); 106562306a36Sopenharmony_ci // hostdata->tag_negotiated &= ~(1<<scmd_id(SCp)); 106662306a36Sopenharmony_ci // } 106762306a36Sopenharmony_ci //} 106862306a36Sopenharmony_ci NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci } else if((dsps & 0xfffff0f0) == A_UNEXPECTED_PHASE) { 107162306a36Sopenharmony_ci __u8 i = (dsps & 0xf00) >> 8; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci scmd_printk(KERN_ERR, SCp, "UNEXPECTED PHASE %s (%s)\n", 107462306a36Sopenharmony_ci NCR_700_phase[i], 107562306a36Sopenharmony_ci sbcl_to_string(NCR_700_readb(host, SBCL_REG))); 107662306a36Sopenharmony_ci scmd_printk(KERN_ERR, SCp, " len = %d, cmd =", 107762306a36Sopenharmony_ci SCp->cmd_len); 107862306a36Sopenharmony_ci scsi_print_command(SCp); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci NCR_700_internal_bus_reset(host); 108162306a36Sopenharmony_ci } else if((dsps & 0xfffff000) == A_FATAL) { 108262306a36Sopenharmony_ci int i = (dsps & 0xfff); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d) FATAL ERROR: %s\n", 108562306a36Sopenharmony_ci host->host_no, pun, lun, NCR_700_fatal_messages[i]); 108662306a36Sopenharmony_ci if(dsps == A_FATAL_ILLEGAL_MSG_LENGTH) { 108762306a36Sopenharmony_ci printk(KERN_ERR " msg begins %02x %02x\n", 108862306a36Sopenharmony_ci hostdata->msgin[0], hostdata->msgin[1]); 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci NCR_700_internal_bus_reset(host); 109162306a36Sopenharmony_ci } else if((dsps & 0xfffff0f0) == A_DISCONNECT) { 109262306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 109362306a36Sopenharmony_ci __u8 i = (dsps & 0xf00) >> 8; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci printk("scsi%d: (%d:%d), DISCONNECTED (%d) %s\n", 109662306a36Sopenharmony_ci host->host_no, pun, lun, 109762306a36Sopenharmony_ci i, NCR_700_phase[i]); 109862306a36Sopenharmony_ci#endif 109962306a36Sopenharmony_ci save_for_reselection(hostdata, SCp, dsp); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci } else if(dsps == A_RESELECTION_IDENTIFIED) { 110262306a36Sopenharmony_ci __u8 lun; 110362306a36Sopenharmony_ci struct NCR_700_command_slot *slot; 110462306a36Sopenharmony_ci __u8 reselection_id = hostdata->reselection_id; 110562306a36Sopenharmony_ci struct scsi_device *SDp; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci lun = hostdata->msgin[0] & 0x1f; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci hostdata->reselection_id = 0xff; 111062306a36Sopenharmony_ci DEBUG(("scsi%d: (%d:%d) RESELECTED!\n", 111162306a36Sopenharmony_ci host->host_no, reselection_id, lun)); 111262306a36Sopenharmony_ci /* clear the reselection indicator */ 111362306a36Sopenharmony_ci SDp = __scsi_device_lookup(host, 0, reselection_id, lun); 111462306a36Sopenharmony_ci if(unlikely(SDp == NULL)) { 111562306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d) HAS NO device\n", 111662306a36Sopenharmony_ci host->host_no, reselection_id, lun); 111762306a36Sopenharmony_ci BUG(); 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) { 112062306a36Sopenharmony_ci struct scsi_cmnd *SCp; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci SCp = scsi_host_find_tag(SDp->host, hostdata->msgin[2]); 112362306a36Sopenharmony_ci if(unlikely(SCp == NULL)) { 112462306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n", 112562306a36Sopenharmony_ci host->host_no, reselection_id, lun, hostdata->msgin[2]); 112662306a36Sopenharmony_ci BUG(); 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci slot = (struct NCR_700_command_slot *)SCp->host_scribble; 113062306a36Sopenharmony_ci DDEBUG(KERN_DEBUG, SDp, 113162306a36Sopenharmony_ci "reselection is tag %d, slot %p(%d)\n", 113262306a36Sopenharmony_ci hostdata->msgin[2], slot, slot->tag); 113362306a36Sopenharmony_ci } else { 113462306a36Sopenharmony_ci struct NCR_700_Device_Parameters *p = SDp->hostdata; 113562306a36Sopenharmony_ci struct scsi_cmnd *SCp = p->current_cmnd; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if(unlikely(SCp == NULL)) { 113862306a36Sopenharmony_ci sdev_printk(KERN_ERR, SDp, 113962306a36Sopenharmony_ci "no saved request for untagged cmd\n"); 114062306a36Sopenharmony_ci BUG(); 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci slot = (struct NCR_700_command_slot *)SCp->host_scribble; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci if(slot == NULL) { 114662306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n", 114762306a36Sopenharmony_ci host->host_no, reselection_id, lun, 114862306a36Sopenharmony_ci hostdata->msgin[0], hostdata->msgin[1], 114962306a36Sopenharmony_ci hostdata->msgin[2]); 115062306a36Sopenharmony_ci } else { 115162306a36Sopenharmony_ci if(hostdata->state != NCR_700_HOST_BUSY) 115262306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n", 115362306a36Sopenharmony_ci host->host_no); 115462306a36Sopenharmony_ci resume_offset = slot->resume_offset; 115562306a36Sopenharmony_ci hostdata->cmd = slot->cmnd; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci /* re-patch for this command */ 115862306a36Sopenharmony_ci script_patch_32_abs(hostdata, hostdata->script, 115962306a36Sopenharmony_ci CommandAddress, slot->pCmd); 116062306a36Sopenharmony_ci script_patch_16(hostdata, hostdata->script, 116162306a36Sopenharmony_ci CommandCount, slot->cmnd->cmd_len); 116262306a36Sopenharmony_ci script_patch_32_abs(hostdata, hostdata->script, 116362306a36Sopenharmony_ci SGScriptStartAddress, 116462306a36Sopenharmony_ci to32bit(&slot->pSG[0].ins)); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci /* Note: setting SXFER only works if we're 116762306a36Sopenharmony_ci * still in the MESSAGE phase, so it is vital 116862306a36Sopenharmony_ci * that ACK is still asserted when we process 116962306a36Sopenharmony_ci * the reselection message. The resume offset 117062306a36Sopenharmony_ci * should therefore always clear ACK */ 117162306a36Sopenharmony_ci NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device), 117262306a36Sopenharmony_ci host, SXFER_REG); 117362306a36Sopenharmony_ci dma_sync_from_dev(hostdata, hostdata->msgin, 117462306a36Sopenharmony_ci MSG_ARRAY_SIZE); 117562306a36Sopenharmony_ci dma_sync_to_dev(hostdata, hostdata->msgout, 117662306a36Sopenharmony_ci MSG_ARRAY_SIZE); 117762306a36Sopenharmony_ci /* I'm just being paranoid here, the command should 117862306a36Sopenharmony_ci * already have been flushed from the cache */ 117962306a36Sopenharmony_ci dma_sync_to_dev(hostdata, slot->cmnd->cmnd, 118062306a36Sopenharmony_ci slot->cmnd->cmd_len); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci } else if(dsps == A_RESELECTED_DURING_SELECTION) { 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci /* This section is full of debugging code because I've 118862306a36Sopenharmony_ci * never managed to reach it. I think what happens is 118962306a36Sopenharmony_ci * that, because the 700 runs with selection 119062306a36Sopenharmony_ci * interrupts enabled the whole time that we take a 119162306a36Sopenharmony_ci * selection interrupt before we manage to get to the 119262306a36Sopenharmony_ci * reselected script interrupt */ 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci __u8 reselection_id = NCR_700_readb(host, SFBR_REG); 119562306a36Sopenharmony_ci struct NCR_700_command_slot *slot; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci /* Take out our own ID */ 119862306a36Sopenharmony_ci reselection_id &= ~(1<<host->this_id); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* I've never seen this happen, so keep this as a printk rather 120162306a36Sopenharmony_ci * than a debug */ 120262306a36Sopenharmony_ci printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%08x[%04x] state=%d, count=%d\n", 120362306a36Sopenharmony_ci host->host_no, reselection_id, lun, dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci { 120662306a36Sopenharmony_ci /* FIXME: DEBUGGING CODE */ 120762306a36Sopenharmony_ci __u32 SG = (__u32)bS_to_cpu(hostdata->script[A_SGScriptStartAddress_used[0]]); 120862306a36Sopenharmony_ci int i; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci for(i=0; i< NCR_700_COMMAND_SLOTS_PER_HOST; i++) { 121162306a36Sopenharmony_ci if(SG >= to32bit(&hostdata->slots[i].pSG[0]) 121262306a36Sopenharmony_ci && SG <= to32bit(&hostdata->slots[i].pSG[NCR_700_SG_SEGMENTS])) 121362306a36Sopenharmony_ci break; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci printk(KERN_INFO "IDENTIFIED SG segment as being %08x in slot %p, cmd %p, slot->resume_offset=%08x\n", SG, &hostdata->slots[i], hostdata->slots[i].cmnd, hostdata->slots[i].resume_offset); 121662306a36Sopenharmony_ci SCp = hostdata->slots[i].cmnd; 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci if(SCp != NULL) { 122062306a36Sopenharmony_ci slot = (struct NCR_700_command_slot *)SCp->host_scribble; 122162306a36Sopenharmony_ci /* change slot from busy to queued to redo command */ 122262306a36Sopenharmony_ci slot->state = NCR_700_SLOT_QUEUED; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci hostdata->cmd = NULL; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if(reselection_id == 0) { 122762306a36Sopenharmony_ci if(hostdata->reselection_id == 0xff) { 122862306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: Invalid reselection during selection!!\n", host->host_no); 122962306a36Sopenharmony_ci return 0; 123062306a36Sopenharmony_ci } else { 123162306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: script reselected and we took a selection interrupt\n", 123262306a36Sopenharmony_ci host->host_no); 123362306a36Sopenharmony_ci reselection_id = hostdata->reselection_id; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci } else { 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* convert to real ID */ 123862306a36Sopenharmony_ci reselection_id = bitmap_to_number(reselection_id); 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci hostdata->reselection_id = reselection_id; 124162306a36Sopenharmony_ci /* just in case we have a stale simple tag message, clear it */ 124262306a36Sopenharmony_ci hostdata->msgin[1] = 0; 124362306a36Sopenharmony_ci dma_sync_to_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE); 124462306a36Sopenharmony_ci if(hostdata->tag_negotiated & (1<<reselection_id)) { 124562306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_GetReselectionWithTag; 124662306a36Sopenharmony_ci } else { 124762306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_GetReselectionData; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci } else if(dsps == A_COMPLETED_SELECTION_AS_TARGET) { 125062306a36Sopenharmony_ci /* we've just disconnected from the bus, do nothing since 125162306a36Sopenharmony_ci * a return here will re-run the queued command slot 125262306a36Sopenharmony_ci * that may have been interrupted by the initial selection */ 125362306a36Sopenharmony_ci DEBUG((" SELECTION COMPLETED\n")); 125462306a36Sopenharmony_ci } else if((dsps & 0xfffff0f0) == A_MSG_IN) { 125562306a36Sopenharmony_ci resume_offset = process_message(host, hostdata, SCp, 125662306a36Sopenharmony_ci dsp, dsps); 125762306a36Sopenharmony_ci } else if((dsps & 0xfffff000) == 0) { 125862306a36Sopenharmony_ci __u8 i = (dsps & 0xf0) >> 4, j = (dsps & 0xf00) >> 8; 125962306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d), unhandled script condition %s %s at %04x\n", 126062306a36Sopenharmony_ci host->host_no, pun, lun, NCR_700_condition[i], 126162306a36Sopenharmony_ci NCR_700_phase[j], dsp - hostdata->pScript); 126262306a36Sopenharmony_ci if(SCp != NULL) { 126362306a36Sopenharmony_ci struct scatterlist *sg; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci scsi_print_command(SCp); 126662306a36Sopenharmony_ci scsi_for_each_sg(SCp, sg, scsi_sg_count(SCp) + 1, i) { 126762306a36Sopenharmony_ci printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, sg->length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr); 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci NCR_700_internal_bus_reset(host); 127162306a36Sopenharmony_ci } else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) { 127262306a36Sopenharmony_ci printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %08x[%04x], continuing\n", 127362306a36Sopenharmony_ci host->host_no, pun, lun, dsps & 0xfff, dsp, dsp - hostdata->pScript); 127462306a36Sopenharmony_ci resume_offset = dsp; 127562306a36Sopenharmony_ci } else { 127662306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d), unidentified script interrupt 0x%x at %04x\n", 127762306a36Sopenharmony_ci host->host_no, pun, lun, dsps, dsp - hostdata->pScript); 127862306a36Sopenharmony_ci NCR_700_internal_bus_reset(host); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci return resume_offset; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci/* We run the 53c700 with selection interrupts always enabled. This 128462306a36Sopenharmony_ci * means that the chip may be selected as soon as the bus frees. On a 128562306a36Sopenharmony_ci * busy bus, this can be before the scripts engine finishes its 128662306a36Sopenharmony_ci * processing. Therefore, part of the selection processing has to be 128762306a36Sopenharmony_ci * to find out what the scripts engine is doing and complete the 128862306a36Sopenharmony_ci * function if necessary (i.e. process the pending disconnect or save 128962306a36Sopenharmony_ci * the interrupted initial selection */ 129062306a36Sopenharmony_ciSTATIC inline __u32 129162306a36Sopenharmony_ciprocess_selection(struct Scsi_Host *host, __u32 dsp) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci __u8 id = 0; /* Squash compiler warning */ 129462306a36Sopenharmony_ci int count = 0; 129562306a36Sopenharmony_ci __u32 resume_offset = 0; 129662306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 129762306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)host->hostdata[0]; 129862306a36Sopenharmony_ci struct scsi_cmnd *SCp = hostdata->cmd; 129962306a36Sopenharmony_ci __u8 sbcl; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci for(count = 0; count < 5; count++) { 130262306a36Sopenharmony_ci id = NCR_700_readb(host, hostdata->chip710 ? 130362306a36Sopenharmony_ci CTEST9_REG : SFBR_REG); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci /* Take out our own ID */ 130662306a36Sopenharmony_ci id &= ~(1<<host->this_id); 130762306a36Sopenharmony_ci if(id != 0) 130862306a36Sopenharmony_ci break; 130962306a36Sopenharmony_ci udelay(5); 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci sbcl = NCR_700_readb(host, SBCL_REG); 131262306a36Sopenharmony_ci if((sbcl & SBCL_IO) == 0) { 131362306a36Sopenharmony_ci /* mark as having been selected rather than reselected */ 131462306a36Sopenharmony_ci id = 0xff; 131562306a36Sopenharmony_ci } else { 131662306a36Sopenharmony_ci /* convert to real ID */ 131762306a36Sopenharmony_ci hostdata->reselection_id = id = bitmap_to_number(id); 131862306a36Sopenharmony_ci DEBUG(("scsi%d: Reselected by %d\n", 131962306a36Sopenharmony_ci host->host_no, id)); 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci if(hostdata->state == NCR_700_HOST_BUSY && SCp != NULL) { 132262306a36Sopenharmony_ci struct NCR_700_command_slot *slot = 132362306a36Sopenharmony_ci (struct NCR_700_command_slot *)SCp->host_scribble; 132462306a36Sopenharmony_ci DEBUG((" ID %d WARNING: RESELECTION OF BUSY HOST, saving cmd %p, slot %p, addr %x [%04x], resume %x!\n", id, hostdata->cmd, slot, dsp, dsp - hostdata->pScript, resume_offset)); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci switch(dsp - hostdata->pScript) { 132762306a36Sopenharmony_ci case Ent_Disconnect1: 132862306a36Sopenharmony_ci case Ent_Disconnect2: 132962306a36Sopenharmony_ci save_for_reselection(hostdata, SCp, Ent_Disconnect2 + hostdata->pScript); 133062306a36Sopenharmony_ci break; 133162306a36Sopenharmony_ci case Ent_Disconnect3: 133262306a36Sopenharmony_ci case Ent_Disconnect4: 133362306a36Sopenharmony_ci save_for_reselection(hostdata, SCp, Ent_Disconnect4 + hostdata->pScript); 133462306a36Sopenharmony_ci break; 133562306a36Sopenharmony_ci case Ent_Disconnect5: 133662306a36Sopenharmony_ci case Ent_Disconnect6: 133762306a36Sopenharmony_ci save_for_reselection(hostdata, SCp, Ent_Disconnect6 + hostdata->pScript); 133862306a36Sopenharmony_ci break; 133962306a36Sopenharmony_ci case Ent_Disconnect7: 134062306a36Sopenharmony_ci case Ent_Disconnect8: 134162306a36Sopenharmony_ci save_for_reselection(hostdata, SCp, Ent_Disconnect8 + hostdata->pScript); 134262306a36Sopenharmony_ci break; 134362306a36Sopenharmony_ci case Ent_Finish1: 134462306a36Sopenharmony_ci case Ent_Finish2: 134562306a36Sopenharmony_ci process_script_interrupt(A_GOOD_STATUS_AFTER_STATUS, dsp, SCp, host, hostdata); 134662306a36Sopenharmony_ci break; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci default: 134962306a36Sopenharmony_ci slot->state = NCR_700_SLOT_QUEUED; 135062306a36Sopenharmony_ci break; 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci hostdata->state = NCR_700_HOST_BUSY; 135462306a36Sopenharmony_ci hostdata->cmd = NULL; 135562306a36Sopenharmony_ci /* clear any stale simple tag message */ 135662306a36Sopenharmony_ci hostdata->msgin[1] = 0; 135762306a36Sopenharmony_ci dma_sync_to_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci if(id == 0xff) { 136062306a36Sopenharmony_ci /* Selected as target, Ignore */ 136162306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_SelectedAsTarget; 136262306a36Sopenharmony_ci } else if(hostdata->tag_negotiated & (1<<id)) { 136362306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_GetReselectionWithTag; 136462306a36Sopenharmony_ci } else { 136562306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_GetReselectionData; 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci return resume_offset; 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_cistatic inline void 137162306a36Sopenharmony_ciNCR_700_clear_fifo(struct Scsi_Host *host) { 137262306a36Sopenharmony_ci const struct NCR_700_Host_Parameters *hostdata 137362306a36Sopenharmony_ci = (struct NCR_700_Host_Parameters *)host->hostdata[0]; 137462306a36Sopenharmony_ci if(hostdata->chip710) { 137562306a36Sopenharmony_ci NCR_700_writeb(CLR_FIFO_710, host, CTEST8_REG); 137662306a36Sopenharmony_ci } else { 137762306a36Sopenharmony_ci NCR_700_writeb(CLR_FIFO, host, DFIFO_REG); 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci} 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_cistatic inline void 138262306a36Sopenharmony_ciNCR_700_flush_fifo(struct Scsi_Host *host) { 138362306a36Sopenharmony_ci const struct NCR_700_Host_Parameters *hostdata 138462306a36Sopenharmony_ci = (struct NCR_700_Host_Parameters *)host->hostdata[0]; 138562306a36Sopenharmony_ci if(hostdata->chip710) { 138662306a36Sopenharmony_ci NCR_700_writeb(FLUSH_DMA_FIFO_710, host, CTEST8_REG); 138762306a36Sopenharmony_ci udelay(10); 138862306a36Sopenharmony_ci NCR_700_writeb(0, host, CTEST8_REG); 138962306a36Sopenharmony_ci } else { 139062306a36Sopenharmony_ci NCR_700_writeb(FLUSH_DMA_FIFO, host, DFIFO_REG); 139162306a36Sopenharmony_ci udelay(10); 139262306a36Sopenharmony_ci NCR_700_writeb(0, host, DFIFO_REG); 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci/* The queue lock with interrupts disabled must be held on entry to 139862306a36Sopenharmony_ci * this function */ 139962306a36Sopenharmony_ciSTATIC int 140062306a36Sopenharmony_ciNCR_700_start_command(struct scsi_cmnd *SCp) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci struct NCR_700_command_slot *slot = 140362306a36Sopenharmony_ci (struct NCR_700_command_slot *)SCp->host_scribble; 140462306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 140562306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; 140662306a36Sopenharmony_ci __u16 count = 1; /* for IDENTIFY message */ 140762306a36Sopenharmony_ci u8 lun = SCp->device->lun; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci if(hostdata->state != NCR_700_HOST_FREE) { 141062306a36Sopenharmony_ci /* keep this inside the lock to close the race window where 141162306a36Sopenharmony_ci * the running command finishes on another CPU while we don't 141262306a36Sopenharmony_ci * change the state to queued on this one */ 141362306a36Sopenharmony_ci slot->state = NCR_700_SLOT_QUEUED; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci DEBUG(("scsi%d: host busy, queueing command %p, slot %p\n", 141662306a36Sopenharmony_ci SCp->device->host->host_no, slot->cmnd, slot)); 141762306a36Sopenharmony_ci return 0; 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci hostdata->state = NCR_700_HOST_BUSY; 142062306a36Sopenharmony_ci hostdata->cmd = SCp; 142162306a36Sopenharmony_ci slot->state = NCR_700_SLOT_BUSY; 142262306a36Sopenharmony_ci /* keep interrupts disabled until we have the command correctly 142362306a36Sopenharmony_ci * set up so we cannot take a selection interrupt */ 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci hostdata->msgout[0] = NCR_700_identify((SCp->cmnd[0] != REQUEST_SENSE && 142662306a36Sopenharmony_ci slot->flags != NCR_700_FLAG_AUTOSENSE), 142762306a36Sopenharmony_ci lun); 142862306a36Sopenharmony_ci /* for INQUIRY or REQUEST_SENSE commands, we cannot be sure 142962306a36Sopenharmony_ci * if the negotiated transfer parameters still hold, so 143062306a36Sopenharmony_ci * always renegotiate them */ 143162306a36Sopenharmony_ci if(SCp->cmnd[0] == INQUIRY || SCp->cmnd[0] == REQUEST_SENSE || 143262306a36Sopenharmony_ci slot->flags == NCR_700_FLAG_AUTOSENSE) { 143362306a36Sopenharmony_ci NCR_700_clear_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci /* REQUEST_SENSE is asking for contingent I_T_L(_Q) status. 143762306a36Sopenharmony_ci * If a contingent allegiance condition exists, the device 143862306a36Sopenharmony_ci * will refuse all tags, so send the request sense as untagged 143962306a36Sopenharmony_ci * */ 144062306a36Sopenharmony_ci if((hostdata->tag_negotiated & (1<<scmd_id(SCp))) 144162306a36Sopenharmony_ci && (slot->tag != SCSI_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE && 144262306a36Sopenharmony_ci slot->flags != NCR_700_FLAG_AUTOSENSE)) { 144362306a36Sopenharmony_ci count += spi_populate_tag_msg(&hostdata->msgout[count], SCp); 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci if(hostdata->fast && 144762306a36Sopenharmony_ci NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) { 144862306a36Sopenharmony_ci count += spi_populate_sync_msg(&hostdata->msgout[count], 144962306a36Sopenharmony_ci spi_period(SCp->device->sdev_target), 145062306a36Sopenharmony_ci spi_offset(SCp->device->sdev_target)); 145162306a36Sopenharmony_ci NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci script_patch_16(hostdata, hostdata->script, MessageCount, count); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci script_patch_ID(hostdata, hostdata->script, Device_ID, 1<<scmd_id(SCp)); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci script_patch_32_abs(hostdata, hostdata->script, CommandAddress, 145962306a36Sopenharmony_ci slot->pCmd); 146062306a36Sopenharmony_ci script_patch_16(hostdata, hostdata->script, CommandCount, SCp->cmd_len); 146162306a36Sopenharmony_ci /* finally plumb the beginning of the SG list into the script 146262306a36Sopenharmony_ci * */ 146362306a36Sopenharmony_ci script_patch_32_abs(hostdata, hostdata->script, 146462306a36Sopenharmony_ci SGScriptStartAddress, to32bit(&slot->pSG[0].ins)); 146562306a36Sopenharmony_ci NCR_700_clear_fifo(SCp->device->host); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci if(slot->resume_offset == 0) 146862306a36Sopenharmony_ci slot->resume_offset = hostdata->pScript; 146962306a36Sopenharmony_ci /* now perform all the writebacks and invalidates */ 147062306a36Sopenharmony_ci dma_sync_to_dev(hostdata, hostdata->msgout, count); 147162306a36Sopenharmony_ci dma_sync_from_dev(hostdata, hostdata->msgin, MSG_ARRAY_SIZE); 147262306a36Sopenharmony_ci dma_sync_to_dev(hostdata, SCp->cmnd, SCp->cmd_len); 147362306a36Sopenharmony_ci dma_sync_from_dev(hostdata, hostdata->status, 1); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci /* set the synchronous period/offset */ 147662306a36Sopenharmony_ci NCR_700_writeb(NCR_700_get_SXFER(SCp->device), 147762306a36Sopenharmony_ci SCp->device->host, SXFER_REG); 147862306a36Sopenharmony_ci NCR_700_writel(slot->temp, SCp->device->host, TEMP_REG); 147962306a36Sopenharmony_ci NCR_700_writel(slot->resume_offset, SCp->device->host, DSP_REG); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci return 1; 148262306a36Sopenharmony_ci} 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ciirqreturn_t 148562306a36Sopenharmony_ciNCR_700_intr(int irq, void *dev_id) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci struct Scsi_Host *host = (struct Scsi_Host *)dev_id; 148862306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 148962306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)host->hostdata[0]; 149062306a36Sopenharmony_ci __u8 istat; 149162306a36Sopenharmony_ci __u32 resume_offset = 0; 149262306a36Sopenharmony_ci __u8 pun = 0xff, lun = 0xff; 149362306a36Sopenharmony_ci unsigned long flags; 149462306a36Sopenharmony_ci int handled = 0; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* Use the host lock to serialise access to the 53c700 149762306a36Sopenharmony_ci * hardware. Note: In future, we may need to take the queue 149862306a36Sopenharmony_ci * lock to enter the done routines. When that happens, we 149962306a36Sopenharmony_ci * need to ensure that for this driver, the host lock and the 150062306a36Sopenharmony_ci * queue lock point to the same thing. */ 150162306a36Sopenharmony_ci spin_lock_irqsave(host->host_lock, flags); 150262306a36Sopenharmony_ci if((istat = NCR_700_readb(host, ISTAT_REG)) 150362306a36Sopenharmony_ci & (SCSI_INT_PENDING | DMA_INT_PENDING)) { 150462306a36Sopenharmony_ci __u32 dsps; 150562306a36Sopenharmony_ci __u8 sstat0 = 0, dstat = 0; 150662306a36Sopenharmony_ci __u32 dsp; 150762306a36Sopenharmony_ci struct scsi_cmnd *SCp = hostdata->cmd; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci handled = 1; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci if(istat & SCSI_INT_PENDING) { 151262306a36Sopenharmony_ci udelay(10); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci sstat0 = NCR_700_readb(host, SSTAT0_REG); 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if(istat & DMA_INT_PENDING) { 151862306a36Sopenharmony_ci udelay(10); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci dstat = NCR_700_readb(host, DSTAT_REG); 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci dsps = NCR_700_readl(host, DSPS_REG); 152462306a36Sopenharmony_ci dsp = NCR_700_readl(host, DSP_REG); 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08x] dsps 0x%x\n", 152762306a36Sopenharmony_ci host->host_no, istat, sstat0, dstat, 152862306a36Sopenharmony_ci (dsp - (__u32)(hostdata->pScript))/4, 152962306a36Sopenharmony_ci dsp, dsps)); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if(SCp != NULL) { 153262306a36Sopenharmony_ci pun = SCp->device->id; 153362306a36Sopenharmony_ci lun = SCp->device->lun; 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if(sstat0 & SCSI_RESET_DETECTED) { 153762306a36Sopenharmony_ci struct scsi_device *SDp; 153862306a36Sopenharmony_ci int i; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci hostdata->state = NCR_700_HOST_BUSY; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n", 154362306a36Sopenharmony_ci host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci scsi_report_bus_reset(host, 0); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci /* clear all the negotiated parameters */ 154862306a36Sopenharmony_ci __shost_for_each_device(SDp, host) 154962306a36Sopenharmony_ci NCR_700_clear_flag(SDp, ~0); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* clear all the slots and their pending commands */ 155262306a36Sopenharmony_ci for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) { 155362306a36Sopenharmony_ci struct scsi_cmnd *SCp; 155462306a36Sopenharmony_ci struct NCR_700_command_slot *slot = 155562306a36Sopenharmony_ci &hostdata->slots[i]; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci if(slot->state == NCR_700_SLOT_FREE) 155862306a36Sopenharmony_ci continue; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci SCp = slot->cmnd; 156162306a36Sopenharmony_ci printk(KERN_ERR " failing command because of reset, slot %p, cmnd %p\n", 156262306a36Sopenharmony_ci slot, SCp); 156362306a36Sopenharmony_ci free_slot(slot, hostdata); 156462306a36Sopenharmony_ci SCp->host_scribble = NULL; 156562306a36Sopenharmony_ci NCR_700_set_depth(SCp->device, 0); 156662306a36Sopenharmony_ci /* NOTE: deadlock potential here: we 156762306a36Sopenharmony_ci * rely on mid-layer guarantees that 156862306a36Sopenharmony_ci * scsi_done won't try to issue the 156962306a36Sopenharmony_ci * command again otherwise we'll 157062306a36Sopenharmony_ci * deadlock on the 157162306a36Sopenharmony_ci * hostdata->state_lock */ 157262306a36Sopenharmony_ci SCp->result = DID_RESET << 16; 157362306a36Sopenharmony_ci scsi_done(SCp); 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci mdelay(25); 157662306a36Sopenharmony_ci NCR_700_chip_setup(host); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci hostdata->state = NCR_700_HOST_FREE; 157962306a36Sopenharmony_ci hostdata->cmd = NULL; 158062306a36Sopenharmony_ci /* signal back if this was an eh induced reset */ 158162306a36Sopenharmony_ci if(hostdata->eh_complete != NULL) 158262306a36Sopenharmony_ci complete(hostdata->eh_complete); 158362306a36Sopenharmony_ci goto out_unlock; 158462306a36Sopenharmony_ci } else if(sstat0 & SELECTION_TIMEOUT) { 158562306a36Sopenharmony_ci DEBUG(("scsi%d: (%d:%d) selection timeout\n", 158662306a36Sopenharmony_ci host->host_no, pun, lun)); 158762306a36Sopenharmony_ci NCR_700_scsi_done(hostdata, SCp, DID_NO_CONNECT<<16); 158862306a36Sopenharmony_ci } else if(sstat0 & PHASE_MISMATCH) { 158962306a36Sopenharmony_ci struct NCR_700_command_slot *slot = (SCp == NULL) ? NULL : 159062306a36Sopenharmony_ci (struct NCR_700_command_slot *)SCp->host_scribble; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci if(dsp == Ent_SendMessage + 8 + hostdata->pScript) { 159362306a36Sopenharmony_ci /* It wants to reply to some part of 159462306a36Sopenharmony_ci * our message */ 159562306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 159662306a36Sopenharmony_ci __u32 temp = NCR_700_readl(host, TEMP_REG); 159762306a36Sopenharmony_ci int count = (hostdata->script[Ent_SendMessage/4] & 0xffffff) - ((NCR_700_readl(host, DBC_REG) & 0xffffff) + NCR_700_data_residual(host)); 159862306a36Sopenharmony_ci printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG))); 159962306a36Sopenharmony_ci#endif 160062306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch; 160162306a36Sopenharmony_ci } else if (slot && dsp >= to32bit(&slot->pSG[0].ins) && 160262306a36Sopenharmony_ci dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) { 160362306a36Sopenharmony_ci int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff; 160462306a36Sopenharmony_ci int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List); 160562306a36Sopenharmony_ci int residual = NCR_700_data_residual(host); 160662306a36Sopenharmony_ci int i; 160762306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 160862306a36Sopenharmony_ci __u32 naddr = NCR_700_readl(host, DNAD_REG); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n", 161162306a36Sopenharmony_ci host->host_no, pun, lun, 161262306a36Sopenharmony_ci SGcount, data_transfer); 161362306a36Sopenharmony_ci scsi_print_command(SCp); 161462306a36Sopenharmony_ci if(residual) { 161562306a36Sopenharmony_ci printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x, residual %d\n", 161662306a36Sopenharmony_ci host->host_no, pun, lun, 161762306a36Sopenharmony_ci SGcount, data_transfer, residual); 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci#endif 162062306a36Sopenharmony_ci data_transfer += residual; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if(data_transfer != 0) { 162362306a36Sopenharmony_ci int count; 162462306a36Sopenharmony_ci __u32 pAddr; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci SGcount--; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci count = (bS_to_cpu(slot->SG[SGcount].ins) & 0x00ffffff); 162962306a36Sopenharmony_ci DEBUG(("DATA TRANSFER MISMATCH, count = %d, transferred %d\n", count, count-data_transfer)); 163062306a36Sopenharmony_ci slot->SG[SGcount].ins &= bS_to_host(0xff000000); 163162306a36Sopenharmony_ci slot->SG[SGcount].ins |= bS_to_host(data_transfer); 163262306a36Sopenharmony_ci pAddr = bS_to_cpu(slot->SG[SGcount].pAddr); 163362306a36Sopenharmony_ci pAddr += (count - data_transfer); 163462306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 163562306a36Sopenharmony_ci if(pAddr != naddr) { 163662306a36Sopenharmony_ci printk("scsi%d (%d:%d) transfer mismatch pAddr=%lx, naddr=%lx, data_transfer=%d, residual=%d\n", host->host_no, pun, lun, (unsigned long)pAddr, (unsigned long)naddr, data_transfer, residual); 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci#endif 163962306a36Sopenharmony_ci slot->SG[SGcount].pAddr = bS_to_host(pAddr); 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci /* set the executed moves to nops */ 164262306a36Sopenharmony_ci for(i=0; i<SGcount; i++) { 164362306a36Sopenharmony_ci slot->SG[i].ins = bS_to_host(SCRIPT_NOP); 164462306a36Sopenharmony_ci slot->SG[i].pAddr = 0; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci dma_sync_to_dev(hostdata, slot->SG, sizeof(slot->SG)); 164762306a36Sopenharmony_ci /* and pretend we disconnected after 164862306a36Sopenharmony_ci * the command phase */ 164962306a36Sopenharmony_ci resume_offset = hostdata->pScript + Ent_MsgInDuringData; 165062306a36Sopenharmony_ci /* make sure all the data is flushed */ 165162306a36Sopenharmony_ci NCR_700_flush_fifo(host); 165262306a36Sopenharmony_ci } else { 165362306a36Sopenharmony_ci __u8 sbcl = NCR_700_readb(host, SBCL_REG); 165462306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n", 165562306a36Sopenharmony_ci host->host_no, pun, lun, dsp - hostdata->pScript, sbcl_to_string(sbcl)); 165662306a36Sopenharmony_ci NCR_700_internal_bus_reset(host); 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci } else if(sstat0 & SCSI_GROSS_ERROR) { 166062306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d) GROSS ERROR\n", 166162306a36Sopenharmony_ci host->host_no, pun, lun); 166262306a36Sopenharmony_ci NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); 166362306a36Sopenharmony_ci } else if(sstat0 & PARITY_ERROR) { 166462306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d) PARITY ERROR\n", 166562306a36Sopenharmony_ci host->host_no, pun, lun); 166662306a36Sopenharmony_ci NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); 166762306a36Sopenharmony_ci } else if(dstat & SCRIPT_INT_RECEIVED) { 166862306a36Sopenharmony_ci DEBUG(("scsi%d: (%d:%d) ====>SCRIPT INTERRUPT<====\n", 166962306a36Sopenharmony_ci host->host_no, pun, lun)); 167062306a36Sopenharmony_ci resume_offset = process_script_interrupt(dsps, dsp, SCp, host, hostdata); 167162306a36Sopenharmony_ci } else if(dstat & (ILGL_INST_DETECTED)) { 167262306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%08x[0x%x]!!!\n" 167362306a36Sopenharmony_ci " Please email James.Bottomley@HansenPartnership.com with the details\n", 167462306a36Sopenharmony_ci host->host_no, pun, lun, 167562306a36Sopenharmony_ci dsp, dsp - hostdata->pScript); 167662306a36Sopenharmony_ci NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); 167762306a36Sopenharmony_ci } else if(dstat & (WATCH_DOG_INTERRUPT|ABORTED)) { 167862306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: (%d:%d) serious DMA problem, dstat=%02x\n", 167962306a36Sopenharmony_ci host->host_no, pun, lun, dstat); 168062306a36Sopenharmony_ci NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci /* NOTE: selection interrupt processing MUST occur 168562306a36Sopenharmony_ci * after script interrupt processing to correctly cope 168662306a36Sopenharmony_ci * with the case where we process a disconnect and 168762306a36Sopenharmony_ci * then get reselected before we process the 168862306a36Sopenharmony_ci * disconnection */ 168962306a36Sopenharmony_ci if(sstat0 & SELECTED) { 169062306a36Sopenharmony_ci /* FIXME: It currently takes at least FOUR 169162306a36Sopenharmony_ci * interrupts to complete a command that 169262306a36Sopenharmony_ci * disconnects: one for the disconnect, one 169362306a36Sopenharmony_ci * for the reselection, one to get the 169462306a36Sopenharmony_ci * reselection data and one to complete the 169562306a36Sopenharmony_ci * command. If we guess the reselected 169662306a36Sopenharmony_ci * command here and prepare it, we only need 169762306a36Sopenharmony_ci * to get a reselection data interrupt if we 169862306a36Sopenharmony_ci * guessed wrongly. Since the interrupt 169962306a36Sopenharmony_ci * overhead is much greater than the command 170062306a36Sopenharmony_ci * setup, this would be an efficient 170162306a36Sopenharmony_ci * optimisation particularly as we probably 170262306a36Sopenharmony_ci * only have one outstanding command on a 170362306a36Sopenharmony_ci * target most of the time */ 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci resume_offset = process_selection(host, dsp); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci if(resume_offset) { 171262306a36Sopenharmony_ci if(hostdata->state != NCR_700_HOST_BUSY) { 171362306a36Sopenharmony_ci printk(KERN_ERR "scsi%d: Driver error: resume at 0x%08x [0x%04x] with non busy host!\n", 171462306a36Sopenharmony_ci host->host_no, resume_offset, resume_offset - hostdata->pScript); 171562306a36Sopenharmony_ci hostdata->state = NCR_700_HOST_BUSY; 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci DEBUG(("Attempting to resume at %x\n", resume_offset)); 171962306a36Sopenharmony_ci NCR_700_clear_fifo(host); 172062306a36Sopenharmony_ci NCR_700_writel(resume_offset, host, DSP_REG); 172162306a36Sopenharmony_ci } 172262306a36Sopenharmony_ci /* There is probably a technical no-no about this: If we're a 172362306a36Sopenharmony_ci * shared interrupt and we got this interrupt because the 172462306a36Sopenharmony_ci * other device needs servicing not us, we're still going to 172562306a36Sopenharmony_ci * check our queued commands here---of course, there shouldn't 172662306a36Sopenharmony_ci * be any outstanding.... */ 172762306a36Sopenharmony_ci if(hostdata->state == NCR_700_HOST_FREE) { 172862306a36Sopenharmony_ci int i; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) { 173162306a36Sopenharmony_ci /* fairness: always run the queue from the last 173262306a36Sopenharmony_ci * position we left off */ 173362306a36Sopenharmony_ci int j = (i + hostdata->saved_slot_position) 173462306a36Sopenharmony_ci % NCR_700_COMMAND_SLOTS_PER_HOST; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci if(hostdata->slots[j].state != NCR_700_SLOT_QUEUED) 173762306a36Sopenharmony_ci continue; 173862306a36Sopenharmony_ci if(NCR_700_start_command(hostdata->slots[j].cmnd)) { 173962306a36Sopenharmony_ci DEBUG(("scsi%d: Issuing saved command slot %p, cmd %p\t\n", 174062306a36Sopenharmony_ci host->host_no, &hostdata->slots[j], 174162306a36Sopenharmony_ci hostdata->slots[j].cmnd)); 174262306a36Sopenharmony_ci hostdata->saved_slot_position = j + 1; 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci break; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci out_unlock: 174962306a36Sopenharmony_ci spin_unlock_irqrestore(host->host_lock, flags); 175062306a36Sopenharmony_ci return IRQ_RETVAL(handled); 175162306a36Sopenharmony_ci} 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_cistatic int NCR_700_queuecommand_lck(struct scsi_cmnd *SCp) 175462306a36Sopenharmony_ci{ 175562306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 175662306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; 175762306a36Sopenharmony_ci __u32 move_ins; 175862306a36Sopenharmony_ci struct NCR_700_command_slot *slot; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) { 176162306a36Sopenharmony_ci /* We're over our allocation, this should never happen 176262306a36Sopenharmony_ci * since we report the max allocation to the mid layer */ 176362306a36Sopenharmony_ci printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->device->host->host_no); 176462306a36Sopenharmony_ci return 1; 176562306a36Sopenharmony_ci } 176662306a36Sopenharmony_ci /* check for untagged commands. We cannot have any outstanding 176762306a36Sopenharmony_ci * commands if we accept them. Commands could be untagged because: 176862306a36Sopenharmony_ci * 176962306a36Sopenharmony_ci * - The tag negotiated bitmap is clear 177062306a36Sopenharmony_ci * - The blk layer sent and untagged command 177162306a36Sopenharmony_ci */ 177262306a36Sopenharmony_ci if(NCR_700_get_depth(SCp->device) != 0 177362306a36Sopenharmony_ci && (!(hostdata->tag_negotiated & (1<<scmd_id(SCp))) 177462306a36Sopenharmony_ci || !(SCp->flags & SCMD_TAGGED))) { 177562306a36Sopenharmony_ci CDEBUG(KERN_ERR, SCp, "has non zero depth %d\n", 177662306a36Sopenharmony_ci NCR_700_get_depth(SCp->device)); 177762306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci if(NCR_700_get_depth(SCp->device) >= SCp->device->queue_depth) { 178062306a36Sopenharmony_ci CDEBUG(KERN_ERR, SCp, "has max tag depth %d\n", 178162306a36Sopenharmony_ci NCR_700_get_depth(SCp->device)); 178262306a36Sopenharmony_ci return SCSI_MLQUEUE_DEVICE_BUSY; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) + 1); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci /* begin the command here */ 178762306a36Sopenharmony_ci /* no need to check for NULL, test for command_slot_count above 178862306a36Sopenharmony_ci * ensures a slot is free */ 178962306a36Sopenharmony_ci slot = find_empty_slot(hostdata); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci slot->cmnd = SCp; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci SCp->host_scribble = (unsigned char *)slot; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 179662306a36Sopenharmony_ci printk("53c700: scsi%d, command ", SCp->device->host->host_no); 179762306a36Sopenharmony_ci scsi_print_command(SCp); 179862306a36Sopenharmony_ci#endif 179962306a36Sopenharmony_ci if ((SCp->flags & SCMD_TAGGED) 180062306a36Sopenharmony_ci && (hostdata->tag_negotiated &(1<<scmd_id(SCp))) == 0 180162306a36Sopenharmony_ci && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_START_TAG_NEGOTIATION) { 180262306a36Sopenharmony_ci scmd_printk(KERN_ERR, SCp, "Enabling Tag Command Queuing\n"); 180362306a36Sopenharmony_ci hostdata->tag_negotiated |= (1<<scmd_id(SCp)); 180462306a36Sopenharmony_ci NCR_700_set_tag_neg_state(SCp->device, NCR_700_DURING_TAG_NEGOTIATION); 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci /* here we may have to process an untagged command. The gate 180862306a36Sopenharmony_ci * above ensures that this will be the only one outstanding, 180962306a36Sopenharmony_ci * so clear the tag negotiated bit. 181062306a36Sopenharmony_ci * 181162306a36Sopenharmony_ci * FIXME: This will royally screw up on multiple LUN devices 181262306a36Sopenharmony_ci * */ 181362306a36Sopenharmony_ci if (!(SCp->flags & SCMD_TAGGED) 181462306a36Sopenharmony_ci && (hostdata->tag_negotiated &(1<<scmd_id(SCp)))) { 181562306a36Sopenharmony_ci scmd_printk(KERN_INFO, SCp, "Disabling Tag Command Queuing\n"); 181662306a36Sopenharmony_ci hostdata->tag_negotiated &= ~(1<<scmd_id(SCp)); 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci if ((hostdata->tag_negotiated & (1<<scmd_id(SCp))) && 182062306a36Sopenharmony_ci SCp->device->simple_tags) { 182162306a36Sopenharmony_ci slot->tag = scsi_cmd_to_rq(SCp)->tag; 182262306a36Sopenharmony_ci CDEBUG(KERN_DEBUG, SCp, "sending out tag %d, slot %p\n", 182362306a36Sopenharmony_ci slot->tag, slot); 182462306a36Sopenharmony_ci } else { 182562306a36Sopenharmony_ci struct NCR_700_Device_Parameters *p = SCp->device->hostdata; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci slot->tag = SCSI_NO_TAG; 182862306a36Sopenharmony_ci /* save current command for reselection */ 182962306a36Sopenharmony_ci p->current_cmnd = SCp; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci /* sanity check: some of the commands generated by the mid-layer 183262306a36Sopenharmony_ci * have an eccentric idea of their sc_data_direction */ 183362306a36Sopenharmony_ci if(!scsi_sg_count(SCp) && !scsi_bufflen(SCp) && 183462306a36Sopenharmony_ci SCp->sc_data_direction != DMA_NONE) { 183562306a36Sopenharmony_ci#ifdef NCR_700_DEBUG 183662306a36Sopenharmony_ci printk("53c700: Command"); 183762306a36Sopenharmony_ci scsi_print_command(SCp); 183862306a36Sopenharmony_ci printk("Has wrong data direction %d\n", SCp->sc_data_direction); 183962306a36Sopenharmony_ci#endif 184062306a36Sopenharmony_ci SCp->sc_data_direction = DMA_NONE; 184162306a36Sopenharmony_ci } 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci switch (SCp->cmnd[0]) { 184462306a36Sopenharmony_ci case REQUEST_SENSE: 184562306a36Sopenharmony_ci /* clear the internal sense magic */ 184662306a36Sopenharmony_ci SCp->cmnd[6] = 0; 184762306a36Sopenharmony_ci fallthrough; 184862306a36Sopenharmony_ci default: 184962306a36Sopenharmony_ci /* OK, get it from the command */ 185062306a36Sopenharmony_ci switch(SCp->sc_data_direction) { 185162306a36Sopenharmony_ci case DMA_BIDIRECTIONAL: 185262306a36Sopenharmony_ci default: 185362306a36Sopenharmony_ci printk(KERN_ERR "53c700: Unknown command for data direction "); 185462306a36Sopenharmony_ci scsi_print_command(SCp); 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci move_ins = 0; 185762306a36Sopenharmony_ci break; 185862306a36Sopenharmony_ci case DMA_NONE: 185962306a36Sopenharmony_ci move_ins = 0; 186062306a36Sopenharmony_ci break; 186162306a36Sopenharmony_ci case DMA_FROM_DEVICE: 186262306a36Sopenharmony_ci move_ins = SCRIPT_MOVE_DATA_IN; 186362306a36Sopenharmony_ci break; 186462306a36Sopenharmony_ci case DMA_TO_DEVICE: 186562306a36Sopenharmony_ci move_ins = SCRIPT_MOVE_DATA_OUT; 186662306a36Sopenharmony_ci break; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci /* now build the scatter gather list */ 187162306a36Sopenharmony_ci if(move_ins != 0) { 187262306a36Sopenharmony_ci int i; 187362306a36Sopenharmony_ci int sg_count; 187462306a36Sopenharmony_ci dma_addr_t vPtr = 0; 187562306a36Sopenharmony_ci struct scatterlist *sg; 187662306a36Sopenharmony_ci __u32 count = 0; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci sg_count = scsi_dma_map(SCp); 187962306a36Sopenharmony_ci BUG_ON(sg_count < 0); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci scsi_for_each_sg(SCp, sg, sg_count, i) { 188262306a36Sopenharmony_ci vPtr = sg_dma_address(sg); 188362306a36Sopenharmony_ci count = sg_dma_len(sg); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci slot->SG[i].ins = bS_to_host(move_ins | count); 188662306a36Sopenharmony_ci DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n", 188762306a36Sopenharmony_ci i, count, slot->SG[i].ins, (unsigned long)vPtr)); 188862306a36Sopenharmony_ci slot->SG[i].pAddr = bS_to_host(vPtr); 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci slot->SG[i].ins = bS_to_host(SCRIPT_RETURN); 189162306a36Sopenharmony_ci slot->SG[i].pAddr = 0; 189262306a36Sopenharmony_ci dma_sync_to_dev(hostdata, slot->SG, sizeof(slot->SG)); 189362306a36Sopenharmony_ci DEBUG((" SETTING %p to %x\n", 189462306a36Sopenharmony_ci (&slot->pSG[i].ins), 189562306a36Sopenharmony_ci slot->SG[i].ins)); 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci slot->resume_offset = 0; 189862306a36Sopenharmony_ci slot->pCmd = dma_map_single(hostdata->dev, SCp->cmnd, 189962306a36Sopenharmony_ci MAX_COMMAND_SIZE, DMA_TO_DEVICE); 190062306a36Sopenharmony_ci NCR_700_start_command(SCp); 190162306a36Sopenharmony_ci return 0; 190262306a36Sopenharmony_ci} 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ciSTATIC DEF_SCSI_QCMD(NCR_700_queuecommand) 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ciSTATIC int 190762306a36Sopenharmony_ciNCR_700_abort(struct scsi_cmnd * SCp) 190862306a36Sopenharmony_ci{ 190962306a36Sopenharmony_ci struct NCR_700_command_slot *slot; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci scmd_printk(KERN_INFO, SCp, "abort command\n"); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci slot = (struct NCR_700_command_slot *)SCp->host_scribble; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci if(slot == NULL) 191662306a36Sopenharmony_ci /* no outstanding command to abort */ 191762306a36Sopenharmony_ci return SUCCESS; 191862306a36Sopenharmony_ci if(SCp->cmnd[0] == TEST_UNIT_READY) { 191962306a36Sopenharmony_ci /* FIXME: This is because of a problem in the new 192062306a36Sopenharmony_ci * error handler. When it is in error recovery, it 192162306a36Sopenharmony_ci * will send a TUR to a device it thinks may still be 192262306a36Sopenharmony_ci * showing a problem. If the TUR isn't responded to, 192362306a36Sopenharmony_ci * it will abort it and mark the device off line. 192462306a36Sopenharmony_ci * Unfortunately, it does no other error recovery, so 192562306a36Sopenharmony_ci * this would leave us with an outstanding command 192662306a36Sopenharmony_ci * occupying a slot. Rather than allow this to 192762306a36Sopenharmony_ci * happen, we issue a bus reset to force all 192862306a36Sopenharmony_ci * outstanding commands to terminate here. */ 192962306a36Sopenharmony_ci NCR_700_internal_bus_reset(SCp->device->host); 193062306a36Sopenharmony_ci /* still drop through and return failed */ 193162306a36Sopenharmony_ci } 193262306a36Sopenharmony_ci return FAILED; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci} 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ciSTATIC int 193762306a36Sopenharmony_ciNCR_700_host_reset(struct scsi_cmnd * SCp) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(complete); 194062306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 194162306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci scmd_printk(KERN_INFO, SCp, 194462306a36Sopenharmony_ci "New error handler wants HOST reset, cmd %p\n\t", SCp); 194562306a36Sopenharmony_ci scsi_print_command(SCp); 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci /* In theory, eh_complete should always be null because the 194862306a36Sopenharmony_ci * eh is single threaded, but just in case we're handling a 194962306a36Sopenharmony_ci * reset via sg or something */ 195062306a36Sopenharmony_ci spin_lock_irq(SCp->device->host->host_lock); 195162306a36Sopenharmony_ci while (hostdata->eh_complete != NULL) { 195262306a36Sopenharmony_ci spin_unlock_irq(SCp->device->host->host_lock); 195362306a36Sopenharmony_ci msleep_interruptible(100); 195462306a36Sopenharmony_ci spin_lock_irq(SCp->device->host->host_lock); 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci hostdata->eh_complete = &complete; 195862306a36Sopenharmony_ci NCR_700_internal_bus_reset(SCp->device->host); 195962306a36Sopenharmony_ci NCR_700_chip_reset(SCp->device->host); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci spin_unlock_irq(SCp->device->host->host_lock); 196262306a36Sopenharmony_ci wait_for_completion(&complete); 196362306a36Sopenharmony_ci spin_lock_irq(SCp->device->host->host_lock); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci hostdata->eh_complete = NULL; 196662306a36Sopenharmony_ci /* Revalidate the transport parameters of the failing device */ 196762306a36Sopenharmony_ci if(hostdata->fast) 196862306a36Sopenharmony_ci spi_schedule_dv_device(SCp->device); 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci spin_unlock_irq(SCp->device->host->host_lock); 197162306a36Sopenharmony_ci return SUCCESS; 197262306a36Sopenharmony_ci} 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ciSTATIC void 197562306a36Sopenharmony_ciNCR_700_set_period(struct scsi_target *STp, int period) 197662306a36Sopenharmony_ci{ 197762306a36Sopenharmony_ci struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent); 197862306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 197962306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)SHp->hostdata[0]; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci if(!hostdata->fast) 198262306a36Sopenharmony_ci return; 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci if(period < hostdata->min_period) 198562306a36Sopenharmony_ci period = hostdata->min_period; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci spi_period(STp) = period; 198862306a36Sopenharmony_ci spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC | 198962306a36Sopenharmony_ci NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); 199062306a36Sopenharmony_ci spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION; 199162306a36Sopenharmony_ci} 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ciSTATIC void 199462306a36Sopenharmony_ciNCR_700_set_offset(struct scsi_target *STp, int offset) 199562306a36Sopenharmony_ci{ 199662306a36Sopenharmony_ci struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent); 199762306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 199862306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)SHp->hostdata[0]; 199962306a36Sopenharmony_ci int max_offset = hostdata->chip710 200062306a36Sopenharmony_ci ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci if(!hostdata->fast) 200362306a36Sopenharmony_ci return; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci if(offset > max_offset) 200662306a36Sopenharmony_ci offset = max_offset; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci /* if we're currently async, make sure the period is reasonable */ 200962306a36Sopenharmony_ci if(spi_offset(STp) == 0 && (spi_period(STp) < hostdata->min_period || 201062306a36Sopenharmony_ci spi_period(STp) > 0xff)) 201162306a36Sopenharmony_ci spi_period(STp) = hostdata->min_period; 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci spi_offset(STp) = offset; 201462306a36Sopenharmony_ci spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC | 201562306a36Sopenharmony_ci NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); 201662306a36Sopenharmony_ci spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION; 201762306a36Sopenharmony_ci} 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ciSTATIC int 202062306a36Sopenharmony_ciNCR_700_slave_alloc(struct scsi_device *SDp) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci SDp->hostdata = kzalloc(sizeof(struct NCR_700_Device_Parameters), 202362306a36Sopenharmony_ci GFP_KERNEL); 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci if (!SDp->hostdata) 202662306a36Sopenharmony_ci return -ENOMEM; 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci return 0; 202962306a36Sopenharmony_ci} 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ciSTATIC int 203262306a36Sopenharmony_ciNCR_700_slave_configure(struct scsi_device *SDp) 203362306a36Sopenharmony_ci{ 203462306a36Sopenharmony_ci struct NCR_700_Host_Parameters *hostdata = 203562306a36Sopenharmony_ci (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci /* to do here: allocate memory; build a queue_full list */ 203862306a36Sopenharmony_ci if(SDp->tagged_supported) { 203962306a36Sopenharmony_ci scsi_change_queue_depth(SDp, NCR_700_DEFAULT_TAGS); 204062306a36Sopenharmony_ci NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION); 204162306a36Sopenharmony_ci } 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci if(hostdata->fast) { 204462306a36Sopenharmony_ci /* Find the correct offset and period via domain validation */ 204562306a36Sopenharmony_ci if (!spi_initial_dv(SDp->sdev_target)) 204662306a36Sopenharmony_ci spi_dv_device(SDp); 204762306a36Sopenharmony_ci } else { 204862306a36Sopenharmony_ci spi_offset(SDp->sdev_target) = 0; 204962306a36Sopenharmony_ci spi_period(SDp->sdev_target) = 0; 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci return 0; 205262306a36Sopenharmony_ci} 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ciSTATIC void 205562306a36Sopenharmony_ciNCR_700_slave_destroy(struct scsi_device *SDp) 205662306a36Sopenharmony_ci{ 205762306a36Sopenharmony_ci kfree(SDp->hostdata); 205862306a36Sopenharmony_ci SDp->hostdata = NULL; 205962306a36Sopenharmony_ci} 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_cistatic int 206262306a36Sopenharmony_ciNCR_700_change_queue_depth(struct scsi_device *SDp, int depth) 206362306a36Sopenharmony_ci{ 206462306a36Sopenharmony_ci if (depth > NCR_700_MAX_TAGS) 206562306a36Sopenharmony_ci depth = NCR_700_MAX_TAGS; 206662306a36Sopenharmony_ci return scsi_change_queue_depth(SDp, depth); 206762306a36Sopenharmony_ci} 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_cistatic ssize_t 207062306a36Sopenharmony_ciNCR_700_show_active_tags(struct device *dev, struct device_attribute *attr, char *buf) 207162306a36Sopenharmony_ci{ 207262306a36Sopenharmony_ci struct scsi_device *SDp = to_scsi_device(dev); 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp)); 207562306a36Sopenharmony_ci} 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_cistatic struct device_attribute NCR_700_active_tags_attr = { 207862306a36Sopenharmony_ci .attr = { 207962306a36Sopenharmony_ci .name = "active_tags", 208062306a36Sopenharmony_ci .mode = S_IRUGO, 208162306a36Sopenharmony_ci }, 208262306a36Sopenharmony_ci .show = NCR_700_show_active_tags, 208362306a36Sopenharmony_ci}; 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ciSTATIC struct attribute *NCR_700_dev_attrs[] = { 208662306a36Sopenharmony_ci &NCR_700_active_tags_attr.attr, 208762306a36Sopenharmony_ci NULL, 208862306a36Sopenharmony_ci}; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ciATTRIBUTE_GROUPS(NCR_700_dev); 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ciEXPORT_SYMBOL(NCR_700_detect); 209362306a36Sopenharmony_ciEXPORT_SYMBOL(NCR_700_release); 209462306a36Sopenharmony_ciEXPORT_SYMBOL(NCR_700_intr); 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_cistatic struct spi_function_template NCR_700_transport_functions = { 209762306a36Sopenharmony_ci .set_period = NCR_700_set_period, 209862306a36Sopenharmony_ci .show_period = 1, 209962306a36Sopenharmony_ci .set_offset = NCR_700_set_offset, 210062306a36Sopenharmony_ci .show_offset = 1, 210162306a36Sopenharmony_ci}; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_cistatic int __init NCR_700_init(void) 210462306a36Sopenharmony_ci{ 210562306a36Sopenharmony_ci NCR_700_transport_template = spi_attach_transport(&NCR_700_transport_functions); 210662306a36Sopenharmony_ci if(!NCR_700_transport_template) 210762306a36Sopenharmony_ci return -ENODEV; 210862306a36Sopenharmony_ci return 0; 210962306a36Sopenharmony_ci} 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_cistatic void __exit NCR_700_exit(void) 211262306a36Sopenharmony_ci{ 211362306a36Sopenharmony_ci spi_release_transport(NCR_700_transport_template); 211462306a36Sopenharmony_ci} 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_cimodule_init(NCR_700_init); 211762306a36Sopenharmony_cimodule_exit(NCR_700_exit); 211862306a36Sopenharmony_ci 2119