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

📄 aic79xx_osm.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 5 页
字号:
"		Enable verbose logging\n""		Set tag depth on Controller 2/Target 2 to 10 tags\n""		Shorten the selection timeout to 128ms\n""\n""	options aic79xx='\"verbose.tag_info:{{}.{}.{..10}}.seltime:1\"'\n""\n""	Sample /etc/modules.conf line:\n""		Change Read Streaming for Controller's 2 and 3\n""\n""	options aic79xx='\"rd_strm:{..0xFFF0.0xC0F0}\"'");#endifstatic void ahd_linux_handle_scsi_status(struct ahd_softc *,					 struct ahd_linux_device *,					 struct scb *);static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd,					 Scsi_Cmnd *cmd);static void ahd_linux_filter_inquiry(struct ahd_softc *ahd,				     struct ahd_devinfo *devinfo);static void ahd_linux_dev_timed_unfreeze(u_long arg);static void ahd_linux_sem_timeout(u_long arg);static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd);static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd);static void ahd_linux_start_dv(struct ahd_softc *ahd);static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd);static int  ahd_linux_dv_thread(void *data);static void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target);static void ahd_linux_dv_transition(struct ahd_softc *ahd,				    struct scsi_cmnd *cmd,				    struct ahd_devinfo *devinfo,				    struct ahd_linux_target *targ);static void ahd_linux_dv_fill_cmd(struct ahd_softc *ahd,				  struct scsi_cmnd *cmd,				  struct ahd_devinfo *devinfo);static void ahd_linux_dv_inq(struct ahd_softc *ahd,			     struct scsi_cmnd *cmd,			     struct ahd_devinfo *devinfo,			     struct ahd_linux_target *targ,			     u_int request_length);static void ahd_linux_dv_tur(struct ahd_softc *ahd,			     struct scsi_cmnd *cmd,			     struct ahd_devinfo *devinfo);static void ahd_linux_dv_rebd(struct ahd_softc *ahd,			      struct scsi_cmnd *cmd,			      struct ahd_devinfo *devinfo,			      struct ahd_linux_target *targ);static void ahd_linux_dv_web(struct ahd_softc *ahd,			     struct scsi_cmnd *cmd,			     struct ahd_devinfo *devinfo,			     struct ahd_linux_target *targ);static void ahd_linux_dv_reb(struct ahd_softc *ahd,			     struct scsi_cmnd *cmd,			     struct ahd_devinfo *devinfo,			     struct ahd_linux_target *targ);static void ahd_linux_dv_su(struct ahd_softc *ahd,			    struct scsi_cmnd *cmd,			    struct ahd_devinfo *devinfo,			    struct ahd_linux_target *targ);static __inline int	   ahd_linux_dv_fallback(struct ahd_softc *ahd,				 struct ahd_devinfo *devinfo);static int ahd_linux_fallback(struct ahd_softc *ahd,			      struct ahd_devinfo *devinfo);static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd,					  struct ahd_devinfo *devinfo);static void ahd_linux_dv_complete(Scsi_Cmnd *cmd);static void ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ);static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd,				     struct ahd_devinfo *devinfo);static u_int ahd_linux_user_dv_setting(struct ahd_softc *ahd);static void ahd_linux_device_queue_depth(struct ahd_softc *ahd,					 struct ahd_linux_device *dev);static struct ahd_linux_target*	ahd_linux_alloc_target(struct ahd_softc*,						       u_int, u_int);static void			ahd_linux_free_target(struct ahd_softc*,						      struct ahd_linux_target*);static struct ahd_linux_device*	ahd_linux_alloc_device(struct ahd_softc*,						       struct ahd_linux_target*,						       u_int);static void			ahd_linux_free_device(struct ahd_softc*,						      struct ahd_linux_device*);static void ahd_linux_run_device_queue(struct ahd_softc*,				       struct ahd_linux_device*);static void ahd_linux_setup_tag_info(char *p, char *end, char *s);static void ahd_linux_setup_tag_info_global(char *p);static void ahd_linux_setup_rd_strm_info(char *p, char *end, char *s);static void ahd_linux_setup_dv(char *p, char *end, char *s);static void ahd_linux_setup_iocell_info(char *p, char *end, char *s, int index);static int ahd_linux_next_unit(void);static void ahd_runq_tasklet(unsigned long data);static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf);static int aic79xx_setup(char *c);/****************************** Inlines ***************************************/static __inline void ahd_schedule_completeq(struct ahd_softc *ahd,					    struct ahd_cmd *acmd);static __inline void ahd_schedule_runq(struct ahd_softc *ahd);static __inline void ahd_setup_runq_tasklet(struct ahd_softc *ahd);static __inline void ahd_teardown_runq_tasklet(struct ahd_softc *ahd);static __inline struct ahd_linux_device*		     ahd_linux_get_device(struct ahd_softc *ahd, u_int channel,					  u_int target, u_int lun, int alloc);static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd,						    struct ahd_cmd *acmd);static __inline void ahd_linux_check_device_queue(struct ahd_softc *ahd,						  struct ahd_linux_device *dev);static __inline struct ahd_linux_device *		     ahd_linux_next_device_to_run(struct ahd_softc *ahd);static __inline void ahd_linux_run_device_queues(struct ahd_softc *ahd);static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);static __inline int ahd_linux_map_seg(struct ahd_softc *ahd, struct scb *scb,		 		      struct ahd_dma_seg *sg,				      bus_addr_t addr, bus_size_t len);static __inline voidahd_schedule_completeq(struct ahd_softc *ahd, struct ahd_cmd *acmd){	while (acmd != NULL) {		struct ahd_completeq *completeq;		struct ahd_cmd *list_cmd;		struct ahd_cmd *next_cmd;		next_cmd = TAILQ_NEXT(acmd, acmd_links.tqe);		completeq = &ahd->platform_data->completeq;		list_cmd = TAILQ_FIRST(completeq);		while (list_cmd != NULL		    && acmd_scsi_cmd(list_cmd).serial_number		     < acmd_scsi_cmd(acmd).serial_number)			list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe);		if (list_cmd != NULL)			TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe);		else			TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe);		acmd = next_cmd;	}	if ((ahd->platform_data->flags & AHD_RUN_CMPLT_Q_TIMER) == 0) {		ahd->platform_data->flags |= AHD_RUN_CMPLT_Q_TIMER;		ahd->platform_data->completeq_timer.expires = jiffies;		add_timer(&ahd->platform_data->completeq_timer);	}}static __inline voidahd_schedule_runq(struct ahd_softc *ahd){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	tasklet_schedule(&ahd->platform_data->runq_tasklet);#else	/*	 * Tasklets are not available, so run inline.	 */	ahd_runq_tasklet((unsigned long)ahd);#endif}static __inlinevoid ahd_setup_runq_tasklet(struct ahd_softc *ahd){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet,		     (unsigned long)ahd);#endif}static __inline voidahd_teardown_runq_tasklet(struct ahd_softc *ahd){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	tasklet_kill(&ahd->platform_data->runq_tasklet);#endif}static __inline struct ahd_linux_device*ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target,		     u_int lun, int alloc){	struct ahd_linux_target *targ;	struct ahd_linux_device *dev;	u_int target_offset;	target_offset = target;	if (channel != 0)		target_offset += 8;	targ = ahd->platform_data->targets[target_offset];	if (targ == NULL) {		if (alloc != 0) {			targ = ahd_linux_alloc_target(ahd, channel, target);			if (targ == NULL)				return (NULL);		} else			return (NULL);	}	dev = targ->devices[lun];	if (dev == NULL && alloc != 0)		dev = ahd_linux_alloc_device(ahd, targ, lun);	return (dev);}#define AHD_LINUX_MAX_RETURNED_ERRORS 4static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd, struct ahd_cmd *acmd){		u_long	done_flags;	int	with_errors;	ahd_done_lock(ahd, &done_flags);	with_errors = 0;	while (acmd != NULL) {		Scsi_Cmnd *cmd;		cmd = &acmd_scsi_cmd(acmd);		acmd = TAILQ_NEXT(acmd, acmd_links.tqe);		cmd->host_scribble = NULL;		if (ahd_cmd_get_transaction_status(cmd) != DID_OK		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)			with_errors++;		cmd->scsi_done(cmd);		if (with_errors > AHD_LINUX_MAX_RETURNED_ERRORS) {			/*			 * Linux uses stack recursion to requeue			 * commands that need to be retried.  Avoid			 * blowing out the stack by "spoon feeding"			 * commands that completed with error back			 * the operating system in case they are going			 * to be retried. "ick"			 */			break;		}	}	ahd_done_unlock(ahd, &done_flags);	return (acmd);}static __inline voidahd_linux_check_device_queue(struct ahd_softc *ahd,			     struct ahd_linux_device *dev){	if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) != 0	 && dev->active == 0) {		dev->flags &= ~AHD_DEV_FREEZE_TIL_EMPTY;		dev->qfrozen--;	}	if (TAILQ_FIRST(&dev->busyq) == NULL	 || dev->openings == 0 || dev->qfrozen != 0)		return;	ahd_linux_run_device_queue(ahd, dev);}static __inline struct ahd_linux_device *ahd_linux_next_device_to_run(struct ahd_softc *ahd){		if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0	 || (ahd->platform_data->qfrozen != 0	  && AHD_DV_SIMQ_FROZEN(ahd) == 0))		return (NULL);	return (TAILQ_FIRST(&ahd->platform_data->device_runq));}static __inline voidahd_linux_run_device_queues(struct ahd_softc *ahd){	struct ahd_linux_device *dev;	while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {		TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);		dev->flags &= ~AHD_DEV_ON_RUN_LIST;		ahd_linux_check_device_queue(ahd, dev);	}}static __inline voidahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb){	Scsi_Cmnd *cmd;	int direction;	cmd = scb->io_ctx;	direction = scsi_to_pci_dma_dir(cmd->sc_data_direction);	ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE);	if (cmd->use_sg != 0) {		struct scatterlist *sg;		sg = (struct scatterlist *)cmd->request_buffer;		pci_unmap_sg(ahd->dev_softc, sg, cmd->use_sg, direction);	} else if (cmd->request_bufflen != 0) {		pci_unmap_single(ahd->dev_softc,				 scb->platform_data->buf_busaddr,				 cmd->request_bufflen, direction);	}}static __inline intahd_linux_map_seg(struct ahd_softc *ahd, struct scb *scb,		  struct ahd_dma_seg *sg, bus_addr_t addr, bus_size_t len){	int	 consumed;	if ((scb->sg_count + 1) > AHD_NSEG)		panic("Too few segs for dma mapping.  "		      "Increase AHD_NSEG\n");	consumed = 1;	sg->addr = ahd_htole32(addr & 0xFFFFFFFF);	scb->platform_data->xfer_len += len;	if (sizeof(bus_addr_t) > 4	 && (ahd->flags & AHD_39BIT_ADDRESSING) != 0) {		/*		 * Due to DAC restrictions, we can't		 * cross a 4GB boundary.		 */		if ((addr ^ (addr + len - 1)) & ~0xFFFFFFFF) {			struct	 ahd_dma_seg *next_sg;			uint32_t next_len;			printf("Crossed Seg\n");			if ((scb->sg_count + 2) > AHD_NSEG)				panic("Too few segs for dma mapping.  "				      "Increase AHD_NSEG\n");			consumed++;			next_sg = sg + 1;			next_sg->addr = 0;			next_len = 0x100000000 - (addr & 0xFFFFFFFF);			len -= next_len;			next_len |= ((addr >> 8) + 0x1000000) & 0x7F000000;			next_sg->len = ahd_htole32(next_len);		}		len |= (addr >> 8) & 0x7F000000;	}	sg->len = ahd_htole32(len);	return (consumed);}/******************************** Macros **************************************/#define BUILD_SCSIID(ahd, cmd)						\	((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id)/************************  Host template entry points *************************/static int	   ahd_linux_detect(Scsi_Host_Template *);static int	   ahd_linux_release(struct Scsi_Host *);static const char *ahd_linux_info(struct Scsi_Host *);static int	   ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)static int	   ahd_linux_slave_alloc(Scsi_Device *);static int	   ahd_linux_slave_configure(Scsi_Device *);static void	   ahd_linux_slave_destroy(Scsi_Device *);static int	   ahd_linux_biosparam(struct scsi_device*,				       struct block_device*, sector_t, int[]);#elsestatic void	   ahd_linux_select_queue_depth(struct Scsi_Host *host,						Scsi_Device *scsi_devs);static int	   ahd_linux_biosparam(Disk *, kdev_t, int[]);#endifstatic int	   ahd_linux_bus_reset(Scsi_Cmnd *);static int	   ahd_linux_dev_reset(Scsi_Cmnd *);static int	   ahd_linux_abort(Scsi_Cmnd *);/* * Try to detect an Adaptec 79XX controller. */static intahd_linux_detect(Scsi_Host_Template *template){	struct	ahd_softc *ahd;	int     found;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	/*	 * It is a bug that the upper layer takes	 * this lock just prior to calling us.	 */	spin_unlock_irq(&io_request_lock);#endif	/*	 * Sanity checking of Linux SCSI data structures so	 * that some of our hacks^H^H^H^H^Hassumptions aren't	 * violated.	 */	if (offsetof(struct ahd_cmd_internal, end)	  > offsetof(struct scsi_cmnd, host_scribble)) {		printf("ahd_linux_detect: SCSI data structures changed.\n");		printf("ahd_linux_detect: Unable to attach\n");		return (0);	}#ifdef MODULE	/*	 * If we've been passed any parameters, process them now.	 */	if (aic79xx)		aic79xx_setup(aic79xx);	if (dummy_buffer[0] != 'P')		printk(KERN_WARNING"aic79xx: Please read the file /usr/src/linux/drivers/scsi/README.aic79xx\n""aic79xx: to see the proper way to specify options to the aic79xx module\n""aic79xx: Specifically, don't use any commas when passing arguments to\n""aic79xx: insmod or else it might trash certain memory areas.\n");#endif#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)	template->proc_name = "aic79xx";#else	template->proc_dir = &proc_scsi_aic79xx;#endif	/*	 * Initialize our softc list lock prior to	 * probing for any adapters.	 */	ahd_list_lockinit();#ifdef CONFIG_PCI	ahd_linux_pci_probe(template);#endif	/*	 * Register with the SCSI layer all	 * controllers we've found.	 */	found = 0;	TAILQ_FOREACH(ahd, &ahd_tailq, links) {		if (ahd_linux_register_host(ahd, template) == 0)			found++;	}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	spin_lock_irq(&io_request_lock);#endif	aic79xx_detect_complete++;	return (found);}/* * Free the passed in Scsi_Host memory structures prior to unloading the * module. */static intahd_linux_release(struct Scsi_Host * host){	struct ahd_softc *ahd;	u_long l;	ahd_list_lock(&l);	if (host != NULL) {		/*		 * We should be able to just perform		 * the free directly, but check our		 * list for extra sanity.		 */		ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata);		if (ahd != NULL) {			u_long s;			ahd_lock(ahd, &s);			ahd_intr_enable(ahd, FALSE);			ahd_unlock(ahd, &s);			ahd_free(ahd);

⌨️ 快捷键说明

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