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

📄 aic79xx_osm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
			break;		case '}':			if (targ != -1)				targ = -1;			else if (instance != -1)				instance = -1;			opt_arg++;			break;		case ',':		case '.':			if (instance == -1)				done = TRUE;			else if (targ >= 0)				targ++;			else if (instance >= 0)				instance++;			opt_arg++;			break;		case '\0':			done = TRUE;			break;		default:			tok_end = end;			for (i = 0; tok_list[i]; i++) {				tok_end2 = strchr(opt_arg, tok_list[i]);				if ((tok_end2) && (tok_end2 < tok_end))					tok_end = tok_end2;			}			callback(callback_arg, instance, targ,				 simple_strtol(opt_arg, NULL, 0));			opt_arg = tok_end;			break;		}	}	return (opt_arg);}/* * Handle Linux boot parameters. This routine allows for assigning a value * to a parameter with a ':' between the parameter and the value. * ie. aic79xx=stpwlev:1,extended */static intaic79xx_setup(char *s){	int	i, n;	char   *p;	char   *end;	static struct {		const char *name;		uint32_t *flag;	} options[] = {		{ "extended", &aic79xx_extended },		{ "no_reset", &aic79xx_no_reset },		{ "verbose", &aic79xx_verbose },		{ "allow_memio", &aic79xx_allow_memio},#ifdef AHD_DEBUG		{ "debug", &ahd_debug },#endif		{ "reverse_scan", &aic79xx_reverse_scan },		{ "periodic_otag", &aic79xx_periodic_otag },		{ "pci_parity", &aic79xx_pci_parity },		{ "seltime", &aic79xx_seltime },		{ "tag_info", NULL },		{ "global_tag_depth", NULL},		{ "slewrate", NULL },		{ "precomp", NULL },		{ "amplitude", NULL },	};	end = strchr(s, '\0');	/*	 * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS	 * will never be 0 in this case.	 */      	n = 0;  	while ((p = strsep(&s, ",.")) != NULL) {		if (*p == '\0')			continue;		for (i = 0; i < NUM_ELEMENTS(options); i++) {			n = strlen(options[i].name);			if (strncmp(options[i].name, p, n) == 0)				break;		}		if (i == NUM_ELEMENTS(options))			continue;		if (strncmp(p, "global_tag_depth", n) == 0) {			ahd_linux_setup_tag_info_global(p + n);		} else if (strncmp(p, "tag_info", n) == 0) {			s = ahd_parse_brace_option("tag_info", p + n, end,			    2, ahd_linux_setup_tag_info, 0);		} else if (strncmp(p, "slewrate", n) == 0) {			s = ahd_parse_brace_option("slewrate",			    p + n, end, 1, ahd_linux_setup_iocell_info,			    AIC79XX_SLEWRATE_INDEX);		} else if (strncmp(p, "precomp", n) == 0) {			s = ahd_parse_brace_option("precomp",			    p + n, end, 1, ahd_linux_setup_iocell_info,			    AIC79XX_PRECOMP_INDEX);		} else if (strncmp(p, "amplitude", n) == 0) {			s = ahd_parse_brace_option("amplitude",			    p + n, end, 1, ahd_linux_setup_iocell_info,			    AIC79XX_AMPLITUDE_INDEX);		} else if (p[n] == ':') {			*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);		} else if (!strncmp(p, "verbose", n)) {			*(options[i].flag) = 1;		} else {			*(options[i].flag) ^= 0xFFFFFFFF;		}	}	return 1;}__setup("aic79xx=", aic79xx_setup);uint32_t aic79xx_verbose;intahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *template){	char	buf[80];	struct	Scsi_Host *host;	char	*new_name;	u_long	s;	template->name = ahd->description;	host = scsi_host_alloc(template, sizeof(struct ahd_softc *));	if (host == NULL)		return (ENOMEM);	*((struct ahd_softc **)host->hostdata) = ahd;	ahd_lock(ahd, &s);	ahd->platform_data->host = host;	host->can_queue = AHD_MAX_QUEUE;	host->cmd_per_lun = 2;	host->sg_tablesize = AHD_NSEG;	host->this_id = ahd->our_id;	host->irq = ahd->platform_data->irq;	host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8;	host->max_lun = AHD_NUM_LUNS;	host->max_channel = 0;	host->sg_tablesize = AHD_NSEG;	ahd_set_unit(ahd, ahd_linux_unit++);	sprintf(buf, "scsi%d", host->host_no);	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);	if (new_name != NULL) {		strcpy(new_name, buf);		ahd_set_name(ahd, new_name);	}	host->unique_id = ahd->unit;	ahd_linux_initialize_scsi_bus(ahd);	ahd_intr_enable(ahd, TRUE);	ahd_unlock(ahd, &s);	host->transportt = ahd_linux_transport_template;	scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */	scsi_scan_host(host);	return (0);}uint64_tahd_linux_get_memsize(void){	struct sysinfo si;	si_meminfo(&si);	return ((uint64_t)si.totalram << PAGE_SHIFT);}/* * Place the SCSI bus into a known state by either resetting it, * or forcing transfer negotiations on the next command to any * target. */static voidahd_linux_initialize_scsi_bus(struct ahd_softc *ahd){	u_int target_id;	u_int numtarg;	target_id = 0;	numtarg = 0;	if (aic79xx_no_reset != 0)		ahd->flags &= ~AHD_RESET_BUS_A;	if ((ahd->flags & AHD_RESET_BUS_A) != 0)		ahd_reset_channel(ahd, 'A', /*initiate_reset*/TRUE);	else		numtarg = (ahd->features & AHD_WIDE) ? 16 : 8;	/*	 * Force negotiation to async for all targets that	 * will not see an initial bus reset.	 */	for (; target_id < numtarg; target_id++) {		struct ahd_devinfo devinfo;		struct ahd_initiator_tinfo *tinfo;		struct ahd_tmode_tstate *tstate;		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,					    target_id, &tstate);		ahd_compile_devinfo(&devinfo, ahd->our_id, target_id,				    CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR);		ahd_update_neg_request(ahd, &devinfo, tstate,				       tinfo, AHD_NEG_ALWAYS);	}	/* Give the bus some time to recover */	if ((ahd->flags & AHD_RESET_BUS_A) != 0) {		ahd_freeze_simq(ahd);		init_timer(&ahd->platform_data->reset_timer);		ahd->platform_data->reset_timer.data = (u_long)ahd;		ahd->platform_data->reset_timer.expires =		    jiffies + (AIC79XX_RESET_DELAY * HZ)/1000;		ahd->platform_data->reset_timer.function =		    (ahd_linux_callback_t *)ahd_release_simq;		add_timer(&ahd->platform_data->reset_timer);	}}intahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg){	ahd->platform_data =	    malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT);	if (ahd->platform_data == NULL)		return (ENOMEM);	memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));	ahd->platform_data->irq = AHD_LINUX_NOIRQ;	ahd_lockinit(ahd);	init_MUTEX_LOCKED(&ahd->platform_data->eh_sem);	ahd->seltime = (aic79xx_seltime & 0x3) << 4;	return (0);}voidahd_platform_free(struct ahd_softc *ahd){	struct scsi_target *starget;	int i, j;	if (ahd->platform_data != NULL) {		/* destroy all of the device and target objects */		for (i = 0; i < AHD_NUM_TARGETS; i++) {			starget = ahd->platform_data->starget[i];			if (starget != NULL) {				for (j = 0; j < AHD_NUM_LUNS; j++) {					struct ahd_linux_target *targ =						scsi_transport_target_data(starget);					if (targ->sdev[j] == NULL)						continue;					targ->sdev[j] = NULL;				}				ahd->platform_data->starget[i] = NULL;			}		}		if (ahd->platform_data->irq != AHD_LINUX_NOIRQ)			free_irq(ahd->platform_data->irq, ahd);		if (ahd->tags[0] == BUS_SPACE_PIO		 && ahd->bshs[0].ioport != 0)			release_region(ahd->bshs[0].ioport, 256);		if (ahd->tags[1] == BUS_SPACE_PIO		 && ahd->bshs[1].ioport != 0)			release_region(ahd->bshs[1].ioport, 256);		if (ahd->tags[0] == BUS_SPACE_MEMIO		 && ahd->bshs[0].maddr != NULL) {			iounmap(ahd->bshs[0].maddr);			release_mem_region(ahd->platform_data->mem_busaddr,					   0x1000);		}		if (ahd->platform_data->host)			scsi_host_put(ahd->platform_data->host);		free(ahd->platform_data, M_DEVBUF);	}}voidahd_platform_init(struct ahd_softc *ahd){	/*	 * Lookup and commit any modified IO Cell options.	 */	if (ahd->unit < NUM_ELEMENTS(aic79xx_iocell_info)) {		struct ahd_linux_iocell_opts *iocell_opts;		iocell_opts = &aic79xx_iocell_info[ahd->unit];		if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP)			AHD_SET_PRECOMP(ahd, iocell_opts->precomp);		if (iocell_opts->slewrate != AIC79XX_DEFAULT_SLEWRATE)			AHD_SET_SLEWRATE(ahd, iocell_opts->slewrate);		if (iocell_opts->amplitude != AIC79XX_DEFAULT_AMPLITUDE)			AHD_SET_AMPLITUDE(ahd, iocell_opts->amplitude);	}}voidahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb){	ahd_platform_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb),				SCB_GET_CHANNEL(ahd, scb),				SCB_GET_LUN(scb), SCB_LIST_NULL,				ROLE_UNKNOWN, CAM_REQUEUE_REQ);}voidahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,		      ahd_queue_alg alg){	struct scsi_target *starget;	struct ahd_linux_target *targ;	struct ahd_linux_device *dev;	struct scsi_device *sdev;	int was_queuing;	int now_queuing;	starget = ahd->platform_data->starget[devinfo->target];	targ = scsi_transport_target_data(starget);	BUG_ON(targ == NULL);	sdev = targ->sdev[devinfo->lun];	if (sdev == NULL)		return;	dev = scsi_transport_device_data(sdev);	if (dev == NULL)		return;	was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED);	switch (alg) {	default:	case AHD_QUEUE_NONE:		now_queuing = 0;		break; 	case AHD_QUEUE_BASIC:		now_queuing = AHD_DEV_Q_BASIC;		break;	case AHD_QUEUE_TAGGED:		now_queuing = AHD_DEV_Q_TAGGED;		break;	}	if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0	 && (was_queuing != now_queuing)	 && (dev->active != 0)) {		dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY;		dev->qfrozen++;	}	dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG);	if (now_queuing) {		u_int usertags;		usertags = ahd_linux_user_tagdepth(ahd, devinfo);		if (!was_queuing) {			/*			 * Start out agressively and allow our			 * dynamic queue depth algorithm to take			 * care of the rest.			 */			dev->maxtags = usertags;			dev->openings = dev->maxtags - dev->active;		}		if (dev->maxtags == 0) {			/*			 * Queueing is disabled by the user.			 */			dev->openings = 1;		} else if (alg == AHD_QUEUE_TAGGED) {			dev->flags |= AHD_DEV_Q_TAGGED;			if (aic79xx_periodic_otag != 0)				dev->flags |= AHD_DEV_PERIODIC_OTAG;		} else			dev->flags |= AHD_DEV_Q_BASIC;	} else {		/* We can only have one opening. */		dev->maxtags = 0;		dev->openings =  1 - dev->active;	}	switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) {	case AHD_DEV_Q_BASIC:		scsi_adjust_queue_depth(sdev,					MSG_SIMPLE_TASK,					dev->openings + dev->active);		break;	case AHD_DEV_Q_TAGGED:		scsi_adjust_queue_depth(sdev,					MSG_ORDERED_TASK,					dev->openings + dev->active);		break;	default:		/*		 * We allow the OS to queue 2 untagged transactions to		 * us at any time even though we can only execute them		 * serially on the controller/device.  This should		 * remove some latency.		 */		scsi_adjust_queue_depth(sdev,					/*NON-TAGGED*/0,					/*queue depth*/2);		break;	}}intahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel,			int lun, u_int tag, role_t role, uint32_t status){	return 0;}static u_intahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo){	static int warned_user;	u_int tags;	tags = 0;	if ((ahd->user_discenable & devinfo->target_mask) != 0) {		if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) {			if (warned_user == 0) {				printf(KERN_WARNING"aic79xx: WARNING: Insufficient tag_info instances\n""aic79xx: for installed controllers.  Using defaults\n""aic79xx: Please update the aic79xx_tag_info array in\n""aic79xx: the aic79xx_osm.c source file.\n");				warned_user++;			}			tags = AHD_MAX_QUEUE;		} else {			adapter_tag_info_t *tag_info;			tag_info = &aic79xx_tag_info[ahd->unit];			tags = tag_info->tag_commands[devinfo->target_offset];			if (tags > AHD_MAX_QUEUE)				tags = AHD_MAX_QUEUE;		}	}	return (tags);}/* * Determines the queue depth for a given device. */static voidahd_linux_device_queue_depth(struct scsi_device *sdev){	struct	ahd_devinfo devinfo;	u_int	tags;	struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata);	ahd_compile_devinfo(&devinfo,			    ahd->our_id,			    sdev->sdev_target->id, sdev->lun,			    sdev->sdev_target->channel == 0 ? 'A' : 'B',			    ROLE_INITIATOR);	tags = ahd_linux_user_tagdepth(ahd, &devinfo);	if (tags != 0 && sdev->tagged_supported != 0) {

⌨️ 快捷键说明

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