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

📄 aic7xxx_osm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (tok_end < end)		*tok_end = ',';	while (!done) {		switch (*opt_arg) {		case '{':			if (instance == -1) {				instance = 0;			} else {				if (depth > 1) {					if (targ == -1)						targ = 0;				} else {					printf("Malformed Option %s\n",					       opt_name);					done = TRUE;				}			}			opt_arg++;			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. aic7xxx=stpwlev:1,extended */static intaic7xxx_setup(char *s){	int	i, n;	char   *p;	char   *end;	static struct {		const char *name;		uint32_t *flag;	} options[] = {		{ "extended", &aic7xxx_extended },		{ "no_reset", &aic7xxx_no_reset },		{ "verbose", &aic7xxx_verbose },		{ "allow_memio", &aic7xxx_allow_memio},#ifdef AHC_DEBUG		{ "debug", &ahc_debug },#endif		{ "periodic_otag", &aic7xxx_periodic_otag },		{ "pci_parity", &aic7xxx_pci_parity },		{ "seltime", &aic7xxx_seltime },		{ "tag_info", NULL },		{ "global_tag_depth", NULL },		{ "dv", 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) {			ahc_linux_setup_tag_info_global(p + n);		} else if (strncmp(p, "tag_info", n) == 0) {			s = ahc_parse_brace_option("tag_info", p + n, end,			    2, ahc_linux_setup_tag_info, 0);		} else if (p[n] == ':') {			*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);		} else if (strncmp(p, "verbose", n) == 0) {			*(options[i].flag) = 1;		} else {			*(options[i].flag) ^= 0xFFFFFFFF;		}	}	return 1;}__setup("aic7xxx=", aic7xxx_setup);uint32_t aic7xxx_verbose;intahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *template){	char	 buf[80];	struct	 Scsi_Host *host;	char	*new_name;	u_long	 s;	template->name = ahc->description;	host = scsi_host_alloc(template, sizeof(struct ahc_softc *));	if (host == NULL)		return (ENOMEM);	*((struct ahc_softc **)host->hostdata) = ahc;	ahc_lock(ahc, &s);	ahc->platform_data->host = host;	host->can_queue = AHC_MAX_QUEUE;	host->cmd_per_lun = 2;	/* XXX No way to communicate the ID for multiple channels */	host->this_id = ahc->our_id;	host->irq = ahc->platform_data->irq;	host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8;	host->max_lun = AHC_NUM_LUNS;	host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;	host->sg_tablesize = AHC_NSEG;	ahc_set_unit(ahc, ahc_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);		ahc_set_name(ahc, new_name);	}	host->unique_id = ahc->unit;	ahc_linux_initialize_scsi_bus(ahc);	ahc_intr_enable(ahc, TRUE);	ahc_unlock(ahc, &s);	host->transportt = ahc_linux_transport_template;	scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */	scsi_scan_host(host);	return (0);}/* * Place the SCSI bus into a known state by either resetting it, * or forcing transfer negotiations on the next command to any * target. */voidahc_linux_initialize_scsi_bus(struct ahc_softc *ahc){	int i;	int numtarg;	i = 0;	numtarg = 0;	if (aic7xxx_no_reset != 0)		ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B);	if ((ahc->flags & AHC_RESET_BUS_A) != 0)		ahc_reset_channel(ahc, 'A', /*initiate_reset*/TRUE);	else		numtarg = (ahc->features & AHC_WIDE) ? 16 : 8;	if ((ahc->features & AHC_TWIN) != 0) {		if ((ahc->flags & AHC_RESET_BUS_B) != 0) {			ahc_reset_channel(ahc, 'B', /*initiate_reset*/TRUE);		} else {			if (numtarg == 0)				i = 8;			numtarg += 8;		}	}	/*	 * Force negotiation to async for all targets that	 * will not see an initial bus reset.	 */	for (; i < numtarg; i++) {		struct ahc_devinfo devinfo;		struct ahc_initiator_tinfo *tinfo;		struct ahc_tmode_tstate *tstate;		u_int our_id;		u_int target_id;		char channel;		channel = 'A';		our_id = ahc->our_id;		target_id = i;		if (i > 7 && (ahc->features & AHC_TWIN) != 0) {			channel = 'B';			our_id = ahc->our_id_b;			target_id = i % 8;		}		tinfo = ahc_fetch_transinfo(ahc, channel, our_id,					    target_id, &tstate);		ahc_compile_devinfo(&devinfo, our_id, target_id,				    CAM_LUN_WILDCARD, channel, ROLE_INITIATOR);		ahc_update_neg_request(ahc, &devinfo, tstate,				       tinfo, AHC_NEG_ALWAYS);	}	/* Give the bus some time to recover */	if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) {		ahc_linux_freeze_simq(ahc);		init_timer(&ahc->platform_data->reset_timer);		ahc->platform_data->reset_timer.data = (u_long)ahc;		ahc->platform_data->reset_timer.expires =		    jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000;		ahc->platform_data->reset_timer.function =		    ahc_linux_release_simq;		add_timer(&ahc->platform_data->reset_timer);	}}intahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg){	ahc->platform_data =	    malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT);	if (ahc->platform_data == NULL)		return (ENOMEM);	memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data));	ahc->platform_data->irq = AHC_LINUX_NOIRQ;	ahc_lockinit(ahc);	init_MUTEX_LOCKED(&ahc->platform_data->eh_sem);	ahc->seltime = (aic7xxx_seltime & 0x3) << 4;	ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4;	if (aic7xxx_pci_parity == 0)		ahc->flags |= AHC_DISABLE_PCI_PERR;	return (0);}voidahc_platform_free(struct ahc_softc *ahc){	struct scsi_target *starget;	int i, j;	if (ahc->platform_data != NULL) {		/* destroy all of the device and target objects */		for (i = 0; i < AHC_NUM_TARGETS; i++) {			starget = ahc->platform_data->starget[i];			if (starget != NULL) {				for (j = 0; j < AHC_NUM_LUNS; j++) {					struct ahc_linux_target *targ =						scsi_transport_target_data(starget);					if (targ->sdev[j] == NULL)						continue;					targ->sdev[j] = NULL;				}				ahc->platform_data->starget[i] = NULL; 			} 		}		if (ahc->platform_data->irq != AHC_LINUX_NOIRQ)			free_irq(ahc->platform_data->irq, ahc);		if (ahc->tag == BUS_SPACE_PIO		 && ahc->bsh.ioport != 0)			release_region(ahc->bsh.ioport, 256);		if (ahc->tag == BUS_SPACE_MEMIO		 && ahc->bsh.maddr != NULL) {			iounmap(ahc->bsh.maddr);			release_mem_region(ahc->platform_data->mem_busaddr,					   0x1000);		}		if (ahc->platform_data->host)			scsi_host_put(ahc->platform_data->host);		free(ahc->platform_data, M_DEVBUF);	}}voidahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb){	ahc_platform_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb),				SCB_GET_CHANNEL(ahc, scb),				SCB_GET_LUN(scb), SCB_LIST_NULL,				ROLE_UNKNOWN, CAM_REQUEUE_REQ);}voidahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,		      ahc_queue_alg alg){	struct scsi_target *starget;	struct ahc_linux_target *targ;	struct ahc_linux_device *dev;	struct scsi_device *sdev;	u_int target_offset;	int was_queuing;	int now_queuing;	target_offset = devinfo->target;	if (devinfo->channel != 'A')		target_offset += 8;	starget = ahc->platform_data->starget[target_offset];	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);	was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);	switch (alg) {	default:	case AHC_QUEUE_NONE:		now_queuing = 0;		break; 	case AHC_QUEUE_BASIC:		now_queuing = AHC_DEV_Q_BASIC;		break;	case AHC_QUEUE_TAGGED:		now_queuing = AHC_DEV_Q_TAGGED;		break;	}	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0	 && (was_queuing != now_queuing)	 && (dev->active != 0)) {		dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY;		dev->qfrozen++;	}	dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED|AHC_DEV_PERIODIC_OTAG);	if (now_queuing) {		u_int usertags;		usertags = ahc_linux_user_tagdepth(ahc, 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 == AHC_QUEUE_TAGGED) {			dev->flags |= AHC_DEV_Q_TAGGED;			if (aic7xxx_periodic_otag != 0)				dev->flags |= AHC_DEV_PERIODIC_OTAG;		} else			dev->flags |= AHC_DEV_Q_BASIC;	} else {		/* We can only have one opening. */		dev->maxtags = 0;		dev->openings =  1 - dev->active;	}	switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) {	case AHC_DEV_Q_BASIC:		scsi_set_tag_type(sdev, MSG_SIMPLE_TAG);		scsi_activate_tcq(sdev, dev->openings + dev->active);		break;	case AHC_DEV_Q_TAGGED:		scsi_set_tag_type(sdev, MSG_ORDERED_TAG);		scsi_activate_tcq(sdev, 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_deactivate_tcq(sdev, 2);		break;	}}intahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel,			int lun, u_int tag, role_t role, uint32_t status){	return 0;}static u_intahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo){	static int warned_user;	u_int tags;	tags = 0;	if ((ahc->user_discenable & devinfo->target_mask) != 0) {		if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) {			if (warned_user == 0) {				printf(KERN_WARNING"aic7xxx: WARNING: Insufficient tag_info instances\n""aic7xxx: for installed controllers. Using defaults\n""aic7xxx: Please update the aic7xxx_tag_info array in\n""aic7xxx: the aic7xxx_osm..c source file.\n");				warned_user++;			}			tags = AHC_MAX_QUEUE;		} else {			adapter_tag_info_t *tag_info;			tag_info = &aic7xxx_tag_info[ahc->unit];			tags = tag_info->tag_commands[devinfo->target_offset];			if (tags > AHC_MAX_QUEUE)				tags = AHC_MAX_QUEUE;		}	}	return (tags);}/* * Determines the queue depth for a given device. */static voidahc_linux_device_queue_depth(struct scsi_device *sdev){	struct	ahc_devinfo devinfo;	u_int	tags;	struct ahc_softc *ahc = *((struct ahc_softc **)sdev->host->hostdata);	ahc_compile_devinfo(&devinfo,			    sdev->sdev_target->channel == 0			  ? ahc->our_id : ahc->our_id_b,			    sdev->sdev_target->id, sdev->lun,			    sdev->sdev_target->channel == 0 ? 'A' : 'B',			    ROLE_INITIATOR);	tags = ahc_linux_user_tagdepth(ahc, &devinfo);	if (tags != 0 && sdev->tagged_supported != 0) {		ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);		ahc_print_devinfo(ahc, &devinfo);

⌨️ 快捷键说明

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