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

📄 aic7xxx_linux.c

📁 自己根据lkd和情境分析
💻 C
📖 第 1 页 / 共 5 页
字号:
{	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));	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;	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		 && 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:		/*		 * XXX Set a timer and handle ourselves????		 * For now we pray that the mid-layer does something		 * sane for devices that are busy.		 */		ahc_set_scsi_status(scb, SCSI_STATUS_BUSY);		break;	}}static voidahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd, struct scb *scb){	switch (cmd->cmnd[0]) {	case INQUIRY:	{		struct	ahc_devinfo devinfo;		struct	scsi_inquiry *inq;		struct	scsi_inquiry_data *sid;		struct	ahc_initiator_tinfo *targ_info;		struct	ahc_tmode_tstate *tstate;		struct	ahc_syncrate *syncrate;		struct	ahc_linux_device *dev;		u_int	scsiid;		u_int	maxsync;		int	transferred_len;		int	minlen;		u_int	width;		u_int	period;		u_int	offset;		u_int	ppr_options;		 /*		  * Validate the command.  We only want to filter		  * standard inquiry commands, not those querying		  * Vital Product Data.		  */		inq = (struct scsi_inquiry *)cmd->cmnd;		if ((inq->byte2 & SI_EVPD) != 0		 || inq->page_code != 0)			break;		if (cmd->use_sg != 0) {			printf("%s: SG Inquiry response ignored\n",			       ahc_name(ahc));			break;		}		transferred_len = ahc_get_transfer_length(scb)				- ahc_get_residual(scb);		sid = (struct scsi_inquiry_data *)cmd->request_buffer;		/*		 * Determine if this lun actually exists.  If so,		 * hold on to its corresponding device structure.		 * If not, make sure we release the device and		 * don't bother processing the rest of this inquiry		 * command.		 */		dev = ahc_linux_get_device(ahc, cmd->channel,					   cmd->target, cmd->lun,					   /*alloc*/FALSE);		if (transferred_len >= 1		 && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) {			dev->flags &= ~AHC_DEV_UNCONFIGURED;		} else {			dev->flags |= AHC_DEV_UNCONFIGURED;			break;		}		/*		 * Update our notion of this device's transfer		 * negotiation capabilities.		 */		scsiid = BUILD_SCSIID(ahc, cmd);		ahc_compile_devinfo(&devinfo, SCSIID_OUR_ID(scsiid),				    cmd->target, cmd->lun,				    SCSIID_CHANNEL(ahc, scsiid),				    ROLE_INITIATOR);		targ_info = ahc_fetch_transinfo(ahc, devinfo.channel,						devinfo.our_scsiid,						devinfo.target, &tstate);		width = targ_info->user.width;		period = targ_info->user.period;		offset = targ_info->user.offset;		ppr_options = targ_info->user.ppr_options;		minlen = offsetof(struct scsi_inquiry_data, version) + 1;		if (transferred_len >= minlen) {			targ_info->curr.protocol_version = SID_ANSI_REV(sid);			/*			 * Only attempt SPI3 once we've verified that			 * the device claims to support SPI3 features.			 */			if (targ_info->curr.protocol_version < SCSI_REV_2)				targ_info->curr.transport_version =				    SID_ANSI_REV(sid);			else				targ_info->curr.transport_version =				     SCSI_REV_2;		}		minlen = offsetof(struct scsi_inquiry

⌨️ 快捷键说明

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