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

📄 aic7xxx_osm.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif	ahc = (struct ahc_softc *)data;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	ahc_lock(ahc, &flags);#endif	while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) {			TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links);		dev->flags &= ~AHC_DEV_ON_RUN_LIST;		ahc_linux_check_device_queue(ahc, dev);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)		/* Yeild to our interrupt handler */		ahc_unlock(ahc, &flags);		ahc_lock(ahc, &flags);#endif	}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	ahc_unlock(ahc, &flags);#endif}/******************************** Macros **************************************/#define BUILD_SCSIID(ahc, cmd)						    \	((((cmd)->device->id << TID_SHIFT) & TID)			    \	| (((cmd)->device->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \	| (((cmd)->device->channel == 0) ? 0 : TWIN_CHNLB))/******************************** Bus DMA *************************************/intahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent,		   bus_size_t alignment, bus_size_t boundary,		   bus_addr_t lowaddr, bus_addr_t highaddr,		   bus_dma_filter_t *filter, void *filterarg,		   bus_size_t maxsize, int nsegments,		   bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag){	bus_dma_tag_t dmat;	dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);	if (dmat == NULL)		return (ENOMEM);	/*	 * Linux is very simplistic about DMA memory.  For now don't	 * maintain all specification information.  Once Linux supplies	 * better facilities for doing these operations, or the	 * needs of this particular driver change, we might need to do	 * more here.	 */	dmat->alignment = alignment;	dmat->boundary = boundary;	dmat->maxsize = maxsize;	*ret_tag = dmat;	return (0);}voidahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat){	free(dmat, M_DEVBUF);}intahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr,		 int flags, bus_dmamap_t *mapp){	bus_dmamap_t map;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)	map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT);	if (map == NULL)		return (ENOMEM);	/*	 * Although we can dma data above 4GB, our	 * "consistent" memory is below 4GB for	 * space efficiency reasons (only need a 4byte	 * address).  For this reason, we have to reset	 * our dma mask when doing allocations.	 */	if (ahc->dev_softc != NULL)		if (ahc_pci_set_dma_mask(ahc->dev_softc, 0xFFFFFFFF)) {			printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");			return (ENODEV);		}	*vaddr = pci_alloc_consistent(ahc->dev_softc,				      dmat->maxsize, &map->bus_addr);	if (ahc->dev_softc != NULL)		if (ahc_pci_set_dma_mask(ahc->dev_softc,				     ahc->platform_data->hw_dma_mask)) {			printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");			return (ENODEV);		}#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) */	/*	 * At least in 2.2.14, malloc is a slab allocator so all	 * allocations are aligned.  We assume for these kernel versions	 * that all allocations will be bellow 4Gig, physically contiguous,	 * and accessible via DMA by the controller.	 */	map = NULL; /* No additional information to store */	*vaddr = malloc(dmat->maxsize, M_DEVBUF, M_NOWAIT);#endif	if (*vaddr == NULL)		return (ENOMEM);	*mapp = map;	return(0);}voidahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat,		void* vaddr, bus_dmamap_t map){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)	pci_free_consistent(ahc->dev_softc, dmat->maxsize,			    vaddr, map->bus_addr);#else	free(vaddr, M_DEVBUF);#endif}intahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map,		void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb,		void *cb_arg, int flags){	/*	 * Assume for now that this will only be used during	 * initialization and not for per-transaction buffer mapping.	 */	bus_dma_segment_t stack_sg;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)	stack_sg.ds_addr = map->bus_addr;#else#define VIRT_TO_BUS(a) (uint32_t)virt_to_bus((void *)(a))	stack_sg.ds_addr = VIRT_TO_BUS(buf);#endif	stack_sg.ds_len = dmat->maxsize;	cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);	return (0);}voidahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map){	/*	 * The map may is NULL in our < 2.3.X implementation.	 */	if (map != NULL)		free(map, M_DEVBUF);}intahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map){	/* Nothing to do */	return (0);}/********************* Platform Dependent Functions ***************************//* * Compare "left hand" softc with "right hand" softc, returning: * < 0 - lahc has a lower priority than rahc *   0 - Softcs are equal * > 0 - lahc has a higher priority than rahc */intahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc){	int	value;	int	rvalue;	int	lvalue;	/*	 * Under Linux, cards are ordered as follows:	 *	1) VLB/EISA BIOS enabled devices sorted by BIOS address.	 *	2) PCI devices with BIOS enabled sorted by bus/slot/func.	 *	3) All remaining VLB/EISA devices sorted by ioport.	 *	4) All remaining PCI devices sorted by bus/slot/func.	 */	value = (lahc->flags & AHC_BIOS_ENABLED)	      - (rahc->flags & AHC_BIOS_ENABLED);	if (value != 0)		/* Controllers with BIOS enabled have a *higher* priority */		return (value);	/*	 * Same BIOS setting, now sort based on bus type.	 * EISA and VL controllers sort together.  EISA/VL	 * have higher priority than PCI.	 */	rvalue = (rahc->chip & AHC_BUS_MASK); 	if (rvalue == AHC_VL)		rvalue = AHC_EISA;	lvalue = (lahc->chip & AHC_BUS_MASK); 	if (lvalue == AHC_VL)		lvalue = AHC_EISA;	value = rvalue - lvalue;	if (value != 0)		return (value);	/* Still equal.  Sort by BIOS address, ioport, or bus/slot/func. */	switch (rvalue) {#ifdef CONFIG_PCI	case AHC_PCI:	{		char primary_channel;		if (aic7xxx_reverse_scan != 0)			value = ahc_get_pci_bus(lahc->dev_softc)			      - ahc_get_pci_bus(rahc->dev_softc);		else			value = ahc_get_pci_bus(rahc->dev_softc)			      - ahc_get_pci_bus(lahc->dev_softc);		if (value != 0)			break;		if (aic7xxx_reverse_scan != 0)			value = ahc_get_pci_slot(lahc->dev_softc)			      - ahc_get_pci_slot(rahc->dev_softc);		else			value = ahc_get_pci_slot(rahc->dev_softc)			      - ahc_get_pci_slot(lahc->dev_softc);		if (value != 0)			break;		/*		 * On multi-function devices, the user can choose		 * to have function 1 probed before function 0.		 * Give whichever channel is the primary channel		 * the highest priority.		 */		primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A';		value = -1;		if (lahc->channel == primary_channel)			value = 1;		break;	}#endif	case AHC_EISA:		if ((rahc->flags & AHC_BIOS_ENABLED) != 0) {			value = rahc->platform_data->bios_address			      - lahc->platform_data->bios_address; 		} else {			value = rahc->bsh.ioport			      - lahc->bsh.ioport; 		}		break;	default:		panic("ahc_softc_sort: invalid bus type");	}	return (value);}static voidahc_linux_setup_tag_info_global(char *p){	int tags, i, j;	tags = simple_strtoul(p + 1, NULL, 0) & 0xff;	printf("Setting Global Tags= %d\n", tags);	for (i = 0; i < NUM_ELEMENTS(aic7xxx_tag_info); i++) {		for (j = 0; j < AHC_NUM_TARGETS; j++) {			aic7xxx_tag_info[i].tag_commands[j] = tags;		}	}}static voidahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value){	if ((instance >= 0) && (targ >= 0)	 && (instance < NUM_ELEMENTS(aic7xxx_tag_info))	 && (targ < AHC_NUM_TARGETS)) {		aic7xxx_tag_info[instance].tag_commands[targ] = value & 0xff;		if (bootverbose)			printf("tag_info[%d:%d] = %d\n", instance, targ, value);	}}static voidahc_linux_setup_dv(u_long arg, int instance, int targ, int32_t value){	if ((instance >= 0)	 && (instance < NUM_ELEMENTS(aic7xxx_dv_settings))) {		aic7xxx_dv_settings[instance] = value;		if (bootverbose)			printf("dv[%d] = %d\n", instance, value);	}}/* * 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		{ "reverse_scan", &aic7xxx_reverse_scan },		{ "no_probe", &aic7xxx_probe_eisa_vl },		{ "probe_eisa_vl", &aic7xxx_probe_eisa_vl },		{ "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 = aic_parse_brace_option("tag_info", p + n, end,			    2, ahc_linux_setup_tag_info, 0);		} else if (strncmp(p, "dv", n) == 0) {			s = aic_parse_brace_option("dv", p + n, end, 1,			    ahc_linux_setup_dv, 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;}#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)__setup("aic7xxx=", aic7xxx_setup);#endifuint32_t aic7xxx_verbose;intahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template){	char	 buf[80];	struct	 Scsi_Host *host;	char	*new_name;	u_long	 s;	u_int	 targ_offset;	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);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)	scsi_assign_lock(host, &ahc->platform_data->spin_lock);#elif AHC_SCSI_HAS_HOST_LOCK != 0	host->lock = &ahc->platform_data->spin_lock;#endif	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_next_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;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) && \    LINUX_VERSION_CODE  < KERNEL_VERSION(2,5,0)	scsi_set_pci_device(host, ahc->dev_softc);#endif	ahc_linux_initialize_scsi_bus(ahc);	ahc_unlock(ahc, &s);	ahc->platform_data->dv_pid = kernel_thread(ahc_linux_dv_thread, ahc, 0);	ahc_lock(ahc, &s);	if (ahc->platform_data->dv_pid < 0) {		printf("%s: Failed to create DV thread, error= %d\n",		       ahc_name(ahc), ahc->platform_data->dv_pid);		return (-ahc->platform_data->dv_pid);	}	/*	 * Initially allocate *all* of our linux target objects	 * so that the DV thread will scan them all in parallel	 * just after driver initialization.  Any device that	 * does not exist will have its target object destroyed	 * by the selection timeout handler.  In the case of a	 * device that appears after the initial DV scan, async	 * negotiation will occur for the first command, and DV	 * will comence should that first command be successful.	 */	for (targ_offset = 0;	     targ_offset < host->max_id * (host->max_channel + 1);	     targ_offset++) {		u_int channel;		u_int target;		channel = 0;		target = targ_offset;		if (target > 7

⌨️ 快捷键说明

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