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

📄 sym_glue.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
#if 0	switch (cp->cdb_buf[0]) {	case 0x0A: case 0x2A: case 0xAA:		panic("XXXXXXXXXXXXX WRITE NOT YET ALLOWED XXXXXXXXXXXXXX\n");		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, cmd);	return 0;}/* *  timer daemon. * *  Misused to keep the driver running when *  interrupts are not configured correctly. */static void sym_timer(struct sym_hcb *np){	unsigned long thistime = jiffies;	/*	 *  Restart the timer.	 */	np->s.timer.expires = thistime + SYM_CONF_TIMER_INTERVAL;	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 (time_before_eq(np->s.settle_time, thistime)) {			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}/* *  PCI BUS error handler. */void sym_log_bus_error(struct sym_hcb *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);	}}/* * queuecommand method.  Entered with the host adapter lock held and * interrupts disabled. */static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,					void (*done)(struct scsi_cmnd *)){	struct sym_hcb *np = SYM_SOFTC_PTR(cmd);	struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd);	int sts = 0;	cmd->scsi_done     = done;	memset(ucp, 0, sizeof(*ucp));	/*	 *  Shorten our settle_time if needed for 	 *  this command not to time out.	 */	if (np->s.settle_time_valid && cmd->timeout_per_command) {		unsigned long tlimit = jiffies + cmd->timeout_per_command;		tlimit -= SYM_CONF_TIMER_INTERVAL*2;		if (time_after(np->s.settle_time, tlimit)) {			np->s.settle_time = tlimit;		}	}	if (np->s.settle_time_valid)		return SCSI_MLQUEUE_HOST_BUSY;	sts = sym_queue_command(np, cmd);	if (sts)		return SCSI_MLQUEUE_HOST_BUSY;	return 0;}/* *  Linux entry point of the interrupt handler. */static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs){	unsigned long flags;	struct sym_hcb *np = (struct sym_hcb *)dev_id;	if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("[");	spin_lock_irqsave(np->s.host->host_lock, flags);	sym_interrupt(np);	spin_unlock_irqrestore(np->s.host->host_lock, flags);	if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("]\n");	return IRQ_HANDLED;}/* *  Linux entry point of the timer handler */static void sym53c8xx_timer(unsigned long npref){	struct sym_hcb *np = (struct sym_hcb *)npref;	unsigned long flags;	spin_lock_irqsave(np->s.host->host_lock, flags);	sym_timer(np);	spin_unlock_irqrestore(np->s.host->host_lock, flags);}/* *  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(struct scsi_cmnd *cmd, int timed_out){	struct sym_eh_wait *ep = SYM_UCMD_PTR(cmd)->eh_wait;	if (!ep)		return;	/* Try to avoid a race here (not 100% safe) */	if (!timed_out) {		ep->timed_out = 0;		if (ep->to_do == SYM_EH_DO_WAIT && !del_timer(&ep->timer))			return;	}	/* Revert everything */	SYM_UCMD_PTR(cmd)->eh_wait = NULL;	cmd->scsi_done = ep->old_done;	/* Wake up the eh thread if it wants to sleep */	if (ep->to_do == SYM_EH_DO_WAIT)		complete(&ep->done);}/* *  scsi_done() alias when error recovery is in progress.  */static void sym_eh_done(struct scsi_cmnd *cmd) { __sym_eh_done(cmd, 0); }/* *  Some timeout handler to avoid waiting too long. */static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); }/* *  Generic method for our eh processing. *  The 'op' argument tells what we have to do. */static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd){	struct sym_hcb *np = SYM_SOFTC_PTR(cmd);	SYM_QUEHEAD *qp;	int to_do = SYM_EH_DO_IGNORE;	int sts = -1;	struct sym_eh_wait eh, *ep = &eh;	dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname);	/* This one is queued in some place -> to wait for completion */	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {		struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);		if (cp->cmd == cmd) {			to_do = SYM_EH_DO_WAIT;			goto prepare;		}	}prepare:	/* Prepare stuff to either ignore, complete or wait for completion */	switch(to_do) {	default:	case SYM_EH_DO_IGNORE:		break;	case SYM_EH_DO_WAIT:		init_completion(&ep->done);		/* fall through */	case SYM_EH_DO_COMPLETE:		ep->old_done = cmd->scsi_done;		cmd->scsi_done = sym_eh_done;		SYM_UCMD_PTR(cmd)->eh_wait = ep;	}	/* Try to proceed the operation we have been asked for */	sts = -1;	switch(op) {	case SYM_EH_ABORT:		sts = sym_abort_scsiio(np, cmd, 1);		break;	case SYM_EH_DEVICE_RESET:		sts = sym_reset_scsi_target(np, cmd->device->id);		break;	case SYM_EH_BUS_RESET:		sym_reset_scsi_bus(np, 1);		sts = 0;		break;	case SYM_EH_HOST_RESET:		sym_reset_scsi_bus(np, 0);		sym_start_up (np, 1);		sts = 0;		break;	default:		break;	}	/* On error, restore everything and cross fingers :) */	if (sts) {		SYM_UCMD_PTR(cmd)->eh_wait = NULL;		cmd->scsi_done = ep->old_done;		to_do = SYM_EH_DO_IGNORE;	}	ep->to_do = to_do;	/* Complete the command with locks held as required by the driver */	if (to_do == SYM_EH_DO_COMPLETE)		sym_xpt_done2(np, cmd, DID_ABORT);	/* Wait for completion with locks released, as required by kernel */	if (to_do == SYM_EH_DO_WAIT) {		init_timer(&ep->timer);		ep->timer.expires = jiffies + (5*HZ);		ep->timer.function = sym_eh_timeout;		ep->timer.data = (u_long)cmd;		ep->timed_out = 1;	/* Be pessimistic for once :) */		add_timer(&ep->timer);		spin_unlock_irq(np->s.host->host_lock);		wait_for_completion(&ep->done);		spin_lock_irq(np->s.host->host_lock);		if (ep->timed_out)			sts = -2;	}	dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,			sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");	return sts ? SCSI_FAILED : SCSI_SUCCESS;}/* * Error handlers called from the eh thread (one thread per HBA). */static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd){	int rc;	spin_lock_irq(cmd->device->host->host_lock);	rc = sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd);	spin_unlock_irq(cmd->device->host->host_lock);	return rc;}static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd){	int rc;	spin_lock_irq(cmd->device->host->host_lock);	rc = sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd);	spin_unlock_irq(cmd->device->host->host_lock);	return rc;}static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd){	int rc;	spin_lock_irq(cmd->device->host->host_lock);	rc = sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd);	spin_unlock_irq(cmd->device->host->host_lock);	return rc;}static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd){	int rc;	spin_lock_irq(cmd->device->host->host_lock);	rc = sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd);	spin_unlock_irq(cmd->device->host->host_lock);	return rc;}/* *  Tune device queuing depth, according to various limits. */static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags){	struct sym_lcb *lp = sym_lp(tp, lun);	u_short	oldtags;	if (!lp)		return;	oldtags = lp->s.reqtags;	if (reqtags > lp->s.scdev_depth)		reqtags = lp->s.scdev_depth;	lp->started_limit = reqtags ? reqtags : 2;	lp->started_max   = 1;	lp->s.reqtags     = reqtags;	if (reqtags != oldtags) {		dev_info(&tp->starget->dev,		         "tagged command queuing %s, command queue depth %d.\n",		          lp->s.reqtags ? "enabled" : "disabled", 		          lp->started_limit);	}}/* *  Linux select queue depths function */#define DEF_DEPTH	(sym_driver_setup.max_tag)#define ALL_TARGETS	-2#define NO_TARGET	-1#define ALL_LUNS	-2#define NO_LUN		-1static int device_queue_depth(struct sym_hcb *np, int target, int lun){	int c, h, t, u, v;	char *p = sym_driver_setup.tag_ctrl;	char *ep;	h = -1;	t = NO_TARGET;	u = NO_LUN;	while ((c = *p++) != 0) {		v = simple_strtoul(p, &ep, 0);		switch(c) {		case '/':			++h;			t = ALL_TARGETS;			u = ALL_LUNS;			break;		case 't':			if (t != target)				t = (target == v) ? v : NO_TARGET;			u = ALL_LUNS;			break;		case 'u':			if (u != lun)				u = (lun == v) ? v : NO_LUN;			break;		case 'q':			if (h == np->s.unit &&				(t == ALL_TARGETS || t == target) &&				(u == ALL_LUNS    || u == lun))				return v;			break;		case '-':			t = ALL_TARGETS;			u = ALL_LUNS;			break;		default:			break;		}		p = ep;	}	return DEF_DEPTH;}static int sym53c8xx_slave_alloc(struct scsi_device *sdev){	struct sym_hcb *np;	struct sym_tcb *tp;	if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN)		return -ENXIO;	np = sym_get_hcb(sdev->host);	tp = &np->target[sdev->id];	/*	 * Fail the device init if the device is flagged NOSCAN at BOOT in	 * the NVRAM.  This may speed up boot and maintain coherency with	 * BIOS device numbering.  Clearing the flag allows the user to	 * rescan skipped devices later.  We also return an error for	 * devices not flagged for SCAN LUNS in the NVRAM since some single	 * lun devices behave badly when asked for a non zero LUN.	 */	if ((tp->usrflags & SYM_SCAN_BOOT_DISABLED) ||	    ((tp->usrflags & SYM_SCAN_LUNS_DISABLED) && sdev->lun != 0)) {		tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;		return -ENXIO;	}	tp->starget = sdev->sdev_target;	return 0;}/* * Linux entry point for device queue sizing. */static int sym53c8xx_slave_configure(struct scsi_device *device){	struct sym_hcb *np = sym_get_hcb(device->host);	struct sym_tcb *tp = &np->target[device->id];	struct sym_lcb *lp;	int reqtags, depth_to_use;	/*	 *  Allocate the LCB if not yet.	 *  If it fail, we may well be in the sh*t. :)	 */	lp = sym_alloc_lcb(np, device->id, device->lun);	if (!lp)		return -ENOMEM;	/*	 *  Get user flags.	 */	lp->curr_flags = lp->user_flags;	/*	 *  Select queue depth from driver setup.	 *  Donnot use more than configured by user.	 *  Use at least 2.	 *  Donnot use more than our maximum.	 */	reqtags = device_queue_depth(np, device->id, device->lun);	if (reqtags > tp->usrtags)		reqtags = tp->usrtags;	if (!device->tagged_supported)		reqtags = 0;#if 1 /* Avoid to locally queue commands for no good reasons */	if (reqtags > SYM_CONF_MAX_TAG)		reqtags = SYM_CONF_MAX_TAG;	depth_to_use = (reqtags ? reqtags : 2);#else	depth_to_use = (reqtags ? SYM_CONF_MAX_TAG : 2);#endif	scsi_adjust_queue_depth(device,				(device->tagged_supported ?				 MSG_SIMPLE_TAG : 0),				depth_to_use);	lp->s.scdev_depth = depth_to_use;	sym_tune_dev_queuing(tp, device->lun, reqtags);	if (!spi_initial_dv(device->sdev_target))		spi_dv_device(device);	return 0;}/* *  Linux entry point for info() function */static const char *sym53c8xx_info (struct Scsi_Host *host){	return SYM_DRIVER_NAME;}#ifdef SYM_LINUX_PROC_INFO_SUPPORT/* *  Proc file system stuff * *  A read operation returns adapter information. *  A write operation is a control command. *  The string is parsed in the driver code and the command is passed  *  to the sym_usercmd() function. */#ifdef SYM_LINUX_USER_COMMAND_SUPPORTstruct	sym_usrcmd {	u_long	target;	u_long	lun;	u_long	data;	u_long	cmd;};#define UC_SETSYNC      10#define UC_SETTAGS	11#define UC_SETDEBUG	12#define UC_SETWIDE	14#define UC_SETFLAG	15#define UC_SETVERBOSE	17#define UC_RESETDEV	18#define UC_CLEARDEV	19static void sym_exec_user_command (struct sym_hcb *np, struct sym_usrcmd *uc){

⌨️ 快捷键说明

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