53c700.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,957 行 · 第 1/5 页
C
1,957 行
/* -*- mode: c; c-basic-offset: 8 -*- *//* NCR (or Symbios) 53c700 and 53c700-66 Driver * * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com**-----------------------------------------------------------------------------** ** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License as published by** the Free Software Foundation; either version 2 of the License, or** (at your option) any later version.**** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU General Public License for more details.**** You should have received a copy of the GNU General Public License** along with this program; if not, write to the Free Software** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.****----------------------------------------------------------------------------- *//* Notes: * * This driver is designed exclusively for these chips (virtually the * earliest of the scripts engine chips). They need their own drivers * because they are missing so many of the scripts and snazzy register * features of their elder brothers (the 710, 720 and 770). * * The 700 is the lowliest of the line, it can only do async SCSI. * The 700-66 can at least do synchronous SCSI up to 10MHz. * * The 700 chip has no host bus interface logic of its own. However, * it is usually mapped to a location with well defined register * offsets. Therefore, if you can determine the base address and the * irq your board incorporating this chip uses, you can probably use * this driver to run it (although you'll probably have to write a * minimal wrapper for the purpose---see the NCR_D700 driver for * details about how to do this). * * * TODO List: * * 1. Better statistics in the proc fs * * 2. Implement message queue (queues SCSI messages like commands) and make * the abort and device reset functions use them. * *//* CHANGELOG * * Version 2.8 * * Fixed bad bug affecting tag starvation processing (previously the * driver would hang the system if too many tags starved. Also fixed * bad bug having to do with 10 byte command processing and REQUEST * SENSE (the command would loop forever getting a transfer length * mismatch in the CMD phase). * * Version 2.7 * * Fixed scripts problem which caused certain devices (notably CDRWs) * to hang on initial INQUIRY. Updated NCR_700_readl/writel to use * __raw_readl/writel for parisc compatibility (Thomas * Bogendoerfer). Added missing SCp->request_bufflen initialisation * for sense requests (Ryan Bradetich). * * Version 2.6 * * Following test of the 64 bit parisc kernel by Richard Hirst, * several problems have now been corrected. Also adds support for * consistent memory allocation. * * Version 2.5 * * More Compatibility changes for 710 (now actually works). Enhanced * support for odd clock speeds which constrain SDTR negotiations. * correct cacheline separation for scsi messages and status for * incoherent architectures. Use of the pci mapping functions on * buffers to begin support for 64 bit drivers. * * Version 2.4 * * Added support for the 53c710 chip (in 53c700 emulation mode only---no * special 53c710 instructions or registers are used). * * Version 2.3 * * More endianness/cache coherency changes. * * Better bad device handling (handles devices lying about tag * queueing support and devices which fail to provide sense data on * contingent allegiance conditions) * * Many thanks to Richard Hirst <rhirst@linuxcare.com> for patiently * debugging this driver on the parisc architecture and suggesting * many improvements and bug fixes. * * Thanks also go to Linuxcare Inc. for providing several PARISC * machines for me to debug the driver on. * * Version 2.2 * * Made the driver mem or io mapped; added endian invariance; added * dma cache flushing operations for architectures which need it; * added support for more varied clocking speeds. * * Version 2.1 * * Initial modularisation from the D700. See NCR_D700.c for the rest of * the changelog. * */#define NCR_700_VERSION "2.8"#include <linux/config.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/spinlock.h>#include <linux/completion.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/blkdev.h>#include <linux/module.h>#include <linux/interrupt.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/byteorder.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_dbg.h>#include <scsi/scsi_eh.h>#include <scsi/scsi_host.h>#include <scsi/scsi_tcq.h>#include <scsi/scsi_transport.h>#include <scsi/scsi_transport_spi.h>#include "53c700.h"/* NOTE: For 64 bit drivers there are points in the code where we use * a non dereferenceable pointer to point to a structure in dma-able * memory (which is 32 bits) so that we can use all of the structure * operations but take the address at the end. This macro allows us * to truncate the 64 bit pointer down to 32 bits without the compiler * complaining */#define to32bit(x) ((__u32)((unsigned long)(x)))#ifdef NCR_700_DEBUG#define STATIC#else#define STATIC static#endifMODULE_AUTHOR("James Bottomley");MODULE_DESCRIPTION("53c700 and 53c700-66 Driver");MODULE_LICENSE("GPL");/* This is the script */#include "53c700_d.h"STATIC int NCR_700_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt);STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt);STATIC int NCR_700_dev_reset(struct scsi_cmnd * SCpnt);STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);STATIC void NCR_700_chip_setup(struct Scsi_Host *host);STATIC void NCR_700_chip_reset(struct Scsi_Host *host);STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);STATIC struct device_attribute *NCR_700_dev_attrs[];STATIC struct scsi_transport_template *NCR_700_transport_template = NULL;static char *NCR_700_phase[] = { "", "after selection", "before command phase", "after command phase", "after status phase", "after data in phase", "after data out phase", "during data phase",};static char *NCR_700_condition[] = { "", "NOT MSG_OUT", "UNEXPECTED PHASE", "NOT MSG_IN", "UNEXPECTED MSG", "MSG_IN", "SDTR_MSG RECEIVED", "REJECT_MSG RECEIVED", "DISCONNECT_MSG RECEIVED", "MSG_OUT", "DATA_IN", };static char *NCR_700_fatal_messages[] = { "unexpected message after reselection", "still MSG_OUT after message injection", "not MSG_IN after selection", "Illegal message length received",};static char *NCR_700_SBCL_bits[] = { "IO ", "CD ", "MSG ", "ATN ", "SEL ", "BSY ", "ACK ", "REQ ",};static char *NCR_700_SBCL_to_phase[] = { "DATA_OUT", "DATA_IN", "CMD_OUT", "STATE", "ILLEGAL PHASE", "ILLEGAL PHASE", "MSG OUT", "MSG IN",};static __u8 NCR_700_SDTR_msg[] = { 0x01, /* Extended message */ 0x03, /* Extended message Length */ 0x01, /* SDTR Extended message */ NCR_700_MIN_PERIOD, NCR_700_MAX_OFFSET};/* This translates the SDTR message offset and period to a value * which can be loaded into the SXFER_REG. * * NOTE: According to SCSI-2, the true transfer period (in ns) is * actually four times this period value */static inline __u8NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, __u8 offset, __u8 period){ int XFERP; __u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); __u8 max_offset = (hostdata->chip710 ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET); if(offset == 0) return 0; if(period < hostdata->min_period) { printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4); period = hostdata->min_period; } XFERP = (period*4 * hostdata->sync_clock)/1000 - 4; if(offset > max_offset) { printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n", offset, max_offset); offset = max_offset; } if(XFERP < min_xferp) { printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n", XFERP, min_xferp); XFERP = min_xferp; } return (offset & 0x0f) | (XFERP & 0x07)<<4;}static inline __u8NCR_700_get_SXFER(struct scsi_device *SDp){ struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; return NCR_700_offset_period_to_sxfer(hostdata, spi_offset(SDp), spi_period(SDp));}struct Scsi_Host *NCR_700_detect(struct scsi_host_template *tpnt, struct NCR_700_Host_Parameters *hostdata){ dma_addr_t pScript, pSlots; __u8 *memory; __u32 *script; struct Scsi_Host *host; static int banner = 0; int j; if(tpnt->sdev_attrs == NULL) tpnt->sdev_attrs = NCR_700_dev_attrs; memory = dma_alloc_noncoherent(hostdata->dev, TOTAL_MEM_SIZE, &pScript, GFP_KERNEL); if(memory == NULL) { printk(KERN_ERR "53c700: Failed to allocate memory for driver, detatching\n"); return NULL; } script = (__u32 *)memory; hostdata->msgin = memory + MSGIN_OFFSET; hostdata->msgout = memory + MSGOUT_OFFSET; hostdata->status = memory + STATUS_OFFSET; /* all of these offsets are L1_CACHE_BYTES separated. It is fatal * if this isn't sufficient separation to avoid dma flushing issues */ BUG_ON(!dma_is_consistent(pScript) && L1_CACHE_BYTES < dma_get_cache_alignment()); hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET); pSlots = pScript + SLOTS_OFFSET; /* Fill in the missing routines from the host template */ tpnt->queuecommand = NCR_700_queuecommand; tpnt->eh_abort_handler = NCR_700_abort; tpnt->eh_device_reset_handler = NCR_700_dev_reset; tpnt->eh_bus_reset_handler = NCR_700_bus_reset; tpnt->eh_host_reset_handler = NCR_700_host_reset; tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST; tpnt->sg_tablesize = NCR_700_SG_SEGMENTS; tpnt->cmd_per_lun = NCR_700_CMD_PER_LUN; tpnt->use_clustering = ENABLE_CLUSTERING; tpnt->slave_configure = NCR_700_slave_configure; tpnt->slave_destroy = NCR_700_slave_destroy; if(tpnt->name == NULL) tpnt->name = "53c700"; if(tpnt->proc_name == NULL) tpnt->proc_name = "53c700"; host = scsi_host_alloc(tpnt, 4); if (!host) return NULL; memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST); for(j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) { dma_addr_t offset = (dma_addr_t)((unsigned long)&hostdata->slots[j].SG[0] - (unsigned long)&hostdata->slots[0].SG[0]); hostdata->slots[j].pSG = (struct NCR_700_SG_List *)((unsigned long)(pSlots + offset)); if(j == 0) hostdata->free_list = &hostdata->slots[j]; else hostdata->slots[j-1].ITL_forw = &hostdata->slots[j]; hostdata->slots[j].state = NCR_700_SLOT_FREE; } for(j = 0; j < sizeof(SCRIPT)/sizeof(SCRIPT[0]); j++) { script[j] = bS_to_host(SCRIPT[j]); } /* adjust all labels to be bus physical */ for(j = 0; j < PATCHES; j++) { script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]); } /* now patch up fixed addresses. */ script_patch_32(script, MessageLocation, pScript + MSGOUT_OFFSET); script_patch_32(script, StatusAddress, pScript + STATUS_OFFSET); script_patch_32(script, ReceiveMsgAddress, pScript + MSGIN_OFFSET); hostdata->script = script; hostdata->pScript = pScript; dma_sync_single_for_device(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE); hostdata->state = NCR_700_HOST_FREE; hostdata->cmd = NULL; host->max_id = 7; host->max_lun = NCR_700_MAX_LUNS; BUG_ON(NCR_700_transport_template == NULL); host->transportt = NCR_700_transport_template; host->unique_id = hostdata->base; host->base = hostdata->base; hostdata->eh_complete = NULL; host->hostdata[0] = (unsigned long)hostdata; /* kick the chip */ NCR_700_writeb(0xff, host, CTEST9_REG); if(hostdata->chip710)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?