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 + -
显示快捷键?