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

📄 sym_glue.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	drv_status  = 0;	cam_status  = DID_OK;	scsi_status = cp->ssss_status;	if (cp->host_flags & HF_SENSE) {		scsi_status = cp->sv_scsi_status;		resid = cp->sv_resid;		if (sym_verbose && cp->sv_xerr_status)			sym_print_xerr(cp, cp->sv_xerr_status);		if (cp->host_status == HS_COMPLETE &&		    cp->ssss_status == S_GOOD &&		    cp->xerr_status == 0) {			cam_status = sym_xerr_cam_status(DID_OK,							 cp->sv_xerr_status);			drv_status = DRIVER_SENSE;			/*			 *  Bounce back the sense data to user.			 */			bzero(&csio->sense_buffer, sizeof(csio->sense_buffer));			bcopy(cp->sns_bbuf, csio->sense_buffer,			      MIN(sizeof(csio->sense_buffer),SYM_SNS_BBUF_LEN));#if 0			/*			 *  If the device reports a UNIT ATTENTION condition 			 *  due to a RESET condition, we should consider all 			 *  disconnect CCBs for this unit as aborted.			 */			if (1) {				u_char *p;				p  = (u_char *) csio->sense_data;				if (p[0]==0x70 && p[2]==0x6 && p[12]==0x29)					sym_clear_tasks(np, DID_ABORT,							cp->target,cp->lun, -1);			}#endif		}		else			cam_status = DID_ERROR;	}	else if (cp->host_status == HS_COMPLETE) 	/* Bad SCSI status */		cam_status = DID_OK;	else if (cp->host_status == HS_SEL_TIMEOUT)	/* Selection timeout */		cam_status = DID_NO_CONNECT;	else if (cp->host_status == HS_UNEXPECTED)	/* Unexpected BUS FREE*/		cam_status = DID_ERROR;	else {						/* Extended error */		if (sym_verbose) {			PRINT_ADDR(cp);			printf ("COMMAND FAILED (%x %x %x).\n",				cp->host_status, cp->ssss_status,				cp->xerr_status);		}		/*		 *  Set the most appropriate value for CAM status.		 */		cam_status = sym_xerr_cam_status(DID_ERROR, cp->xerr_status);	}#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,99)	csio->resid = resid;#endif	csio->result = (drv_status << 24) + (cam_status << 16) + scsi_status;}/* *  Called on successfull INQUIRY response. */void sym_sniff_inquiry(hcb_p np, Scsi_Cmnd *cmd, int resid){	int retv;	if (!cmd || cmd->use_sg)		return;	sync_scsi_data(np, cmd);	retv = __sym_sniff_inquiry(np, cmd->target, cmd->lun,				   (u_char *) cmd->request_buffer,				   cmd->request_bufflen - resid);	if (retv < 0)		return;	else if (retv)		sym_update_trans_settings(np, &np->target[cmd->target]);}/* *  Build the scatter/gather array for an I/O. */static int sym_scatter_no_sglist(hcb_p np, ccb_p cp, Scsi_Cmnd *cmd){	struct sym_tblmove *data = &cp->phys.data[SYM_CONF_MAX_SG-1];	int segment;	cp->data_len = cmd->request_bufflen;	if (cmd->request_bufflen) {		bus_addr_t baddr = map_scsi_single_data(np, cmd);		if (baddr) {			sym_build_sge(np, data, baddr, cmd->request_bufflen);			segment = 1;		}		else			segment = -2;	}	else		segment = 0;	return segment;}static int sym_scatter(hcb_p np, ccb_p cp, Scsi_Cmnd *cmd){	int segment;	int use_sg = (int) cmd->use_sg;	cp->data_len = 0;	if (!use_sg)		segment = sym_scatter_no_sglist(np, cp, cmd);	else if (use_sg > SYM_CONF_MAX_SG)		segment = -1;	else if ((use_sg = map_scsi_sg_data(np, cmd)) > 0) {		struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;		struct sym_tblmove *data;		data = &cp->phys.data[SYM_CONF_MAX_SG - use_sg];		for (segment = 0; segment < use_sg; segment++) {			bus_addr_t baddr = bus_sg_dma_address(&scatter[segment]);			unsigned int len = bus_sg_dma_len(&scatter[segment]);			sym_build_sge(np, &data[segment], baddr, len);			cp->data_len += len;		}	}	else		segment = -2;	return segment;}/* *  Queue a SCSI command. */static int sym_queue_command(hcb_p np, Scsi_Cmnd *ccb){/*	Scsi_Device        *device    = ccb->device; */	tcb_p	tp;	lcb_p	lp;	ccb_p	cp;	int	order;	/*	 *  Minimal checkings, so that we will not 	 *  go outside our tables.	 */	if (ccb->target == np->myaddr ||	    ccb->target >= SYM_CONF_MAX_TARGET ||	    ccb->lun    >= SYM_CONF_MAX_LUN) {		sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE);		return 0;        }	/*	 *  Retreive the target descriptor.	 */	tp = &np->target[ccb->target];	/*	 *  Complete the 1st INQUIRY command with error 	 *  condition if the device is flagged NOSCAN 	 *  at BOOT in the NVRAM. This may speed up 	 *  the boot and maintain coherency with BIOS 	 *  device numbering. Clearing the flag allows 	 *  user to rescan skipped devices later.	 *  We also return error for devices not flagged 	 *  for SCAN LUNS in the NVRAM since some mono-lun 	 *  devices behave badly when asked for some non 	 *  zero LUN. Btw, this is an absolute hack.:-)	 */	if (ccb->cmnd[0] == 0x12 || ccb->cmnd[0] == 0x0) {		if ((tp->usrflags & SYM_SCAN_BOOT_DISABLED) ||		    ((tp->usrflags & SYM_SCAN_LUNS_DISABLED) && 		     ccb->lun != 0)) {			tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;			sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE);			return 0;		}	}	/*	 *  Select tagged/untagged.	 */	lp = sym_lp(np, tp, ccb->lun);	order = (lp && lp->s.reqtags) ? M_SIMPLE_TAG : 0;	/*	 *  Queue the SCSI IO.	 */	cp = sym_get_ccb(np, ccb->target, ccb->lun, order);	if (!cp)		return 1;	/* Means resource shortage */	(void) sym_queue_scsiio(np, ccb, cp);	return 0;}/* *  Setup buffers and pointers that address the CDB. */static int __inline sym_setup_cdb(hcb_p np, Scsi_Cmnd *ccb, ccb_p cp){	u32	cmd_ba;	int	cmd_len;	/*	 *  CDB is 16 bytes max.	 */	if (ccb->cmd_len > sizeof(cp->cdb_buf)) {		sym_set_cam_status(cp->cam_ccb, CAM_REQ_INVALID);		return -1;	}	bcopy(ccb->cmnd, cp->cdb_buf, ccb->cmd_len);	cmd_ba  = CCB_BA (cp, cdb_buf[0]);	cmd_len = ccb->cmd_len;	cp->phys.cmd.addr	= cpu_to_scr(cmd_ba);	cp->phys.cmd.size	= cpu_to_scr(cmd_len);	return 0;}/* *  Setup pointers that address the data and start the I/O. */int sym_setup_data_and_start(hcb_p np, Scsi_Cmnd *csio, ccb_p cp){	int dir;	tcb_p tp = &np->target[cp->target];	lcb_p lp = sym_lp(np, tp, cp->lun);	/*	 *  Build the CDB.	 */	if (sym_setup_cdb(np, csio, cp))		goto out_abort;	/*	 *  No direction means no data.	 */	dir = scsi_data_direction(csio);	if (dir != SCSI_DATA_NONE) {		cp->segments = sym_scatter (np, cp, csio);		if (cp->segments < 0) {			if (cp->segments == -2)				sym_set_cam_status(csio, CAM_RESRC_UNAVAIL);			else				sym_set_cam_status(csio, CAM_REQ_TOO_BIG);			goto out_abort;		}	}	else {		cp->data_len = 0;		cp->segments = 0;	}	/*	 *  Set data pointers.	 */	sym_setup_data_pointers(np, cp, dir);	/*	 *  When `#ifed 1', the code below makes the driver 	 *  panic on the first attempt to write to a SCSI device.	 *  It is the first test we want to do after a driver 	 *  change that does not seem obviously safe. :)	 */#if 0	switch (cp->cdb_buf[0]) {	case 0x0A: case 0x2A: case 0xAA:		panic("XXXXXXXXXXXXX WRITE NOT YET ALLOWED XXXXXXXXXXXXXX\n");		MDELAY(10000);		break;	default:		break;	}#endif	/*	 *	activate this job.	 */	if (lp)		sym_start_next_ccbs(np, lp, 2);	else		sym_put_start_queue(np, cp);	return 0;out_abort:	sym_free_ccb(np, cp);	sym_xpt_done(np, csio);	return 0;}/* *  timer daemon. * *  Misused to keep the driver running when *  interrupts are not configured correctly. */static void sym_timer (hcb_p np){	u_long	thistime = ktime_get(0);#if LINUX_VERSION_CODE < LinuxVersionCode(2, 4, 0)	/*	 *  If release process in progress, let's go	 *  Set the release stage from 1 to 2 to synchronize	 *  with the release process.	 */	if (np->s.release_stage) {		if (np->s.release_stage == 1)			np->s.release_stage = 2;		return;	}#endif	/*	 *  Restart the timer.	 */#ifdef SYM_CONF_PCIQ_BROKEN_INTR	np->s.timer.expires = ktime_get((HZ+99)/100);#else	np->s.timer.expires = ktime_get(SYM_CONF_TIMER_INTERVAL);#endif	add_timer(&np->s.timer);	/*	 *  If we are resetting the ncr, wait for settle_time before 	 *  clearing it. Then command processing will be resumed.	 */	if (np->s.settle_time_valid) {		if (ktime_dif(np->s.settle_time, thistime) <= 0){			if (sym_verbose >= 2 )				printk("%s: command processing resumed\n",				       sym_name(np));			np->s.settle_time_valid = 0;		}		return;	}	/*	 *	Nothing to do for now, but that may come.	 */	if (np->s.lasttime + 4*HZ < thistime) {		np->s.lasttime = thistime;	}#ifdef SYM_CONF_PCIQ_MAY_MISS_COMPLETIONS	/*	 *  Some way-broken PCI bridges may lead to 	 *  completions being lost when the clearing 	 *  of the INTFLY flag by the CPU occurs 	 *  concurrently with the chip raising this flag.	 *  If this ever happen, lost completions will 	 * be reaped here.	 */	sym_wakeup_done(np);#endif#ifdef SYM_CONF_PCIQ_BROKEN_INTR	if (INB(nc_istat) & (INTF|SIP|DIP)) {		/*		**	Process pending interrupts.		*/		if (DEBUG_FLAGS & DEBUG_TINY) printk ("{");		sym_interrupt(np);		if (DEBUG_FLAGS & DEBUG_TINY) printk ("}");	}#endif /* SYM_CONF_PCIQ_BROKEN_INTR */}/* *  PCI BUS error handler. */void sym_log_bus_error(hcb_p np){	u_short pci_sts;	pci_read_config_word(np->s.device, PCI_STATUS, &pci_sts);	if (pci_sts & 0xf900) {		pci_write_config_word(np->s.device, PCI_STATUS,		                         pci_sts);		printf("%s: PCI STATUS = 0x%04x\n",			sym_name(np), pci_sts & 0xf900);	}}/* *  Requeue awaiting commands. */static void sym_requeue_awaiting_cmds(hcb_p np){	Scsi_Cmnd *cmd;	ucmd_p ucp = SYM_UCMD_PTR(cmd);	SYM_QUEHEAD tmp_cmdq;	int sts;	sym_que_move(&np->s.wait_cmdq, &tmp_cmdq);	while ((ucp = (ucmd_p) sym_remque_head(&tmp_cmdq)) != 0) {		sym_insque_tail(&ucp->link_cmdq, &np->s.busy_cmdq);		cmd = SYM_SCMD_PTR(ucp);		sts = sym_queue_command(np, cmd);		if (sts) {			sym_remque(&ucp->link_cmdq);			sym_insque_head(&ucp->link_cmdq, &np->s.wait_cmdq);		}	}}/* *  Linux entry point of the queuecommand() function */int sym53c8xx_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)){	hcb_p  np  = SYM_SOFTC_PTR(cmd);	ucmd_p ucp = SYM_UCMD_PTR(cmd);	u_long flags;	int sts = 0;	cmd->scsi_done     = done;	cmd->host_scribble = NULL;	memset(ucp, 0, sizeof(*ucp));	SYM_LOCK_HCB(np, flags);	/*	 *  Shorten our settle_time if needed for 	 *  this command not to time out.	 */	if (np->s.settle_time_valid && cmd->timeout_per_command) {		u_long tlimit = ktime_get(cmd->timeout_per_command);		tlimit = ktime_sub(tlimit, SYM_CONF_TIMER_INTERVAL*2);		if (ktime_dif(np->s.settle_time, tlimit) > 0) {			np->s.settle_time = tlimit;		}	}	if (np->s.settle_time_valid || !sym_que_empty(&np->s.wait_cmdq)) {		sym_insque_tail(&ucp->link_cmdq, &np->s.wait_cmdq);		goto out;	}	sym_insque_tail(&ucp->link_cmdq, &np->s.busy_cmdq);	sts = sym_queue_command(np, cmd);	if (sts) {		sym_remque(&ucp->link_cmdq);		sym_insque_tail(&ucp->link_cmdq, &np->s.wait_cmdq);	}out:	SYM_UNLOCK_HCB(np, flags);	return 0;}/* *  Linux entry point of the interrupt handler. */static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs){	unsigned long flags;	unsigned long flags1;	hcb_p np = (hcb_p) dev_id;	if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("[");	SYM_LOCK_SCSI(np, flags1);	SYM_LOCK_HCB(np, flags);	sym_interrupt(np);	if (!sym_que_empty(&np->s.wait_cmdq) && !np->s.settle_time_valid)		sym_requeue_awaiting_cmds(np);	SYM_UNLOCK_HCB(np, flags);	SYM_UNLOCK_SCSI(np, flags1);	if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("]\n");}/* *  Linux entry point of the timer handler */static void sym53c8xx_timer(unsigned long npref){	hcb_p np = (hcb_p) npref;	unsigned long flags;	unsigned long flags1;	SYM_LOCK_SCSI(np, flags1);	SYM_LOCK_HCB(np, flags);	sym_timer(np);	if (!sym_que_empty(&np->s.wait_cmdq) && !np->s.settle_time_valid)		sym_requeue_awaiting_cmds(np);	SYM_UNLOCK_HCB(np, flags);	SYM_UNLOCK_SCSI(np, flags1);}/* *  What the eh thread wants us to perform. */#define SYM_EH_ABORT		0#define SYM_EH_DEVICE_RESET	1#define SYM_EH_BUS_RESET	2#define SYM_EH_HOST_RESET	3/* *  What we will do regarding the involved SCSI command. */#define SYM_EH_DO_IGNORE	0#define SYM_EH_DO_COMPLETE	1#define SYM_EH_DO_WAIT		2/* *  Our general completion handler. */static void __sym_eh_done(Scsi_Cmnd *cmd, int timed_out){	struct sym_eh_wait *ep = SYM_UCMD_PTR(cmd)->eh_wait;

⌨️ 快捷键说明

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