esp_scsi.c

来自「linux 内核源代码」· C语言 代码 · 共 2,700 行 · 第 1/5 页

C
2,700
字号
/* esp_scsi.c: ESP SCSI driver. * * Copyright (C) 2007 David S. Miller (davem@davemloft.net) */#include <linux/kernel.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/list.h>#include <linux/completion.h>#include <linux/kallsyms.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/irqreturn.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/dma.h>#include <scsi/scsi.h>#include <scsi/scsi_host.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_tcq.h>#include <scsi/scsi_dbg.h>#include <scsi/scsi_transport_spi.h>#include "esp_scsi.h"#define DRV_MODULE_NAME		"esp"#define PFX DRV_MODULE_NAME	": "#define DRV_VERSION		"2.000"#define DRV_MODULE_RELDATE	"April 19, 2007"/* SCSI bus reset settle time in seconds.  */static int esp_bus_reset_settle = 3;static u32 esp_debug;#define ESP_DEBUG_INTR		0x00000001#define ESP_DEBUG_SCSICMD	0x00000002#define ESP_DEBUG_RESET		0x00000004#define ESP_DEBUG_MSGIN		0x00000008#define ESP_DEBUG_MSGOUT	0x00000010#define ESP_DEBUG_CMDDONE	0x00000020#define ESP_DEBUG_DISCONNECT	0x00000040#define ESP_DEBUG_DATASTART	0x00000080#define ESP_DEBUG_DATADONE	0x00000100#define ESP_DEBUG_RECONNECT	0x00000200#define ESP_DEBUG_AUTOSENSE	0x00000400#define esp_log_intr(f, a...) \do {	if (esp_debug & ESP_DEBUG_INTR) \		printk(f, ## a); \} while (0)#define esp_log_reset(f, a...) \do {	if (esp_debug & ESP_DEBUG_RESET) \		printk(f, ## a); \} while (0)#define esp_log_msgin(f, a...) \do {	if (esp_debug & ESP_DEBUG_MSGIN) \		printk(f, ## a); \} while (0)#define esp_log_msgout(f, a...) \do {	if (esp_debug & ESP_DEBUG_MSGOUT) \		printk(f, ## a); \} while (0)#define esp_log_cmddone(f, a...) \do {	if (esp_debug & ESP_DEBUG_CMDDONE) \		printk(f, ## a); \} while (0)#define esp_log_disconnect(f, a...) \do {	if (esp_debug & ESP_DEBUG_DISCONNECT) \		printk(f, ## a); \} while (0)#define esp_log_datastart(f, a...) \do {	if (esp_debug & ESP_DEBUG_DATASTART) \		printk(f, ## a); \} while (0)#define esp_log_datadone(f, a...) \do {	if (esp_debug & ESP_DEBUG_DATADONE) \		printk(f, ## a); \} while (0)#define esp_log_reconnect(f, a...) \do {	if (esp_debug & ESP_DEBUG_RECONNECT) \		printk(f, ## a); \} while (0)#define esp_log_autosense(f, a...) \do {	if (esp_debug & ESP_DEBUG_AUTOSENSE) \		printk(f, ## a); \} while (0)#define esp_read8(REG)		esp->ops->esp_read8(esp, REG)#define esp_write8(VAL,REG)	esp->ops->esp_write8(esp, VAL, REG)static void esp_log_fill_regs(struct esp *esp,			      struct esp_event_ent *p){	p->sreg = esp->sreg;	p->seqreg = esp->seqreg;	p->sreg2 = esp->sreg2;	p->ireg = esp->ireg;	p->select_state = esp->select_state;	p->event = esp->event;}void scsi_esp_cmd(struct esp *esp, u8 val){	struct esp_event_ent *p;	int idx = esp->esp_event_cur;	p = &esp->esp_event_log[idx];	p->type = ESP_EVENT_TYPE_CMD;	p->val = val;	esp_log_fill_regs(esp, p);	esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);	esp_write8(val, ESP_CMD);}EXPORT_SYMBOL(scsi_esp_cmd);static void esp_event(struct esp *esp, u8 val){	struct esp_event_ent *p;	int idx = esp->esp_event_cur;	p = &esp->esp_event_log[idx];	p->type = ESP_EVENT_TYPE_EVENT;	p->val = val;	esp_log_fill_regs(esp, p);	esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);	esp->event = val;}static void esp_dump_cmd_log(struct esp *esp){	int idx = esp->esp_event_cur;	int stop = idx;	printk(KERN_INFO PFX "esp%d: Dumping command log\n",	       esp->host->unique_id);	do {		struct esp_event_ent *p = &esp->esp_event_log[idx];		printk(KERN_INFO PFX "esp%d: ent[%d] %s ",		       esp->host->unique_id, idx,		       p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT");		printk("val[%02x] sreg[%02x] seqreg[%02x] "		       "sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n",		       p->val, p->sreg, p->seqreg,		       p->sreg2, p->ireg, p->select_state, p->event);		idx = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);	} while (idx != stop);}static void esp_flush_fifo(struct esp *esp){	scsi_esp_cmd(esp, ESP_CMD_FLUSH);	if (esp->rev == ESP236) {		int lim = 1000;		while (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) {			if (--lim == 0) {				printk(KERN_ALERT PFX "esp%d: ESP_FF_BYTES "				       "will not clear!\n",				       esp->host->unique_id);				break;			}			udelay(1);		}	}}static void hme_read_fifo(struct esp *esp){	int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;	int idx = 0;	while (fcnt--) {		esp->fifo[idx++] = esp_read8(ESP_FDATA);		esp->fifo[idx++] = esp_read8(ESP_FDATA);	}	if (esp->sreg2 & ESP_STAT2_F1BYTE) {		esp_write8(0, ESP_FDATA);		esp->fifo[idx++] = esp_read8(ESP_FDATA);		scsi_esp_cmd(esp, ESP_CMD_FLUSH);	}	esp->fifo_cnt = idx;}static void esp_set_all_config3(struct esp *esp, u8 val){	int i;	for (i = 0; i < ESP_MAX_TARGET; i++)		esp->target[i].esp_config3 = val;}/* Reset the ESP chip, _not_ the SCSI bus. */static void esp_reset_esp(struct esp *esp){	u8 family_code, version;	/* Now reset the ESP chip */	scsi_esp_cmd(esp, ESP_CMD_RC);	scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);	scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);	/* Reload the configuration registers */	esp_write8(esp->cfact, ESP_CFACT);	esp->prev_stp = 0;	esp_write8(esp->prev_stp, ESP_STP);	esp->prev_soff = 0;	esp_write8(esp->prev_soff, ESP_SOFF);	esp_write8(esp->neg_defp, ESP_TIMEO);	/* This is the only point at which it is reliable to read	 * the ID-code for a fast ESP chip variants.	 */	esp->max_period = ((35 * esp->ccycle) / 1000);	if (esp->rev == FAST) {		version = esp_read8(ESP_UID);		family_code = (version & 0xf8) >> 3;		if (family_code == 0x02)			esp->rev = FAS236;		else if (family_code == 0x0a)			esp->rev = FASHME; /* Version is usually '5'. */		else			esp->rev = FAS100A;		esp->min_period = ((4 * esp->ccycle) / 1000);	} else {		esp->min_period = ((5 * esp->ccycle) / 1000);	}	esp->max_period = (esp->max_period + 3)>>2;	esp->min_period = (esp->min_period + 3)>>2;	esp_write8(esp->config1, ESP_CFG1);	switch (esp->rev) {	case ESP100:		/* nothing to do */		break;	case ESP100A:		esp_write8(esp->config2, ESP_CFG2);		break;	case ESP236:		/* Slow 236 */		esp_write8(esp->config2, ESP_CFG2);		esp->prev_cfg3 = esp->target[0].esp_config3;		esp_write8(esp->prev_cfg3, ESP_CFG3);		break;	case FASHME:		esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);		/* fallthrough... */	case FAS236:		/* Fast 236 or HME */		esp_write8(esp->config2, ESP_CFG2);		if (esp->rev == FASHME) {			u8 cfg3 = esp->target[0].esp_config3;			cfg3 |= ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;			if (esp->scsi_id >= 8)				cfg3 |= ESP_CONFIG3_IDBIT3;			esp_set_all_config3(esp, cfg3);		} else {			u32 cfg3 = esp->target[0].esp_config3;			cfg3 |= ESP_CONFIG3_FCLK;			esp_set_all_config3(esp, cfg3);		}		esp->prev_cfg3 = esp->target[0].esp_config3;		esp_write8(esp->prev_cfg3, ESP_CFG3);		if (esp->rev == FASHME) {			esp->radelay = 80;		} else {			if (esp->flags & ESP_FLAG_DIFFERENTIAL)				esp->radelay = 0;			else				esp->radelay = 96;		}		break;	case FAS100A:		/* Fast 100a */		esp_write8(esp->config2, ESP_CFG2);		esp_set_all_config3(esp,				    (esp->target[0].esp_config3 |				     ESP_CONFIG3_FCLOCK));		esp->prev_cfg3 = esp->target[0].esp_config3;		esp_write8(esp->prev_cfg3, ESP_CFG3);		esp->radelay = 32;		break;	default:		break;	}	/* Eat any bitrot in the chip */	esp_read8(ESP_INTRPT);	udelay(100);}static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd){	struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);	struct scatterlist *sg = scsi_sglist(cmd);	int dir = cmd->sc_data_direction;	int total, i;	if (dir == DMA_NONE)		return;	spriv->u.num_sg = esp->ops->map_sg(esp, sg, scsi_sg_count(cmd), dir);	spriv->cur_residue = sg_dma_len(sg);	spriv->cur_sg = sg;	total = 0;	for (i = 0; i < spriv->u.num_sg; i++)		total += sg_dma_len(&sg[i]);	spriv->tot_residue = total;}static dma_addr_t esp_cur_dma_addr(struct esp_cmd_entry *ent,				   struct scsi_cmnd *cmd){	struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {		return ent->sense_dma +			(ent->sense_ptr - cmd->sense_buffer);	}	return sg_dma_address(p->cur_sg) +		(sg_dma_len(p->cur_sg) -		 p->cur_residue);}static unsigned int esp_cur_dma_len(struct esp_cmd_entry *ent,				    struct scsi_cmnd *cmd){	struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {		return SCSI_SENSE_BUFFERSIZE -			(ent->sense_ptr - cmd->sense_buffer);	}	return p->cur_residue;}static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,			    struct scsi_cmnd *cmd, unsigned int len){	struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {		ent->sense_ptr += len;		return;	}	p->cur_residue -= len;	p->tot_residue -= len;	if (p->cur_residue < 0 || p->tot_residue < 0) {		printk(KERN_ERR PFX "esp%d: Data transfer overflow.\n",		       esp->host->unique_id);		printk(KERN_ERR PFX "esp%d: cur_residue[%d] tot_residue[%d] "		       "len[%u]\n",		       esp->host->unique_id,		       p->cur_residue, p->tot_residue, len);		p->cur_residue = 0;		p->tot_residue = 0;	}	if (!p->cur_residue && p->tot_residue) {		p->cur_sg++;		p->cur_residue = sg_dma_len(p->cur_sg);	}}static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd){	struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);	int dir = cmd->sc_data_direction;	if (dir == DMA_NONE)		return;	esp->ops->unmap_sg(esp, scsi_sglist(cmd), spriv->u.num_sg, dir);}static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent){	struct scsi_cmnd *cmd = ent->cmd;	struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {		ent->saved_sense_ptr = ent->sense_ptr;		return;	}	ent->saved_cur_residue = spriv->cur_residue;	ent->saved_cur_sg = spriv->cur_sg;	ent->saved_tot_residue = spriv->tot_residue;}static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent){	struct scsi_cmnd *cmd = ent->cmd;	struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);	if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {		ent->sense_ptr = ent->saved_sense_ptr;		return;	}	spriv->cur_residue = ent->saved_cur_residue;	spriv->cur_sg = ent->saved_cur_sg;	spriv->tot_residue = ent->saved_tot_residue;}static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd){	if (cmd->cmd_len == 6 ||	    cmd->cmd_len == 10 ||	    cmd->cmd_len == 12) {		esp->flags &= ~ESP_FLAG_DOING_SLOWCMD;	} else {		esp->flags |= ESP_FLAG_DOING_SLOWCMD;	}}static void esp_write_tgt_config3(struct esp *esp, int tgt){	if (esp->rev > ESP100A) {		u8 val = esp->target[tgt].esp_config3;		if (val != esp->prev_cfg3) {			esp->prev_cfg3 = val;			esp_write8(val, ESP_CFG3);		}	}}static void esp_write_tgt_sync(struct esp *esp, int tgt){	u8 off = esp->target[tgt].esp_offset;	u8 per = esp->target[tgt].esp_period;	if (off != esp->prev_soff) {		esp->prev_soff = off;		esp_write8(off, ESP_SOFF);	}	if (per != esp->prev_stp) {		esp->prev_stp = per;		esp_write8(per, ESP_STP);	}}static u32 esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len){	if (esp->rev == FASHME) {		/* Arbitrary segment boundaries, 24-bit counts.  */		if (dma_len > (1U << 24))			dma_len = (1U << 24);	} else {		u32 base, end;		/* ESP chip limits other variants by 16-bits of transfer		 * count.  Actually on FAS100A and FAS236 we could get		 * 24-bits of transfer count by enabling ESP_CONFIG2_FENAB		 * in the ESP_CFG2 register but that causes other unwanted		 * changes so we don't use it currently.		 */		if (dma_len > (1U << 16))			dma_len = (1U << 16);		/* All of the DMA variants hooked up to these chips		 * cannot handle crossing a 24-bit address boundary.		 */		base = dma_addr & ((1U << 24) - 1U);		end = base + dma_len;		if (end > (1U << 24))			end = (1U <<24);		dma_len = end - base;	}	return dma_len;}static int esp_need_to_nego_wide(struct esp_target_data *tp){	struct scsi_target *target = tp->starget;	return spi_width(target) != tp->nego_goal_width;}static int esp_need_to_nego_sync(struct esp_target_data *tp){	struct scsi_target *target = tp->starget;	/* When offset is zero, period is "don't care".  */	if (!spi_offset(target) && !tp->nego_goal_offset)		return 0;	if (spi_offset(target) == tp->nego_goal_offset &&	    spi_period(target) == tp->nego_goal_period)		return 0;	return 1;}static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,			     struct esp_lun_data *lp){	if (!ent->tag[0]) {		/* Non-tagged, slot already taken?  */		if (lp->non_tagged_cmd)			return -EBUSY;		if (lp->hold) {			/* We are being held by active tagged			 * commands.			 */			if (lp->num_tagged)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?