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

📄 aic79xx_osm.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 5 页
字号:
		if ((pending_scb->flags & SCB_PACKETIZED) != 0) {			/*			 * Mark the SCB has having an outstanding			 * task management function.  Should the command			 * complete normally before the task management			 * function can be sent, the host will be notified			 * to abort our requeued SCB.			 */			ahd_outb(ahd, SCB_TASK_MANAGEMENT,				 pending_scb->hscb->task_management);		} else {			/*			 * If non-packetized, set the MK_MESSAGE control			 * bit indicating that we desire to send a message.			 * We also set the disconnected flag since there is			 * no guarantee that our SCB control byte matches			 * the version on the card.  We don't want the			 * sequencer to abort the command thinking an			 * unsolicited reselection occurred.			 */			pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;			/*			 * The sequencer will never re-reference the			 * in-core SCB.  To make sure we are notified			 * during reslection, set the MK_MESSAGE flag in			 * the card's copy of the SCB.			 */			ahd_outb(ahd, SCB_CONTROL,				 ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE);		}		/*		 * Clear out any entries in the QINFIFO first		 * so we are the next SCB for this target		 * to run.		 */		ahd_search_qinfifo(ahd, cmd->device->id,				   cmd->device->channel + 'A', cmd->device->lun,				   SCB_LIST_NULL, ROLE_INITIATOR,				   CAM_REQUEUE_REQ, SEARCH_COMPLETE);		ahd_qinfifo_requeue_tail(ahd, pending_scb);		ahd_set_scbptr(ahd, saved_scbptr);		ahd_print_path(ahd, pending_scb);		printf("Device is disconnected, re-queuing SCB\n");		wait = TRUE;	} else {		printf("%s:%d:%d:%d: Unable to deliver message\n",		       ahd_name(ahd), cmd->device->channel,		       cmd->device->id, cmd->device->lun);		retval = FAILED;		goto done;	}no_cmd:	/*	 * Our assumption is that if we don't have the command, no	 * recovery action was required, so we return success.  Again,	 * the semantics of the mid-layer recovery engine are not	 * well defined, so this may change in time.	 */	retval = SUCCESS;done:	if (paused)		ahd_unpause(ahd);	if (wait) {		struct timer_list timer;		int ret;		ahd->platform_data->flags |= AHD_UP_EH_SEMAPHORE;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)		ahd_unlock(ahd, &s);#else		spin_unlock_irq(ahd->platform_data->host->host_lock);#endif		init_timer(&timer);		timer.data = (u_long)ahd;		timer.expires = jiffies + (5 * HZ);		timer.function = ahd_linux_sem_timeout;		add_timer(&timer);		printf("Recovery code sleeping\n");		down(&ahd->platform_data->eh_sem);		printf("Recovery code awake\n");        	ret = del_timer(&timer);		if (ret == 0) {			printf("Timer Expired\n");			retval = FAILED;		}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)		ahd_lock(ahd, &s);#else		spin_lock_irq(ahd->platform_data->host->host_lock);#endif	}	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);	TAILQ_INIT(&ahd->platform_data->completeq);	ahd_midlayer_entrypoint_unlock(ahd, &s);	if (acmd != NULL) {		acmd = ahd_linux_run_complete_queue(ahd, acmd);		if (acmd != NULL) {			ahd_midlayer_entrypoint_lock(ahd, &s);			ahd_schedule_completeq(ahd, acmd);			ahd_midlayer_entrypoint_unlock(ahd, &s);		}	}	ahd_schedule_runq(ahd);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	spin_lock_irq(&io_request_lock);#endif	return (retval);}static voidahd_linux_dev_reset_complete(Scsi_Cmnd *cmd){	free(cmd, M_DEVBUF);}/* * Attempt to send a target reset message to the device that timed out. */static intahd_linux_dev_reset(Scsi_Cmnd *cmd){	struct	ahd_softc *ahd;	struct	scsi_cmnd *recovery_cmd;	struct	ahd_linux_device *dev;	struct	ahd_initiator_tinfo *tinfo;	struct	ahd_tmode_tstate *tstate;	struct	scb *scb;	struct	hardware_scb *hscb;	struct	ahd_cmd *acmd;	u_long	s;	struct	timer_list timer;	int	retval;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	spin_unlock_irq(&io_request_lock);#endif	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;	recovery_cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);	memset(recovery_cmd, 0, sizeof(struct scsi_cmnd));	recovery_cmd->device = cmd->device;	recovery_cmd->scsi_done = ahd_linux_dev_reset_complete;#if AHD_DEBUG	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)		printf("%s:%d:%d:%d: Device reset called for cmd %p\n",		       ahd_name(ahd), cmd->device->channel, cmd->device->id,		       cmd->device->lun, cmd);#endif	ahd_midlayer_entrypoint_lock(ahd, &s);	dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id,				   cmd->device->lun, /*alloc*/FALSE);	if (dev == NULL) {		ahd_midlayer_entrypoint_unlock(ahd, &s);		return (FAILED);	}	if ((scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX)) == NULL) {		ahd_midlayer_entrypoint_unlock(ahd, &s);		return (FAILED);	}	tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,				    cmd->device->id, &tstate);	recovery_cmd->result = CAM_REQ_INPROG << 16;	recovery_cmd->host_scribble = (char *)scb;	scb->io_ctx = recovery_cmd;	scb->platform_data->dev = dev;	scb->sg_count = 0;	ahd_set_residual(scb, 0);	ahd_set_sense_residual(scb, 0);	hscb = scb->hscb;	hscb->control = 0;	hscb->scsiid = BUILD_SCSIID(ahd, cmd);	hscb->lun = cmd->lun;	hscb->cdb_len = 0;	hscb->task_management = SIU_TASKMGMT_LUN_RESET;	scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE;	if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {		scb->flags |= SCB_PACKETIZED;	} else {		hscb->control |= MK_MESSAGE;	}	dev->openings--;	dev->active++;	dev->commands_issued++;	LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);	ahd_queue_scb(ahd, scb);	ahd->platform_data->flags |= AHD_UP_EH_SEMAPHORE;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	ahd_unlock(ahd, &s);#else	spin_unlock_irq(ahd->platform_data->host->host_lock);#endif	init_timer(&timer);	timer.data = (u_long)ahd;	timer.expires = jiffies + (5 * HZ);	timer.function = ahd_linux_sem_timeout;	add_timer(&timer);	printf("Recovery code sleeping\n");	down(&ahd->platform_data->eh_sem);	printf("Recovery code awake\n");	retval = SUCCESS;	if (del_timer(&timer) == 0) {		printf("Timer Expired\n");		retval = FAILED;	}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	ahd_lock(ahd, &s);#else	spin_lock_irq(ahd->platform_data->host->host_lock);#endif	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);	TAILQ_INIT(&ahd->platform_data->completeq);	ahd_midlayer_entrypoint_unlock(ahd, &s);	if (acmd != NULL) {		acmd = ahd_linux_run_complete_queue(ahd, acmd);		if (acmd != NULL) {			ahd_midlayer_entrypoint_lock(ahd, &s);			ahd_schedule_completeq(ahd, acmd);			ahd_midlayer_entrypoint_unlock(ahd, &s);		}	}	ahd_schedule_runq(ahd);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	spin_lock_irq(&io_request_lock);#endif	printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);	return (retval);}/* * Reset the SCSI bus. */static intahd_linux_bus_reset(Scsi_Cmnd *cmd){	struct ahd_softc *ahd;	struct ahd_cmd *acmd;	u_long s;	int    found;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	spin_unlock_irq(&io_request_lock);#endif	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;#ifdef AHD_DEBUG	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)		printf("%s: Bus reset called for cmd %p\n",		       ahd_name(ahd), cmd);#endif	ahd_midlayer_entrypoint_lock(ahd, &s);	found = ahd_reset_channel(ahd, cmd->channel + 'A',				  /*initiate reset*/TRUE);	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);	TAILQ_INIT(&ahd->platform_data->completeq);	ahd_midlayer_entrypoint_unlock(ahd, &s);	if (bootverbose)		printf("%s: SCSI bus reset delivered. "		       "%d SCBs aborted.\n", ahd_name(ahd), found);	if (acmd != NULL) {		acmd = ahd_linux_run_complete_queue(ahd, acmd);		if (acmd != NULL) {			ahd_midlayer_entrypoint_lock(ahd, &s);			ahd_schedule_completeq(ahd, acmd);			ahd_midlayer_entrypoint_unlock(ahd, &s);		}	}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	spin_lock_irq(&io_request_lock);#endif	return (SUCCESS);}Scsi_Host_Template aic79xx_driver_template = {	.proc_info		= ahd_linux_proc_info,	.detect			= ahd_linux_detect,	.release		= ahd_linux_release,	.info			= ahd_linux_info,	.queuecommand		= ahd_linux_queue,	.eh_abort_handler	= ahd_linux_abort,	.eh_device_reset_handler = ahd_linux_dev_reset,	.eh_bus_reset_handler	= ahd_linux_bus_reset,#if defined(__i386__)	.bios_param		= ahd_linux_biosparam,#endif	.can_queue		= AHD_MAX_QUEUE,	.this_id		= -1,	.sg_tablesize		= AHD_NSEG,	.cmd_per_lun		= 2,	.use_clustering		= ENABLE_CLUSTERING,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)	/*	 * We can only map 16MB per-SG	 * so create a sector limit of	 * "16MB" in 2K sectors.	 */	.max_sectors		= 8192,#endif#if defined CONFIG_HIGHIO || LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)/* Assume RedHat Distribution with its different HIGHIO conventions. */	.can_dma_32		= 1,	.single_sg_okay		= 1,#else	.highmem_io		= 1,#endif#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)	.name			= "aic79xx",	.slave_alloc		= ahd_linux_slave_alloc,	.slave_configure	= ahd_linux_slave_configure,	.slave_destroy		= ahd_linux_slave_destroy,#else	.select_queue_depths	= ahd_linux_select_queue_depth,	.use_new_eh_code	= 1,#endif};#define driver_template aic79xx_driver_template#include "scsi_module.c"/**************************** Tasklet Handler *********************************/static voidahd_runq_tasklet(unsigned long data){	struct ahd_softc* ahd;	struct ahd_linux_device *dev;	u_long flags;	ahd = (struct ahd_softc *)data;	ahd_lock(ahd, &flags);	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);		/* Yeild to our interrupt handler */		ahd_unlock(ahd, &flags);		ahd_lock(ahd, &flags);	}	ahd_unlock(ahd, &flags);}/************************ Shutdown/halt/reboot hook ***************************/#include <linux/notifier.h>#include <linux/reboot.h>static struct notifier_block ahd_linux_notifier = {	ahd_linux_halt, NULL, 0};static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf){#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	struct ahd_softc *ahd;	/*	 * In 2.5.X, this is called prior to the filesystems	 * being synced and the SCSI layer being properly	 * shutdown.  A different API is required there,	 * but the device hooks for this don't quite look	 * right.	 */	if (event == SYS_DOWN || event == SYS_HALT) {		TAILQ_FOREACH(ahd, &ahd_tailq, links) {			ahd_shutdown(ahd);		}	}#endif	return (NOTIFY_OK);}/******************************** Bus DMA *************************************/intahd_dma_tag_create(struct ahd_softc *ahd, 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);}voidahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat){	free(dmat, M_DEVBUF);}intahd_dmamem_alloc(struct ahd_softc *ahd, 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 (ahd->dev_softc != NULL)		ahd_pci_set_dma_mask(ahd->dev_softc, 0xFFFFFFFF);	*vaddr = pci_alloc_consistent(ahd->dev_softc,				      dmat->maxsize, &map->bus_addr);	if (ahd->dev_softc != NULL)		ahd_pci_set_dma_mask(ahd->dev_softc,				     ahd->platform_data->hw_dma_mask);#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 accessable 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);}voidahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat,		void* vaddr, bus_dmamap_t map){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)	pci_free_consistent(ahd->dev_softc, dmat->maxsize,			    vaddr, map->bus_addr);#else	free(vaddr, M_DEVBUF);#endif}

⌨️ 快捷键说明

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