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

📄 qlogicpti.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* Pin lines are only stable while RISC is paused. */	sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL);	if (sbus_readw(qpti->qregs + CPU_PDIFF) & CPU_PDIFF_MODE)		qpti->differential = 1;	else		qpti->differential = 0;	sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL);	/* This shouldn't be necessary- we've reset things so we should be	   running from the ROM now.. */	param[0] = MBOX_STOP_FIRMWARE;	param[1] = param[2] = param[3] = param[4] = param[5] = 0;	if (qlogicpti_mbox_command(qpti, param, 1)) {		printk(KERN_EMERG "qlogicpti%d: Cannot stop firmware for reload.\n",		       qpti->qpti_id);		restore_flags(flags);		return 1;	}			/* Load it up.. */	for (i = 0; i < risc_code_length; i++) {		param[0] = MBOX_WRITE_RAM_WORD;		param[1] = risc_code_addr + i;		param[2] = risc_code[i];		if (qlogicpti_mbox_command(qpti, param, 1) ||		    param[0] != MBOX_COMMAND_COMPLETE) {			printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",			       qpti->qpti_id);			restore_flags(flags);			return 1;		}	}	/* Reset the ISP again. */	sbus_writew(HCCTRL_RESET, qpti->qregs + HCCTRL);	mdelay(1);	qlogicpti_enable_irqs(qpti);	sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE);	sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL);	/* Ask ISP to verify the checksum of the new code. */	param[0] = MBOX_VERIFY_CHECKSUM;	param[1] = risc_code_addr;	if (qlogicpti_mbox_command(qpti, param, 1) ||	    (param[0] != MBOX_COMMAND_COMPLETE)) {		printk(KERN_EMERG "qlogicpti%d: New firmware csum failure!\n",		       qpti->qpti_id);		restore_flags(flags);		return 1;	}	/* Start using newly downloaded firmware. */	param[0] = MBOX_EXEC_FIRMWARE;	param[1] = risc_code_addr;	qlogicpti_mbox_command(qpti, param, 1);	param[0] = MBOX_ABOUT_FIRMWARE;	if (qlogicpti_mbox_command(qpti, param, 1) ||	    (param[0] != MBOX_COMMAND_COMPLETE)) {		printk(KERN_EMERG "qlogicpti%d: AboutFirmware cmd fails.\n",		       qpti->qpti_id);		restore_flags(flags);		return 1;	}	/* Snag the major and minor revisions from the result. */	qpti->fware_majrev = param[1];	qpti->fware_minrev = param[2];	qpti->fware_micrev = param[3];	/* Set the clock rate */	param[0] = MBOX_SET_CLOCK_RATE;	param[1] = qpti->clock;	if (qlogicpti_mbox_command(qpti, param, 1) ||	    (param[0] != MBOX_COMMAND_COMPLETE)) {		printk(KERN_EMERG "qlogicpti%d: could not set clock rate.\n",		       qpti->qpti_id);		restore_flags(flags);		return 1;	}	if (qpti->is_pti != 0) {		/* Load scsi initiator ID and interrupt level into sbus static ram. */		param[0] = MBOX_WRITE_RAM_WORD;		param[1] = 0xff80;		param[2] = (unsigned short) qpti->scsi_id;		qlogicpti_mbox_command(qpti, param, 1);		param[0] = MBOX_WRITE_RAM_WORD;		param[1] = 0xff00;		param[2] = (unsigned short) 3;		qlogicpti_mbox_command(qpti, param, 1);	}	restore_flags(flags);	return 0;}static int qlogicpti_verify_tmon(struct qlogicpti *qpti){	int curstat = sbus_readb(qpti->sreg);	curstat &= 0xf0;	if (!(curstat & SREG_FUSE) && (qpti->swsreg & SREG_FUSE))		printk("qlogicpti%d: Fuse returned to normal state.\n", qpti->qpti_id);	if (!(curstat & SREG_TPOWER) && (qpti->swsreg & SREG_TPOWER))		printk("qlogicpti%d: termpwr back to normal state.\n", qpti->qpti_id);	if (curstat != qpti->swsreg) {		int error = 0;		if (curstat & SREG_FUSE) {			error++;			printk("qlogicpti%d: Fuse is open!\n", qpti->qpti_id);		}		if (curstat & SREG_TPOWER) {			error++;			printk("qlogicpti%d: termpwr failure\n", qpti->qpti_id);		}		if (qpti->differential &&		    (curstat & SREG_DSENSE) != SREG_DSENSE) {			error++;			printk("qlogicpti%d: You have a single ended device on a "			       "differential bus!  Please fix!\n", qpti->qpti_id);		}		qpti->swsreg = curstat;		return error;	}	return 0;}static void qpti_intr(int irq, void *dev_id, struct pt_regs *regs);static void __init qpti_chain_add(struct qlogicpti *qpti){	spin_lock_irq(&qptichain_lock);	if (qptichain != NULL) {		struct qlogicpti *qlink = qptichain;		while(qlink->next)			qlink = qlink->next;		qlink->next = qpti;	} else {		qptichain = qpti;	}	qpti->next = NULL;	spin_unlock_irq(&qptichain_lock);}static void __init qpti_chain_del(struct qlogicpti *qpti){	spin_lock_irq(&qptichain_lock);	if (qptichain == qpti) {		qptichain = qpti->next;	} else {		struct qlogicpti *qlink = qptichain;		while(qlink->next != qpti)			qlink = qlink->next;		qlink->next = qpti->next;	}	qpti->next = NULL;	spin_unlock_irq(&qptichain_lock);}static int __init qpti_map_regs(struct qlogicpti *qpti){	struct sbus_dev *sdev = qpti->sdev;	qpti->qregs = sbus_ioremap(&sdev->resource[0], 0,				   sdev->reg_addrs[0].reg_size,				   "PTI Qlogic/ISP");	if (!qpti->qregs) {		printk("PTI: Qlogic/ISP registers are unmappable\n");		return -1;	}	if (qpti->is_pti) {		qpti->sreg = sbus_ioremap(&sdev->resource[0], (16 * 4096),					  sizeof(unsigned char),					  "PTI Qlogic/ISP statreg");		if (!qpti->sreg) {			printk("PTI: Qlogic/ISP status register is unmappable\n");			return -1;		}	}	return 0;}static int __init qpti_register_irq(struct qlogicpti *qpti){	struct sbus_dev *sdev = qpti->sdev;	qpti->qhost->irq = qpti->irq = sdev->irqs[0];	/* We used to try various overly-clever things to	 * reduce the interrupt processing overhead on	 * sun4c/sun4m when multiple PTI's shared the	 * same IRQ.  It was too complex and messy to	 * sanely maintain.	 */	if (request_irq(qpti->irq, qpti_intr,			SA_SHIRQ, "Qlogic/PTI", qpti))		goto fail;	printk("qpti%d: IRQ %s ", qpti->qpti_id, __irq_itoa(qpti->irq));	return 0;fail:	printk("qpti%d: Cannot acquire irq line\n", qpti->qpti_id);	return -1;}static void __init qpti_get_scsi_id(struct qlogicpti *qpti){	qpti->scsi_id = prom_getintdefault(qpti->prom_node,					   "initiator-id",					   -1);	if (qpti->scsi_id == -1)		qpti->scsi_id = prom_getintdefault(qpti->prom_node,						   "scsi-initiator-id",						   -1);	if (qpti->scsi_id == -1)		qpti->scsi_id =			prom_getintdefault(qpti->sdev->bus->prom_node,					   "scsi-initiator-id", 7);	qpti->qhost->this_id = qpti->scsi_id;	printk("SCSI ID %d ", qpti->scsi_id);}static void qpti_get_bursts(struct qlogicpti *qpti){	struct sbus_dev *sdev = qpti->sdev;	u8 bursts, bmask;	bursts = prom_getintdefault(qpti->prom_node, "burst-sizes", 0xff);	bmask = prom_getintdefault(sdev->bus->prom_node,				   "burst-sizes", 0xff);	if (bmask != 0xff)		bursts &= bmask;	if (bursts == 0xff ||	    (bursts & DMA_BURST16) == 0 ||	    (bursts & DMA_BURST32) == 0)		bursts = (DMA_BURST32 - 1);	qpti->bursts = bursts;}static void qpti_get_clock(struct qlogicpti *qpti){	unsigned int cfreq;	/* Check for what the clock input to this card is.	 * Default to 40Mhz.	 */	cfreq = prom_getintdefault(qpti->prom_node,"clock-frequency",40000000);	qpti->clock = (cfreq + 500000)/1000000;	if (qpti->clock == 0) /* bullshit */		qpti->clock = 40;}/* The request and response queues must each be aligned * on a page boundry. */static int __init qpti_map_queues(struct qlogicpti *qpti){	struct sbus_dev *sdev = qpti->sdev;#define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)	qpti->res_cpu = sbus_alloc_consistent(sdev,					      QSIZE(RES_QUEUE_LEN),					      &qpti->res_dvma);	if (qpti->res_cpu == NULL ||	    qpti->res_dvma == 0) {		printk("QPTI: Cannot map response queue.\n");		return -1;	}	qpti->req_cpu = sbus_alloc_consistent(sdev,					      QSIZE(QLOGICPTI_REQ_QUEUE_LEN),					      &qpti->req_dvma);	if (qpti->req_cpu == NULL ||	    qpti->req_dvma == 0) {		sbus_free_consistent(sdev, QSIZE(RES_QUEUE_LEN),				     qpti->res_cpu, qpti->res_dvma);		printk("QPTI: Cannot map request queue.\n");		return -1;	}	memset(qpti->res_cpu, 0, QSIZE(RES_QUEUE_LEN));	memset(qpti->req_cpu, 0, QSIZE(QLOGICPTI_REQ_QUEUE_LEN));	return 0;}/* Detect all PTI Qlogic ISP's in the machine. */int __init qlogicpti_detect(Scsi_Host_Template *tpnt){	struct qlogicpti *qpti;	struct Scsi_Host *qpti_host;	struct sbus_bus *sbus;	struct sbus_dev *sdev;	int nqptis = 0, nqptis_in_use = 0;	tpnt->proc_name = "qlogicpti";	for_each_sbus(sbus) {		for_each_sbusdev(sdev, sbus) {			/* Is this a red snapper? */			if (strcmp(sdev->prom_name, "ptisp") &&			    strcmp(sdev->prom_name, "PTI,ptisp") &&			    strcmp(sdev->prom_name, "QLGC,isp"))				continue;			/* Sometimes Antares cards come up not completely			 * setup, and we get a report of a zero IRQ.			 * Skip over them in such cases so we survive.			 */			if (sdev->irqs[0] == 0) {				printk("qpti%d: Adapter reports no interrupt, "				       "skipping over this card.", nqptis);				continue;			}			/* Yep, register and allocate software state. */			qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti));			if (!qpti_host) {				printk("QPTI: Cannot register PTI Qlogic ISP SCSI host");				continue;			}			qpti = (struct qlogicpti *) qpti_host->hostdata;			spin_lock_init(&qpti->lock);			/* We are wide capable, 16 targets. */			qpti_host->max_id = MAX_TARGETS;			/* Setup back pointers and misc. state. */			qpti->qhost = qpti_host;			qpti->sdev = sdev;			qpti->qpti_id = nqptis++;			qpti->prom_node = sdev->prom_node;			prom_getstring(qpti->prom_node, "name",				       qpti->prom_name,				       sizeof(qpti->prom_name));			/* This is not correct, actually. There's a switch			 * on the PTI cards that put them into "emulation"			 * mode- i.e., report themselves as QLGC,isp			 * instead of PTI,ptisp. The only real substantive			 * difference between non-pti and pti cards is			 * the tmon register. Which is possibly even			 * there for Qlogic cards, but non-functional.			 */			qpti->is_pti = (strcmp (qpti->prom_name, "QLGC,isp") != 0);			qpti_chain_add(qpti);			if (qpti_map_regs(qpti) < 0)				goto fail_unlink;			if (qpti_register_irq(qpti) < 0)				goto fail_unmap_regs;			qpti_get_scsi_id(qpti);			qpti_get_bursts(qpti);			qpti_get_clock(qpti);			/* Clear out Scsi_Cmnd array. */			memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));			if (qpti_map_queues(qpti) < 0)				goto fail_free_irq;			/* Load the firmware. */			if (qlogicpti_load_firmware(qpti))				goto fail_unmap_queues;			if (qpti->is_pti) {				/* Check the PTI status reg. */				if (qlogicpti_verify_tmon(qpti))					goto fail_unmap_queues;			}			/* Reset the ISP and init res/req queues. */			if (qlogicpti_reset_hardware(qpti_host))				goto fail_unmap_queues;			printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,			    qpti->fware_minrev, qpti->fware_micrev);			{				char buffer[60];								prom_getstring (qpti->prom_node,						"isp-fcode", buffer, 60);				if (buffer[0])					printk("(Firmware %s)", buffer);				if (prom_getbool(qpti->prom_node, "differential"))					qpti->differential = 1;			}						printk (" [%s Wide, using %s interface]\n",			       (qpti->ultra ? "Ultra" : "Fast"),			       (qpti->differential ? "differential" : "single ended"));			nqptis_in_use++;			continue;		fail_unmap_queues:#define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)			sbus_free_consistent(qpti->sdev,					     QSIZE(RES_QUEUE_LEN),					     qpti->res_cpu, qpti->res_dvma);			sbus_free_consistent(qpti->sdev,					     QSIZE(QLOGICPTI_REQ_QUEUE_LEN),					     qpti->req_cpu, qpti->req_dvma);#undef QSIZE		fail_free_irq:			free_irq(qpti->irq, qpti);		fail_unmap_regs:			sbus_iounmap(qpti->qregs,				     qpti->sdev->reg_addrs[0].reg_size);			if (qpti->is_pti)				sbus_iounmap(qpti->sreg, sizeof(unsigned char));		fail_unlink:			qpti_chain_del(qpti);			scsi_unregister(qpti->qhost);		}	}	if (nqptis)		printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",		       nqptis, nqptis_in_use);	qptis_running = nqptis_in_use;	return nqptis;}int qlogicpti_release(struct Scsi_Host *host){	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;	/* Remove visibility from IRQ handlers. */	qpti_chain_del(qpti);	/* Shut up the card. */	sbus_writew(0, qpti->qregs + SBUS_CTRL);	/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */	free_irq(qpti->irq, qpti);#define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)	sbus_free_consistent(qpti->sdev,			     QSIZE(RES_QUEUE_LEN),			     qpti->res_cpu, qpti->res_dvma);	sbus_free_consistent(qpti->sdev,			     QSIZE(QLOGICPTI_REQ_QUEUE_LEN),			     qpti->req_cpu, qpti->req_dvma);#undef QSIZE	sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);	if (qpti->is_pti)		sbus_iounmap(qpti->sreg, sizeof(unsigned char));	return 0;}const char *qlogicpti_info(struct Scsi_Host *host){	static char buf[80];	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;	sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %lx",		__irq_itoa(qpti->qhost->irq), qpti->qregs);	return buf;}/* I am a certified frobtronicist. */static inline void marker_frob(struct Command_Entry *cmd){	struct Marker_Entry *marker = (struct Marker_Entry *) cmd;	memset(marker, 0, sizeof(struct Marker_Entry));	marker->hdr.entry_cnt = 1;	marker->hdr.entry_type = ENTRY_MARKER;	marker->modifier = SYNC_ALL;	marker->rsvd = 0;}static inline void cmd_frob(struct Command_Entry *cmd, Scsi_Cmnd *Cmnd,			    struct qlogicpti *qpti){	memset(cmd, 0, sizeof(struct Command_Entry));	cmd->hdr.entry_cnt = 1;	cmd->hdr.entry_type = ENTRY_COMMAND;	cmd->target_id = Cmnd->target;	cmd->target_lun = Cmnd->lun;	cmd->cdb_length = Cmnd->cmd_len;	cmd->control_flags = 0;	if (Cmnd->device->tagged_supported) {		if (qpti->cmd_count[Cmnd->target] == 0)			qpti->tag_ages[Cmnd->target] = jiffies;		if ((jiffies - qpti->tag_ages[Cmnd->target]) > (5*HZ)) {			cmd->control_flags = CFLAG_ORDERED_TAG;			qpti->tag_ages[Cmnd->target] = jiffies;		} else			cmd->control_flags = CFLAG_SIMPLE_TAG;	}	if ((Cmnd->cmnd[0] == WRITE_6) ||	    (Cmnd->cmnd[0] == WRITE_10) ||	    (Cmnd->cmnd[0] == WRITE_12))		cmd->control_flags |= CFLAG_WRITE;	else		cmd->control_flags |= CFLAG_READ;	cmd->time_out = 30;	memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);}

⌨️ 快捷键说明

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