⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qlogicpti.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver. * * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) * * A lot of this driver was directly stolen from Erik H. Moe's PCI * Qlogic ISP driver.  Mucho kudos to him for this code. * * An even bigger kudos to John Grana at Performance Technologies * for providing me with the hardware to write this driver, you rule * John you really do. * * May, 2, 1997: Added support for QLGC,isp --jj */#include <linux/kernel.h>#include <linux/delay.h>#include <linux/types.h>#include <linux/string.h>#include <linux/malloc.h>#include <linux/blk.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/init.h>#include <linux/spinlock.h>#include <asm/byteorder.h>#include "scsi.h"#include "hosts.h"#include "qlogicpti.h"#include <asm/sbus.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/ptrace.h>#include <asm/pgtable.h>#include <asm/oplib.h>#include <asm/vaddrs.h>#include <asm/io.h>#include <asm/irq.h>#include <linux/module.h>#define MAX_TARGETS	16#define MAX_LUNS	8	/* 32 for 1.31 F/W */#define DEFAULT_LOOP_COUNT	10000#include "qlogicpti_asm.c"static struct qlogicpti *qptichain = NULL;static spinlock_t qptichain_lock = SPIN_LOCK_UNLOCKED;static int qptis_running = 0;#define PACKB(a, b)			(((a)<<4)|(b))const u_char mbox_param[] = {	PACKB(1, 1),	/* MBOX_NO_OP */	PACKB(5, 5),	/* MBOX_LOAD_RAM */	PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */	PACKB(5, 5),	/* MBOX_DUMP_RAM */	PACKB(3, 3),	/* MBOX_WRITE_RAM_WORD */	PACKB(2, 3),	/* MBOX_READ_RAM_WORD */	PACKB(6, 6),	/* MBOX_MAILBOX_REG_TEST */	PACKB(2, 3),	/* MBOX_VERIFY_CHECKSUM	*/	PACKB(1, 3),	/* MBOX_ABOUT_FIRMWARE */	PACKB(0, 0),	/* 0x0009 */	PACKB(0, 0),	/* 0x000a */	PACKB(0, 0),	/* 0x000b */	PACKB(0, 0),	/* 0x000c */	PACKB(0, 0),	/* 0x000d */	PACKB(1, 2),	/* MBOX_CHECK_FIRMWARE */	PACKB(0, 0),	/* 0x000f */	PACKB(5, 5),	/* MBOX_INIT_REQ_QUEUE */	PACKB(6, 6),	/* MBOX_INIT_RES_QUEUE */	PACKB(4, 4),	/* MBOX_EXECUTE_IOCB */	PACKB(2, 2),	/* MBOX_WAKE_UP	*/	PACKB(1, 6),	/* MBOX_STOP_FIRMWARE */	PACKB(4, 4),	/* MBOX_ABORT */	PACKB(2, 2),	/* MBOX_ABORT_DEVICE */	PACKB(3, 3),	/* MBOX_ABORT_TARGET */	PACKB(2, 2),	/* MBOX_BUS_RESET */	PACKB(2, 3),	/* MBOX_STOP_QUEUE */	PACKB(2, 3),	/* MBOX_START_QUEUE */	PACKB(2, 3),	/* MBOX_SINGLE_STEP_QUEUE */	PACKB(2, 3),	/* MBOX_ABORT_QUEUE */	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_STATUS */	PACKB(0, 0),	/* 0x001e */	PACKB(1, 3),	/* MBOX_GET_FIRMWARE_STATUS */	PACKB(1, 2),	/* MBOX_GET_INIT_SCSI_ID */	PACKB(1, 2),	/* MBOX_GET_SELECT_TIMEOUT */	PACKB(1, 3),	/* MBOX_GET_RETRY_COUNT	*/	PACKB(1, 2),	/* MBOX_GET_TAG_AGE_LIMIT */	PACKB(1, 2),	/* MBOX_GET_CLOCK_RATE */	PACKB(1, 2),	/* MBOX_GET_ACT_NEG_STATE */	PACKB(1, 2),	/* MBOX_GET_ASYNC_DATA_SETUP_TIME */	PACKB(1, 3),	/* MBOX_GET_SBUS_PARAMS */	PACKB(2, 4),	/* MBOX_GET_TARGET_PARAMS */	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_PARAMS */	PACKB(0, 0),	/* 0x002a */	PACKB(0, 0),	/* 0x002b */	PACKB(0, 0),	/* 0x002c */	PACKB(0, 0),	/* 0x002d */	PACKB(0, 0),	/* 0x002e */	PACKB(0, 0),	/* 0x002f */	PACKB(2, 2),	/* MBOX_SET_INIT_SCSI_ID */	PACKB(2, 2),	/* MBOX_SET_SELECT_TIMEOUT */	PACKB(3, 3),	/* MBOX_SET_RETRY_COUNT	*/	PACKB(2, 2),	/* MBOX_SET_TAG_AGE_LIMIT */	PACKB(2, 2),	/* MBOX_SET_CLOCK_RATE */	PACKB(2, 2),	/* MBOX_SET_ACTIVE_NEG_STATE */	PACKB(2, 2),	/* MBOX_SET_ASYNC_DATA_SETUP_TIME */	PACKB(3, 3),	/* MBOX_SET_SBUS_CONTROL_PARAMS */	PACKB(4, 4),	/* MBOX_SET_TARGET_PARAMS */	PACKB(4, 4),	/* MBOX_SET_DEV_QUEUE_PARAMS */	PACKB(0, 0),	/* 0x003a */	PACKB(0, 0),	/* 0x003b */	PACKB(0, 0),	/* 0x003c */	PACKB(0, 0),	/* 0x003d */	PACKB(0, 0),	/* 0x003e */	PACKB(0, 0),	/* 0x003f */	PACKB(0, 0),	/* 0x0040 */	PACKB(0, 0),	/* 0x0041 */	PACKB(0, 0)	/* 0x0042 */};#define MAX_MBOX_COMMAND	(sizeof(mbox_param)/sizeof(u_short))/* queue length's _must_ be power of two: */#define QUEUE_DEPTH(in, out, ql)	((in - out) & (ql))#define REQ_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, 		     \						    QLOGICPTI_REQ_QUEUE_LEN)#define RES_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, RES_QUEUE_LEN)static inline void qlogicpti_enable_irqs(struct qlogicpti *qpti){	sbus_writew(SBUS_CTRL_ERIRQ | SBUS_CTRL_GENAB,		    qpti->qregs + SBUS_CTRL);}static inline void qlogicpti_disable_irqs(struct qlogicpti *qpti){	sbus_writew(0, qpti->qregs + SBUS_CTRL);}static inline void set_sbus_cfg1(struct qlogicpti *qpti){	u16 val;	u8 bursts = qpti->bursts;#if 0	/* It appears that at least PTI cards do not support	 * 64-byte bursts and that setting the B64 bit actually	 * is a nop and the chip ends up using the smallest burst	 * size. -DaveM	 */	if (sbus_can_burst64(qpti->sdev) && (bursts & DMA_BURST64)) {		val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64);	} else#endif	if (bursts & DMA_BURST32) {		val = (SBUS_CFG1_BENAB | SBUS_CFG1_B32);	} else if (bursts & DMA_BURST16) {		val = (SBUS_CFG1_BENAB | SBUS_CFG1_B16);	} else if (bursts & DMA_BURST8) {		val = (SBUS_CFG1_BENAB | SBUS_CFG1_B8);	} else {		val = 0; /* No sbus bursts for you... */	}	sbus_writew(val, qpti->qregs + SBUS_CFG1);}static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int force){	int loop_count;	u16 tmp;	if (mbox_param[param[0]] == 0)		return 1;	/* Set SBUS semaphore. */	tmp = sbus_readw(qpti->qregs + SBUS_SEMAPHORE);	tmp |= SBUS_SEMAPHORE_LCK;	sbus_writew(tmp, qpti->qregs + SBUS_SEMAPHORE);	/* Wait for host IRQ bit to clear. */	loop_count = DEFAULT_LOOP_COUNT;	while (--loop_count && (sbus_readw(qpti->qregs + HCCTRL) & HCCTRL_HIRQ))		barrier();	if (!loop_count)		printk(KERN_EMERG "qlogicpti: mbox_command loop timeout #1\n");	/* Write mailbox command registers. */	switch (mbox_param[param[0]] >> 4) {	case 6: sbus_writew(param[5], qpti->qregs + MBOX5);	case 5: sbus_writew(param[4], qpti->qregs + MBOX4);	case 4: sbus_writew(param[3], qpti->qregs + MBOX3);	case 3: sbus_writew(param[2], qpti->qregs + MBOX2);	case 2: sbus_writew(param[1], qpti->qregs + MBOX1);	case 1: sbus_writew(param[0], qpti->qregs + MBOX0);	}	/* Clear RISC interrupt. */	tmp = sbus_readw(qpti->qregs + HCCTRL);	tmp |= HCCTRL_CRIRQ;	sbus_writew(tmp, qpti->qregs + HCCTRL);	/* Clear SBUS semaphore. */	sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE);	/* Set HOST interrupt. */	tmp = sbus_readw(qpti->qregs + HCCTRL);	tmp |= HCCTRL_SHIRQ;	sbus_writew(tmp, qpti->qregs + HCCTRL);	/* Wait for HOST interrupt clears. */	loop_count = DEFAULT_LOOP_COUNT;	while (--loop_count &&	       (sbus_readw(qpti->qregs + HCCTRL) & HCCTRL_CRIRQ))		udelay(20);	if (!loop_count)		printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #2\n",		       param[0]);	/* Wait for SBUS semaphore to get set. */	loop_count = DEFAULT_LOOP_COUNT;	while (--loop_count &&	       !(sbus_readw(qpti->qregs + SBUS_SEMAPHORE) & SBUS_SEMAPHORE_LCK)) {		udelay(20);		/* Workaround for some buggy chips. */		if (sbus_readw(qpti->qregs + MBOX0) & 0x4000)			break;	}	if (!loop_count)		printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #3\n",		       param[0]);	/* Wait for MBOX busy condition to go away. */	loop_count = DEFAULT_LOOP_COUNT;	while (--loop_count && (sbus_readw(qpti->qregs + MBOX0) == 0x04))		udelay(20);	if (!loop_count)		printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #4\n",		       param[0]);	/* Read back output parameters. */	switch (mbox_param[param[0]] & 0xf) {	case 6: param[5] = sbus_readw(qpti->qregs + MBOX5);	case 5: param[4] = sbus_readw(qpti->qregs + MBOX4);	case 4: param[3] = sbus_readw(qpti->qregs + MBOX3);	case 3: param[2] = sbus_readw(qpti->qregs + MBOX2);	case 2: param[1] = sbus_readw(qpti->qregs + MBOX1);	case 1: param[0] = sbus_readw(qpti->qregs + MBOX0);	}	/* Clear RISC interrupt. */	tmp = sbus_readw(qpti->qregs + HCCTRL);	tmp |= HCCTRL_CRIRQ;	sbus_writew(tmp, qpti->qregs + HCCTRL);	/* Release SBUS semaphore. */	tmp = sbus_readw(qpti->qregs + SBUS_SEMAPHORE);	tmp &= ~(SBUS_SEMAPHORE_LCK);	sbus_writew(tmp, qpti->qregs + SBUS_SEMAPHORE);	/* We're done. */	return 0;}static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti){	int i;	qpti->host_param.initiator_scsi_id = qpti->scsi_id;	qpti->host_param.bus_reset_delay = 3;	qpti->host_param.retry_count = 0;	qpti->host_param.retry_delay = 5;	qpti->host_param.async_data_setup_time = 3;	qpti->host_param.req_ack_active_negation = 1;	qpti->host_param.data_line_active_negation = 1;	qpti->host_param.data_dma_burst_enable = 1;	qpti->host_param.command_dma_burst_enable = 1;	qpti->host_param.tag_aging = 8;	qpti->host_param.selection_timeout = 250;	qpti->host_param.max_queue_depth = 256;	for(i = 0; i < MAX_TARGETS; i++) {		/*		 * disconnect, parity, arq, reneg on reset, and, oddly enough		 * tags...the midlayer's notion of tagged support has to match		 * our device settings, and since we base whether we enable a		 * tag on a  per-cmnd basis upon what the midlayer sez, we		 * actually enable the capability here.		 */		qpti->dev_param[i].device_flags = 0xcd;		qpti->dev_param[i].execution_throttle = 16;		if (qpti->ultra) {			qpti->dev_param[i].synchronous_period = 12;			qpti->dev_param[i].synchronous_offset = 8;		} else {			qpti->dev_param[i].synchronous_period = 25;			qpti->dev_param[i].synchronous_offset = 12;		}		qpti->dev_param[i].device_enable = 1;	}	/* this is very important to set! */	qpti->sbits = 1 << qpti->scsi_id;}static int qlogicpti_reset_hardware(struct Scsi_Host *host){	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;	u_short param[6];	unsigned short risc_code_addr;	int loop_count, i;	unsigned long flags;	risc_code_addr = 0x1000;	/* all load addresses are at 0x1000 */	save_flags(flags); cli();	sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL);	/* Only reset the scsi bus if it is not free. */	if (sbus_readw(qpti->qregs + CPU_PCTRL) & CPU_PCTRL_BSY) {		sbus_writew(CPU_ORIDE_RMOD, qpti->qregs + CPU_ORIDE);		sbus_writew(CPU_CMD_BRESET, qpti->qregs + CPU_CMD);		udelay(400);	}	sbus_writew(SBUS_CTRL_RESET, qpti->qregs + SBUS_CTRL);	sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + CMD_DMA_CTRL);	sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + DATA_DMA_CTRL);	loop_count = DEFAULT_LOOP_COUNT;	while (--loop_count && ((sbus_readw(qpti->qregs + MBOX0) & 0xff) == 0x04))		udelay(20);	if (!loop_count)		printk(KERN_EMERG "qlogicpti: reset_hardware loop timeout\n");	sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL);	set_sbus_cfg1(qpti);	qlogicpti_enable_irqs(qpti);	if (sbus_readw(qpti->qregs + RISC_PSR) & RISC_PSR_ULTRA) {		qpti->ultra = 1;		sbus_writew((RISC_MTREG_P0ULTRA | RISC_MTREG_P1ULTRA),			    qpti->qregs + RISC_MTREG);	} else {		qpti->ultra = 0;		sbus_writew((RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT),			    qpti->qregs + RISC_MTREG);	}	/* reset adapter and per-device default values. */	/* do it after finding out whether we're ultra mode capable */	qlogicpti_set_hostdev_defaults(qpti);	/* Release the RISC processor. */	sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL);	/* Get RISC to start executing the firmware code. */	param[0] = MBOX_EXEC_FIRMWARE;	param[1] = risc_code_addr;	if (qlogicpti_mbox_command(qpti, param, 1)) {		printk(KERN_EMERG "qlogicpti%d: Cannot execute ISP firmware.\n",		       qpti->qpti_id);		restore_flags(flags);		return 1;	}	/* Set initiator scsi ID. */	param[0] = MBOX_SET_INIT_SCSI_ID;	param[1] = qpti->host_param.initiator_scsi_id;	if (qlogicpti_mbox_command(qpti, param, 1) ||	   (param[0] != MBOX_COMMAND_COMPLETE)) {		printk(KERN_EMERG "qlogicpti%d: Cannot set initiator SCSI ID.\n",		       qpti->qpti_id);		restore_flags(flags);		return 1;	}	/* Initialize state of the queues, both hw and sw. */	qpti->req_in_ptr = qpti->res_out_ptr = 0;	param[0] = MBOX_INIT_RES_QUEUE;	param[1] = RES_QUEUE_LEN + 1;	param[2] = (u_short) (qpti->res_dvma >> 16);	param[3] = (u_short) (qpti->res_dvma & 0xffff);	param[4] = param[5] = 0;	if (qlogicpti_mbox_command(qpti, param, 1)) {		printk(KERN_EMERG "qlogicpti%d: Cannot init response queue.\n",		       qpti->qpti_id);		restore_flags(flags);		return 1;	}	param[0] = MBOX_INIT_REQ_QUEUE;	param[1] = QLOGICPTI_REQ_QUEUE_LEN + 1;	param[2] = (u_short) (qpti->req_dvma >> 16);	param[3] = (u_short) (qpti->req_dvma & 0xffff);	param[4] = param[5] = 0;	if (qlogicpti_mbox_command(qpti, param, 1)) {		printk(KERN_EMERG "qlogicpti%d: Cannot init request queue.\n",		       qpti->qpti_id);		restore_flags(flags);		return 1;	}	param[0] = MBOX_SET_RETRY_COUNT;	param[1] = qpti->host_param.retry_count;	param[2] = qpti->host_param.retry_delay;	qlogicpti_mbox_command(qpti, param, 0);	param[0] = MBOX_SET_TAG_AGE_LIMIT;	param[1] = qpti->host_param.tag_aging;	qlogicpti_mbox_command(qpti, param, 0);	for (i = 0; i < MAX_TARGETS; i++) {		param[0] = MBOX_GET_DEV_QUEUE_PARAMS;		param[1] = (i << 8);		qlogicpti_mbox_command(qpti, param, 0);	}	param[0] = MBOX_GET_FIRMWARE_STATUS;	qlogicpti_mbox_command(qpti, param, 0);	param[0] = MBOX_SET_SELECT_TIMEOUT;	param[1] = qpti->host_param.selection_timeout;	qlogicpti_mbox_command(qpti, param, 0);	for (i = 0; i < MAX_TARGETS; i++) {		param[0] = MBOX_SET_TARGET_PARAMS;		param[1] = (i << 8);		param[2] = (qpti->dev_param[i].device_flags << 8);		/*		 * Since we're now loading 1.31 f/w, force narrow/async.		 */		param[2] |= 0xc0;		param[3] = 0;	/* no offset, we do not have sync mode yet */		qlogicpti_mbox_command(qpti, param, 0);	}	/*	 * Always (sigh) do an initial bus reset (kicks f/w).	 */	param[0] = MBOX_BUS_RESET;	param[1] = qpti->host_param.bus_reset_delay;	qlogicpti_mbox_command(qpti, param, 0);	qpti->send_marker = 1;	restore_flags(flags);	return 0;}#define PTI_RESET_LIMIT 400static int __init qlogicpti_load_firmware(struct qlogicpti *qpti){	unsigned short csum = 0;	unsigned short param[6];	unsigned short *risc_code, risc_code_addr, risc_code_length;	unsigned long flags;	int i, timeout;	risc_code = &sbus_risc_code01[0];	risc_code_addr = 0x1000;	/* all f/w modules load at 0x1000 */	risc_code_length = sbus_risc_code_length01;	save_flags(flags); cli();	/* Verify the checksum twice, one before loading it, and once	 * afterwards via the mailbox commands.	 */	for (i = 0; i < risc_code_length; i++)		csum += risc_code[i];	if (csum) {		restore_flags(flags);		printk(KERN_EMERG "qlogicpti%d: Aieee, firmware checksum failed!",		       qpti->qpti_id);		return 1;	}			sbus_writew(SBUS_CTRL_RESET, qpti->qregs + SBUS_CTRL);	sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + CMD_DMA_CTRL);	sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + DATA_DMA_CTRL);	timeout = PTI_RESET_LIMIT;	while (--timeout && (sbus_readw(qpti->qregs + SBUS_CTRL) & SBUS_CTRL_RESET))		udelay(20);	if (!timeout) {		restore_flags(flags);		printk(KERN_EMERG "qlogicpti%d: Cannot reset the ISP.", qpti->qpti_id);		return 1;	}	sbus_writew(HCCTRL_RESET, qpti->qregs + HCCTRL);	mdelay(1);	sbus_writew((SBUS_CTRL_GENAB | SBUS_CTRL_ERIRQ), qpti->qregs + SBUS_CTRL);	set_sbus_cfg1(qpti);	sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE);	if (sbus_readw(qpti->qregs + RISC_PSR) & RISC_PSR_ULTRA) {		qpti->ultra = 1;		sbus_writew((RISC_MTREG_P0ULTRA | RISC_MTREG_P1ULTRA),			    qpti->qregs + RISC_MTREG);	} else {		qpti->ultra = 0;		sbus_writew((RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT),			    qpti->qregs + RISC_MTREG);	}	sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL);

⌨️ 快捷键说明

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