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

📄 aic7xxx_osm.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		} else {			scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL);			scb->hscb->dataptr = 0;			scb->hscb->datacnt = 0;			scb->sg_count = 0;		}		ahc_sync_sglist(ahc, scb, BUS_DMASYNC_PREWRITE);		LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);		dev->openings--;		dev->active++;		dev->commands_issued++;		if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0)			dev->commands_since_idle_or_otag++;		/*		 * We only allow one untagged transaction		 * per target in the initiator role unless		 * we are storing a full busy target *lun*		 * table in SCB space.		 */		if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0		 && (ahc->features & AHC_SCB_BTT) == 0) {			struct scb_tailq *untagged_q;			int target_offset;			target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);			untagged_q = &(ahc->untagged_queues[target_offset]);			TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);			scb->flags |= SCB_UNTAGGEDQ;			if (TAILQ_FIRST(untagged_q) != scb)				continue;		}		scb->flags |= SCB_ACTIVE;		ahc_queue_scb(ahc, scb);	}}/* * SCSI controller interrupt handler. */voidahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs){	struct	ahc_softc *ahc;	struct	ahc_cmd *acmd;	u_long	flags;	struct	ahc_linux_device *next_dev;	ahc = (struct ahc_softc *) dev_id;	ahc_lock(ahc, &flags); 	ahc_intr(ahc);	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);	TAILQ_INIT(&ahc->platform_data->completeq);	next_dev = ahc_linux_next_device_to_run(ahc);	ahc_unlock(ahc, &flags);	if (next_dev) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)		tasklet_schedule(&ahc->platform_data->runq_tasklet);#else		ahc_runq_tasklet((unsigned long)ahc);#endif	}	if (acmd != NULL)		ahc_linux_run_complete_queue(ahc, acmd);}voidahc_platform_flushwork(struct ahc_softc *ahc){	struct ahc_cmd *acmd;	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);	TAILQ_INIT(&ahc->platform_data->completeq);	if (acmd != NULL)		ahc_linux_run_complete_queue(ahc, acmd);}static struct ahc_linux_target*ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target){	struct ahc_linux_target *targ;	u_int target_offset;	targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT);	if (targ == NULL)		return (NULL);	memset(targ, 0, sizeof(*targ));	targ->channel = channel;	targ->target = target;	targ->ahc = ahc;	target_offset = target;	if (channel != 0)		target_offset += 8;	ahc->platform_data->targets[target_offset] = targ;	return (targ);}static voidahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ){	u_int target_offset;	target_offset = targ->target;	if (targ->channel != 0)		target_offset += 8;	ahc->platform_data->targets[target_offset] = NULL;	free(targ, M_DEVBUF);}static struct ahc_linux_device*ahc_linux_alloc_device(struct ahc_softc *ahc,		 struct ahc_linux_target *targ, u_int lun){	struct ahc_linux_device *dev;	dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT);	if (dev == NULL)		return (NULL);	memset(dev, 0, sizeof(*dev));	init_timer(&dev->timer);	TAILQ_INIT(&dev->busyq);	dev->flags = AHC_DEV_UNCONFIGURED;	dev->lun = lun;	dev->target = targ;	/*	 * 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->refcount++;	targ->devices[lun] = dev;	return (dev);}static voidahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev){	struct ahc_linux_target *targ;	del_timer(&dev->timer);	targ = dev->target;	targ->devices[dev->lun] = NULL;	free(dev, M_DEVBUF);	targ->refcount--;	if (targ->refcount == 0)		ahc_linux_free_target(ahc, targ);}/* * Return a string describing the driver. */const char *ahc_linux_info(struct Scsi_Host *host){	static char buffer[512];	char	ahc_info[256];	char   *bp;	struct ahc_softc *ahc;	bp = &buffer[0];	ahc = *(struct ahc_softc **)host->hostdata;	memset(bp, 0, sizeof(buffer));	strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev ");	strcat(bp, AIC7XXX_DRIVER_VERSION);	strcat(bp, "\n");	strcat(bp, "        <");	strcat(bp, ahc->description);	strcat(bp, ">\n");	strcat(bp, "        ");	ahc_controller_info(ahc, ahc_info);	strcat(bp, ahc_info);	strcat(bp, "\n");	return (bp);}voidahc_send_async(struct ahc_softc *ahc, char channel,	       u_int target, u_int lun, ac_code code, void *arg){	switch (code) {	case AC_TRANSFER_NEG:	{		char	buf[80];		struct	ahc_linux_target *targ;		struct	info_str info;		struct	ahc_initiator_tinfo *tinfo;		struct	ahc_tmode_tstate *tstate;		int	target_offset;		info.buffer = buf;		info.length = sizeof(buf);		info.offset = 0;		info.pos = 0;		tinfo = ahc_fetch_transinfo(ahc, channel,						channel == 'A' ? ahc->our_id							       : ahc->our_id_b,						target, &tstate);		/*		 * Don't bother reporting results while		 * negotiations are still pending.		 */		if (tinfo->curr.period != tinfo->goal.period		 || tinfo->curr.width != tinfo->goal.width		 || tinfo->curr.offset != tinfo->goal.offset		 || tinfo->curr.ppr_options != tinfo->goal.ppr_options)			if (bootverbose == 0)				break;		/*		 * Don't bother reporting results that		 * are identical to those last reported.		 */		target_offset = target;		if (channel == 'B')			target_offset += 8;		targ = ahc->platform_data->targets[target_offset];		if (targ == NULL)			break;		if (tinfo->curr.period == targ->last_tinfo.period		 && tinfo->curr.width == targ->last_tinfo.width		 && tinfo->curr.offset == targ->last_tinfo.offset		 && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options)			if (bootverbose == 0)				break;		targ->last_tinfo.period = tinfo->curr.period;		targ->last_tinfo.width = tinfo->curr.width;		targ->last_tinfo.offset = tinfo->curr.offset;		targ->last_tinfo.ppr_options = tinfo->curr.ppr_options;		printf("(%s:%c:", ahc_name(ahc), channel);		if (target == CAM_TARGET_WILDCARD)			printf("*): ");		else			printf("%d): ", target);		ahc_format_transinfo(&info, &tinfo->curr);		if (info.pos < info.length)			*info.buffer = '\0';		else			buf[info.length - 1] = '\0';		printf("%s", buf);		break;	}        case AC_SENT_BDR:		break;        case AC_BUS_RESET:#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)		if (ahc->platform_data->host != NULL) {			scsi_report_bus_reset(ahc->platform_data->host,					      channel - 'A');		}#endif                break;        default:                panic("ahc_send_async: Unexpected async event");        }}/* * Calls the higher level scsi done function and frees the scb. */voidahc_done(struct ahc_softc *ahc, struct scb * scb){	Scsi_Cmnd *cmd;	struct ahc_linux_device *dev;	LIST_REMOVE(scb, pending_links);	if ((scb->flags & SCB_UNTAGGEDQ) != 0) {		struct scb_tailq *untagged_q;		int target_offset;		target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);		untagged_q = &(ahc->untagged_queues[target_offset]);		TAILQ_REMOVE(untagged_q, scb, links.tqe);		ahc_run_untagged_queue(ahc, untagged_q);	}	if ((scb->flags & SCB_ACTIVE) == 0) {		printf("SCB %d done'd twice\n", scb->hscb->tag);		ahc_dump_card_state(ahc);		panic("Stopping for safety");	}	cmd = scb->io_ctx;	dev = scb->platform_data->dev;	dev->active--;	dev->openings++;	ahc_linux_unmap_scb(ahc, scb);	if (scb->flags & SCB_SENSE) {		memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb),		       MIN(sizeof(struct scsi_sense_data),			   sizeof(cmd->sense_buffer)));		cmd->result |= (DRIVER_SENSE << 24);	} else {		/*		 * Guard against stale sense data.		 * The Linux mid-layer assumes that sense		 * was retrieved anytime the first byte of		 * the sense buffer looks "sane".		 */		cmd->sense_buffer[0] = 0;	}	if (ahc_get_transaction_status(scb) == CAM_REQ_INPROG) {		uint32_t amount_xferred;		amount_xferred =		    ahc_get_transfer_length(scb) - ahc_get_residual(scb);		if (amount_xferred < scb->io_ctx->underflow) {			printf("Saw underflow (%ld of %ld bytes). "			       "Treated as error\n",				ahc_get_residual(scb),				ahc_get_transfer_length(scb));			ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);		} else {			ahc_set_transaction_status(scb, CAM_REQ_CMP);			ahc_linux_sniff_command(ahc, cmd, scb);		}	} else if (ahc_get_transaction_status(scb) == DID_OK) {		ahc_linux_handle_scsi_status(ahc, dev, scb);	} else if (ahc_get_transaction_status(scb) == DID_NO_CONNECT) {		/*		 * Should a selection timeout kill the device?		 * That depends on whether the selection timeout		 * is persistent.  Since we have no guarantee that		 * the mid-layer will issue an inquiry for this device		 * again, we can't just kill it off.		dev->flags |= AHC_DEV_UNCONFIGURED;		 */	}	if (dev->openings == 1	 && ahc_get_transaction_status(scb) == CAM_REQ_CMP	 && ahc_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL)		dev->tag_success_count++;	/*	 * Some devices deal with temporary internal resource	 * shortages by returning queue full.  When the queue	 * full occurrs, we throttle back.  Slowly try to get	 * back to our previous queue depth.	 */	if ((dev->openings + dev->active) < dev->maxtags	 && dev->tag_success_count > AHC_TAG_SUCCESS_INTERVAL) {		dev->tag_success_count = 0;		dev->openings++;	}	if (dev->active == 0)		dev->commands_since_idle_or_otag = 0;	if (TAILQ_EMPTY(&dev->busyq)) {		if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0		 && dev->active == 0)			ahc_linux_free_device(ahc, dev);	} else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {		TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links);		dev->flags |= AHC_DEV_ON_RUN_LIST;	}	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {		printf("Recovery SCB completes\n");		up(&ahc->platform_data->eh_sem);	}	ahc_free_scb(ahc, scb);	ahc_linux_queue_cmd_complete(ahc, cmd);}static voidahc_linux_handle_scsi_status(struct ahc_softc *ahc,			     struct ahc_linux_device *dev, struct scb *scb){	/*	 * We don't currently trust the mid-layer to	 * properly deal with queue full or busy.  So,	 * when one occurs, we tell the mid-layer to	 * unconditionally requeue the command to us	 * so that we can retry it ourselves.  We also	 * implement our own throttling mechanism so	 * we don't clobber the device with too many	 * commands.	 */	switch (ahc_get_scsi_status(scb)) {	default:		break;	case SCSI_STATUS_QUEUE_FULL:	{		/*		 * By the time the core driver has returned this		 * command, all other commands that were queued		 * to us but not the device have been returned.		 * This ensures that dev->active is equal to		 * the number of commands actually queued to		 * the device.		 */		dev->tag_success_count = 0;		if (dev->active != 0) {			/*			 * Drop our opening count to the number			 * of commands currently outstanding.			 */			dev->openings = 0;/*			ahc_print_path(ahc, scb);			printf("Dropping tag count to %d\n", dev->active); */			if (dev->active == dev->tags_on_last_queuefull) {				dev->last_queuefull_same_count++;				/*				 * If we repeatedly see a queue full				 * at the same queue depth, this				 * device has a fixed number of tag				 * slots.  Lock in this tag depth				 * so we stop seeing queue fulls from				 * this device.				 */				if (dev->last_queuefull_same_count				 == AHC_LOCK_TAGS_COUNT) {					dev->maxtags = dev->active;					ahc_print_path(ahc, scb);					printf("Locking max tag count at %d\n",					       dev->active);				}			} else {				dev->tags_on_last_queuefull = dev->active;				dev->last_queuefull_same_count = 0;			}			ahc_set_transaction_status(scb, CAM_REQUEUE_REQ);			ahc_set_scsi_status(scb, SCSI_STATUS_OK);			break;		}		/*		 * Drop down to a single opening, and treat this		 * as if the target return BUSY SCSI status.		 */		dev->openings = 1;		/* FALLTHROUGH */	}	case SCSI_STATUS_BUSY:	{		/*		 * Set a short timer to defer sending commands for		 * a bit since 

⌨️ 快捷键说明

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