aic79xx_osm.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,358 行 · 第 1/5 页

C
2,358
字号
	if (starget->channel != 0)		target_offset += 8;	return &ahd->platform_data->starget[target_offset];}static intahd_linux_target_alloc(struct scsi_target *starget){	struct	ahd_softc *ahd =		*((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata);	struct seeprom_config *sc = ahd->seep_config;	unsigned long flags;	struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget);	struct ahd_linux_target *targ = scsi_transport_target_data(starget);	struct ahd_devinfo devinfo;	struct ahd_initiator_tinfo *tinfo;	struct ahd_tmode_tstate *tstate;	char channel = starget->channel + 'A';	ahd_lock(ahd, &flags);	BUG_ON(*ahd_targp != NULL);	*ahd_targp = starget;	memset(targ, 0, sizeof(*targ));	if (sc) {		int flags = sc->device_flags[starget->id];		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,					    starget->id, &tstate);		if ((flags  & CFPACKETIZED) == 0) {			/* Do not negotiate packetized transfers */			spi_rd_strm(starget) = 0;			spi_pcomp_en(starget) = 0;			spi_rti(starget) = 0;			spi_wr_flow(starget) = 0;			spi_hold_mcs(starget) = 0;		} else {			if ((ahd->features & AHD_RTI) == 0)				spi_rti(starget) = 0;		}		if ((flags & CFQAS) == 0)			spi_qas(starget) = 0;		/* Transinfo values have been set to BIOS settings */		spi_max_width(starget) = (flags & CFWIDEB) ? 1 : 0;		spi_min_period(starget) = tinfo->user.period;		spi_max_offset(starget) = tinfo->user.offset;	}	tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id,				    starget->id, &tstate);	ahd_compile_devinfo(&devinfo, ahd->our_id, starget->id,			    CAM_LUN_WILDCARD, channel,			    ROLE_INITIATOR);	ahd_set_syncrate(ahd, &devinfo, 0, 0, 0,			 AHD_TRANS_GOAL, /*paused*/FALSE);	ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,		      AHD_TRANS_GOAL, /*paused*/FALSE);	ahd_unlock(ahd, &flags);	return 0;}static voidahd_linux_target_destroy(struct scsi_target *starget){	struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget);	*ahd_targp = NULL;}static intahd_linux_slave_alloc(struct scsi_device *sdev){	struct	ahd_softc *ahd =		*((struct ahd_softc **)sdev->host->hostdata);	struct scsi_target *starget = sdev->sdev_target;	struct ahd_linux_target *targ = scsi_transport_target_data(starget);	struct ahd_linux_device *dev;	if (bootverbose)		printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id);	BUG_ON(targ->sdev[sdev->lun] != NULL);	dev = scsi_transport_device_data(sdev);	memset(dev, 0, sizeof(*dev));	/*	 * We start out life using untagged	 * transactions of which we allow one.	 */	dev->openings = 1;	/*	 * Set maxtags to 0.  This will be changed if we	 * later determine that we are dealing with	 * a tagged queuing capable device.	 */	dev->maxtags = 0;		targ->sdev[sdev->lun] = sdev;	return (0);}static intahd_linux_slave_configure(struct scsi_device *sdev){	struct	ahd_softc *ahd;	ahd = *((struct ahd_softc **)sdev->host->hostdata);	if (bootverbose)		sdev_printk(KERN_INFO, sdev, "Slave Configure\n");	ahd_linux_device_queue_depth(sdev);	/* Initial Domain Validation */	if (!spi_initial_dv(sdev->sdev_target))		spi_dv_device(sdev);	return 0;}static voidahd_linux_slave_destroy(struct scsi_device *sdev){	struct	ahd_softc *ahd;	struct	ahd_linux_device *dev = scsi_transport_device_data(sdev);	struct  ahd_linux_target *targ = scsi_transport_target_data(sdev->sdev_target);	ahd = *((struct ahd_softc **)sdev->host->hostdata);	if (bootverbose)		printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id);	BUG_ON(dev->active);	targ->sdev[sdev->lun] = NULL;}#if defined(__i386__)/* * Return the disk geometry for the given SCSI device. */static intahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,		    sector_t capacity, int geom[]){	uint8_t *bh;	int	 heads;	int	 sectors;	int	 cylinders;	int	 ret;	int	 extended;	struct	 ahd_softc *ahd;	ahd = *((struct ahd_softc **)sdev->host->hostdata);	bh = scsi_bios_ptable(bdev);	if (bh) {		ret = scsi_partsize(bh, capacity,				    &geom[2], &geom[0], &geom[1]);		kfree(bh);		if (ret != -1)			return (ret);	}	heads = 64;	sectors = 32;	cylinders = aic_sector_div(capacity, heads, sectors);	if (aic79xx_extended != 0)		extended = 1;	else		extended = (ahd->flags & AHD_EXTENDED_TRANS_A) != 0;	if (extended && cylinders >= 1024) {		heads = 255;		sectors = 63;		cylinders = aic_sector_div(capacity, heads, sectors);	}	geom[0] = heads;	geom[1] = sectors;	geom[2] = cylinders;	return (0);}#endif/* * Abort the current SCSI command(s). */static intahd_linux_abort(struct scsi_cmnd *cmd){	int error;		error = ahd_linux_queue_abort_cmd(cmd);	return error;}/* * Attempt to send a target reset message to the device that timed out. */static intahd_linux_dev_reset(struct scsi_cmnd *cmd){	struct ahd_softc *ahd;	struct ahd_linux_device *dev;	struct scb *reset_scb;	u_int  cdb_byte;	int    retval = SUCCESS;	int    paused;	int    wait;	struct	ahd_initiator_tinfo *tinfo;	struct	ahd_tmode_tstate *tstate;	unsigned long flags;	DECLARE_COMPLETION(done);	reset_scb = NULL;	paused = FALSE;	wait = FALSE;	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;	scmd_printk(KERN_INFO, cmd,		    "Attempting to queue a TARGET RESET message:");	printf("CDB:");	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)		printf(" 0x%x", cmd->cmnd[cdb_byte]);	printf("\n");	/*	 * Determine if we currently own this command.	 */	dev = scsi_transport_device_data(cmd->device);	if (dev == NULL) {		/*		 * No target device for this command exists,		 * so we must not still own the command.		 */		scmd_printk(KERN_INFO, cmd, "Is not an active device\n");		return SUCCESS;	}	/*	 * Generate us a new SCB	 */	reset_scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX);	if (!reset_scb) {		scmd_printk(KERN_INFO, cmd, "No SCB available\n");		return FAILED;	}	tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,				    cmd->device->id, &tstate);	reset_scb->io_ctx = cmd;	reset_scb->platform_data->dev = dev;	reset_scb->sg_count = 0;	ahd_set_residual(reset_scb, 0);	ahd_set_sense_residual(reset_scb, 0);	reset_scb->platform_data->xfer_len = 0;	reset_scb->hscb->control = 0;	reset_scb->hscb->scsiid = BUILD_SCSIID(ahd,cmd);	reset_scb->hscb->lun = cmd->device->lun;	reset_scb->hscb->cdb_len = 0;	reset_scb->hscb->task_management = SIU_TASKMGMT_LUN_RESET;	reset_scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE;	if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {		reset_scb->flags |= SCB_PACKETIZED;	} else {		reset_scb->hscb->control |= MK_MESSAGE;	}	dev->openings--;	dev->active++;	dev->commands_issued++;	ahd_lock(ahd, &flags);	LIST_INSERT_HEAD(&ahd->pending_scbs, reset_scb, pending_links);	ahd_queue_scb(ahd, reset_scb);	ahd->platform_data->eh_done = &done;	ahd_unlock(ahd, &flags);	printf("%s: Device reset code sleeping\n", ahd_name(ahd));	if (!wait_for_completion_timeout(&done, 5 * HZ)) {		ahd_lock(ahd, &flags);		ahd->platform_data->eh_done = NULL;		ahd_unlock(ahd, &flags);		printf("%s: Device reset timer expired (active %d)\n",		       ahd_name(ahd), dev->active);		retval = FAILED;	}	printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);	return (retval);}/* * Reset the SCSI bus. */static intahd_linux_bus_reset(struct scsi_cmnd *cmd){	struct ahd_softc *ahd;	int    found;	unsigned long flags;	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_lock(ahd, &flags);	found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A',				  /*initiate reset*/TRUE);	ahd_unlock(ahd, &flags);	if (bootverbose)		printf("%s: SCSI bus reset delivered. "		       "%d SCBs aborted.\n", ahd_name(ahd), found);	return (SUCCESS);}struct scsi_host_template aic79xx_driver_template = {	.module			= THIS_MODULE,	.name			= "aic79xx",	.proc_name		= "aic79xx",	.proc_info		= ahd_linux_proc_info,	.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,	.cmd_per_lun		= 2,	.use_clustering		= ENABLE_CLUSTERING,	.slave_alloc		= ahd_linux_slave_alloc,	.slave_configure	= ahd_linux_slave_configure,	.slave_destroy		= ahd_linux_slave_destroy,	.target_alloc		= ahd_linux_target_alloc,	.target_destroy		= ahd_linux_target_destroy,};/******************************** Bus DMA *************************************/intahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,		   bus_size_t alignment, bus_size_t boundary,		   dma_addr_t lowaddr, dma_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){	*vaddr = pci_alloc_consistent(ahd->dev_softc,				      dmat->maxsize, mapp);	if (*vaddr == NULL)		return (ENOMEM);	return(0);}voidahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat,		void* vaddr, bus_dmamap_t map){	pci_free_consistent(ahd->dev_softc, dmat->maxsize,			    vaddr, map);}intahd_dmamap_load(struct ahd_softc *ahd, 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;	stack_sg.ds_addr = map;	stack_sg.ds_len = dmat->maxsize;	cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);	return (0);}voidahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map){}intahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map){	/* Nothing to do */	return (0);}/********************* Platform Dependent Functions ***************************/static voidahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value){	if ((instance >= 0)	 && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {		uint8_t *iocell_info;		iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];		iocell_info[index] = value & 0xFFFF;		if (bootverbose)			printf("iocell[%d:%ld] = %d\n", instance, index, value);	}}static voidahd_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(aic79xx_tag_info); i++) {		for (j = 0; j < AHD_NUM_TARGETS; j++) {			aic79xx_tag_info[i].tag_commands[j] = tags;		}	}}static void

⌨️ 快捷键说明

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