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

📄 bt.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	timeout = 5 * 10000;	while (--timeout) {		status = bt_inb(bt, STATUS_REG);		if ((status & DIAG_ACTIVE) != 0)			break;		DELAY(100);	}	if (timeout == 0) {		if (bootverbose)			printf("%s: btreset - Diagnostic Active failed to "				"assert. status = 0x%x\n", bt_name(bt), status);		return (ETIMEDOUT);	}	/* Wait 10sec. for Diagnostic end */	timeout = 10 * 10000;	while (--timeout) {		status = bt_inb(bt, STATUS_REG);		if ((status & DIAG_ACTIVE) == 0)			break;		DELAY(100);	}	if (timeout == 0) {		panic("%s: btreset - Diagnostic Active failed to drop. "		       "status = 0x%x\n", bt_name(bt), status);		return (ETIMEDOUT);	}	/* Wait for the host adapter to become ready or report a failure */	timeout = 10000;	while (--timeout) {		status = bt_inb(bt, STATUS_REG);		if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0)			break;		DELAY(100);	}	if (timeout == 0) {		printf("%s: btreset - Host adapter failed to come ready. "		       "status = 0x%x\n", bt_name(bt), status);		return (ETIMEDOUT);	}	/* If the diagnostics failed, tell the user */	if ((status & DIAG_FAIL) != 0	 || (status & HA_READY) == 0) {		printf("%s: btreset - Adapter failed diagnostics\n",		       bt_name(bt));		if ((status & DATAIN_REG_READY) != 0)			printf("%s: btreset - Host Adapter Error code = 0x%x\n",			       bt_name(bt), bt_inb(bt, DATAIN_REG));		return (ENXIO);	}	/* If we've allocated mailboxes, initialize them */	if (bt->init_level > 4)		btinitmboxes(bt);	/* If we've attached to the XPT, tell it about the event */	if (bt->path != NULL)		xpt_async(AC_BUS_RESET, bt->path, NULL);	/*	 * Perform completion processing for all outstanding CCBs.	 */	while ((ccb_h = LIST_FIRST(&bt->pending_ccbs)) != NULL) {		struct bt_ccb *pending_bccb;		pending_bccb = (struct bt_ccb *)ccb_h->ccb_bccb_ptr;		pending_bccb->hccb.btstat = BTSTAT_HA_SCSI_BUS_RESET;		btdone(bt, pending_bccb, BMBI_ERROR);	}	return (0);}/* * Send a command to the adapter. */intbt_cmd(struct bt_softc *bt, bt_op_t opcode, u_int8_t *params, u_int param_len,      u_int8_t *reply_data, u_int reply_len, u_int cmd_timeout){	u_int	timeout;	u_int	status;	u_int	saved_status;	u_int	intstat;	u_int	reply_buf_size;	int	s;	int	cmd_complete;	int	error;	/* No data returned to start */	reply_buf_size = reply_len;	reply_len = 0;	intstat = 0;	cmd_complete = 0;	saved_status = 0;	error = 0;	bt->command_cmp = 0;	/*	 * Wait up to 10 sec. for the adapter to become	 * ready to accept commands.	 */	timeout = 100000;	while (--timeout) {		status = bt_inb(bt, STATUS_REG);		if ((status & HA_READY) != 0		 && (status & CMD_REG_BUSY) == 0)			break;		/*		 * Throw away any pending data which may be		 * left over from earlier commands that we		 * timedout on.		 */		if ((status & DATAIN_REG_READY) != 0)			(void)bt_inb(bt, DATAIN_REG);		DELAY(100);	}	if (timeout == 0) {		printf("%s: bt_cmd: Timeout waiting for adapter ready, "		       "status = 0x%x\n", bt_name(bt), status);		return (ETIMEDOUT);	}	/*	 * Send the opcode followed by any necessary parameter bytes.	 */	bt_outb(bt, COMMAND_REG, opcode);	/*	 * Wait for up to 1sec for each byte of the the	 * parameter list sent to be sent.	 */	timeout = 10000;	while (param_len && --timeout) {		DELAY(100);		s = splcam();		status = bt_inb(bt, STATUS_REG);		intstat = bt_inb(bt, INTSTAT_REG);		splx(s);		if ((intstat & (INTR_PENDING|CMD_COMPLETE))		 == (INTR_PENDING|CMD_COMPLETE)) {			saved_status = status;			cmd_complete = 1;			break;		}		if (bt->command_cmp != 0) {			saved_status = bt->latched_status;			cmd_complete = 1;			break;		}		if ((status & DATAIN_REG_READY) != 0)			break;		if ((status & CMD_REG_BUSY) == 0) {			bt_outb(bt, COMMAND_REG, *params++);			param_len--;			timeout = 10000;		}	}	if (timeout == 0) {		printf("%s: bt_cmd: Timeout sending parameters, "		       "status = 0x%x\n", bt_name(bt), status);		cmd_complete = 1;		saved_status = status;		error = ETIMEDOUT;	}	/*	 * Wait for the command to complete.	 */	while (cmd_complete == 0 && --cmd_timeout) {		s = splcam();		status = bt_inb(bt, STATUS_REG);		intstat = bt_inb(bt, INTSTAT_REG);		splx(s);		if (bt->command_cmp != 0) { 			/*			 * Our interrupt handler saw CMD_COMPLETE			 * status before we did.			 */			cmd_complete = 1;			saved_status = bt->latched_status;		} else if ((intstat & (INTR_PENDING|CMD_COMPLETE))			== (INTR_PENDING|CMD_COMPLETE)) {			/*			 * Our poll (in case interrupts are blocked)			 * saw the CMD_COMPLETE interrupt.			 */			cmd_complete = 1;			saved_status = status;		} else if (opcode == BOP_MODIFY_IO_ADDR			&& (status & CMD_REG_BUSY) == 0) {			/*			 * The BOP_MODIFY_IO_ADDR does not issue a CMD_COMPLETE,			 * but it should update the status register.  So, we			 * consider this command complete when the CMD_REG_BUSY			 * status clears.			 */			saved_status = status;			cmd_complete = 1;		} else if ((status & DATAIN_REG_READY) != 0) {			u_int8_t data;			data = bt_inb(bt, DATAIN_REG);			if (reply_len < reply_buf_size) {				*reply_data++ = data;			} else {				printf("%s: bt_cmd - Discarded reply data byte "				       "for opcode 0x%x\n", bt_name(bt),				       opcode);			}			/*			 * Reset timeout to ensure at least a second			 * between response bytes.			 */			cmd_timeout = MAX(cmd_timeout, 10000);			reply_len++;		} else if ((opcode == BOP_FETCH_LRAM)			&& (status & HA_READY) != 0) {				saved_status = status;				cmd_complete = 1;		}		DELAY(100);	}	if (cmd_timeout == 0) {		printf("%s: bt_cmd: Timeout waiting for command (%x) "		       "to complete.\n%s: status = 0x%x, intstat = 0x%x, "		       "rlen %d\n", bt_name(bt), opcode, bt_name(bt),		       status, intstat, reply_len);		error = (ETIMEDOUT);	}	/*	 * Clear any pending interrupts.  Block interrupts so our	 * interrupt handler is not re-entered.	 */	s = splcam();	bt_intr(bt);	splx(s);		if (error != 0)		return (error);	/*	 * If the command was rejected by the controller, tell the caller.	 */	if ((saved_status & CMD_INVALID) != 0) {		/*		 * Some early adapters may not recover properly from		 * an invalid command.  If it appears that the controller		 * has wedged (i.e. status was not cleared by our interrupt		 * reset above), perform a soft reset.      		 */		if (bootverbose)			printf("%s: Invalid Command 0x%x\n", bt_name(bt), 				opcode);		DELAY(1000);		status = bt_inb(bt, STATUS_REG);		if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY|			      CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0		 || (status & (HA_READY|INIT_REQUIRED))		  != (HA_READY|INIT_REQUIRED)) {			btreset(bt, /*hard_reset*/FALSE);		}		return (EINVAL);	}	if (param_len > 0) {		/* The controller did not accept the full argument list */	 	return (E2BIG);	}	if (reply_len != reply_buf_size) {		/* Too much or too little data received */		return (EMSGSIZE);	}	/* We were successful */	return (0);}static intbtinitmboxes(struct bt_softc *bt) {	init_32b_mbox_params_t init_mbox;	int error;	bzero(bt->in_boxes, sizeof(bt_mbox_in_t) * bt->num_boxes);	bzero(bt->out_boxes, sizeof(bt_mbox_out_t) * bt->num_boxes);	bt->cur_inbox = bt->in_boxes;	bt->last_inbox = bt->in_boxes + bt->num_boxes - 1;	bt->cur_outbox = bt->out_boxes;	bt->last_outbox = bt->out_boxes + bt->num_boxes - 1;	/* Tell the adapter about them */	init_mbox.num_boxes = bt->num_boxes;	init_mbox.base_addr[0] = bt->mailbox_physbase & 0xFF;	init_mbox.base_addr[1] = (bt->mailbox_physbase >> 8) & 0xFF;	init_mbox.base_addr[2] = (bt->mailbox_physbase >> 16) & 0xFF;	init_mbox.base_addr[3] = (bt->mailbox_physbase >> 24) & 0xFF;	error = bt_cmd(bt, BOP_INITIALIZE_32BMBOX, (u_int8_t *)&init_mbox,		       /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL,		       /*reply_len*/0, DEFAULT_CMD_TIMEOUT);	if (error != 0)		printf("btinitmboxes: Initialization command failed\n");	else if (bt->strict_rr != 0) {		/*		 * If the controller supports		 * strict round robin mode,		 * enable it		 */		u_int8_t param;		param = 0;		error = bt_cmd(bt, BOP_ENABLE_STRICT_RR, &param, 1,			       /*reply_buf*/NULL, /*reply_len*/0,			       DEFAULT_CMD_TIMEOUT);		if (error != 0) {			printf("btinitmboxes: Unable to enable strict RR\n");			error = 0;		} else if (bootverbose) {			printf("%s: Using Strict Round Robin Mailbox Mode\n",			       bt_name(bt));		}	}		return (error);}/* * Update the XPT's idea of the negotiated transfer * parameters for a particular target. */static voidbtfetchtransinfo(struct bt_softc *bt, struct ccb_trans_settings* cts){	setup_data_t	setup_info;	u_int		target;	u_int		targ_offset;	u_int		targ_mask;	u_int		sync_period;	int		error;	u_int8_t	param;	targ_syncinfo_t	sync_info;	target = cts->ccb_h.target_id;	targ_offset = (target & 0x7);	targ_mask = (0x01 << targ_offset);	/*	 * Inquire Setup Information.  This command retreives the	 * Wide negotiation status for recent adapters as well as	 * the sync info for older models.	 */	param = sizeof(setup_info);	error = bt_cmd(bt, BOP_INQUIRE_SETUP_INFO, &param, /*paramlen*/1,		       (u_int8_t*)&setup_info, sizeof(setup_info),		       DEFAULT_CMD_TIMEOUT);	if (error != 0) {		printf("%s: btfetchtransinfo - Inquire Setup Info Failed %x\n",		       bt_name(bt), error);		cts->valid = 0;		return;	}	sync_info = (target < 8) ? setup_info.low_syncinfo[targ_offset]				 : setup_info.high_syncinfo[targ_offset];	if (sync_info.sync == 0)		cts->sync_offset = 0;	else		cts->sync_offset = sync_info.offset;	cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;	if (strcmp(bt->firmware_ver, "5.06L") >= 0) {		u_int wide_active;		wide_active =		    (target < 8) ? (setup_info.low_wide_active & targ_mask)		    		 : (setup_info.high_wide_active & targ_mask);		if (wide_active)			cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;	} else if ((bt->wide_permitted & targ_mask) != 0) {		struct ccb_getdev cgd;		/*		 * Prior to rev 5.06L, wide status isn't provided,		 * so we "guess" that wide transfers are in effect		 * if the user settings allow for wide and the inquiry		 * data for the device indicates that it can handle		 * wide transfers.		 */		xpt_setup_ccb(&cgd.ccb_h, cts->ccb_h.path, /*priority*/1);		cgd.ccb_h.func_code = XPT_GDEV_TYPE;		xpt_action((union ccb *)&cgd);		if ((cgd.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP		 && (cgd.inq_data.flags & SID_WBus16) != 0)			cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT;	}	if (bt->firmware_ver[0] >= '3') {		/*		 * For adapters that can do fast or ultra speeds,		 * use the more exact Target Sync Information command.		 */		target_sync_info_data_t sync_info;		param = sizeof(sync_info);		error = bt_cmd(bt, BOP_TARG_SYNC_INFO, &param, /*paramlen*/1,			       (u_int8_t*)&sync_info, sizeof(sync_info),			       DEFAULT_CMD_TIMEOUT);				if (error != 0) {			printf("%s: btfetchtransinfo - Inquire Sync "			       "Info Failed 0x%x\n", bt_name(bt), error);			cts->valid = 0;			return;		}		sync_period = sync_info.sync_rate[target] * 100;	} else {		sync_period = 2000 + (500 * sync_info.period);	}	/* Convert ns value to standard SCSI sync rate */	if (cts->sync_offset != 0)		cts->sync_period = scsi_calc_syncparam(sync_period);	else		cts->sync_period = 0;		cts->valid = CCB_TRANS_SYNC_RATE_VALID		   | CCB_TRANS_SYNC_OFFSET_VALID		   | CCB_TRANS_BUS_WIDTH_VALID;        xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts);}static voidbtmapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error){	struct bt_softc* bt;	bt = (struct bt_softc*)arg;	bt->mailbox_physbase = segs->ds_addr;}static voidbtmapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error){	struct bt_softc* bt;	bt = (struct bt_softc*)arg;	bt->bt_ccb_physbase = segs->ds_addr;}static voidbtmapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error){	struct bt_softc* bt;	bt = (struct bt_softc*)arg;	SLIST_FIRST(&bt->sg_maps)->sg_physaddr = segs->ds_addr;}static voidbtpoll(struct cam_sim *sim){	bt_intr(cam_sim_softc(sim));}voidbttimeout(void *arg){	struct bt_ccb	*bccb;	union  ccb	*ccb;	struct bt_softc *bt;	int		 s;	bccb = (struct bt_ccb *)arg;	ccb = bccb->ccb;	bt = (struct bt_softc *)ccb->ccb_h.ccb_bt_ptr;	xpt_print_path(ccb->ccb_h.path);	printf("CCB %p - timed out\n", (void *)bccb);	s = splcam();	if ((bccb->flags & BCCB_ACTIVE) == 0) {		xpt_print_path(ccb->ccb_h.path);		printf("CCB %p - timed out CCB already completed\n",		       (void *)bccb);		splx(s);		return;	}	/*	 * In order to simplify the recovery process, we ask the XPT	 * layer to halt the queue of new transactions and we traverse	 * the list of pending CCBs and remove their timeouts. This	 * means that the driver attempts to clear only one error	 * condition at a time.  In general, timeouts that occur	 * close together are related anyway, so there is no benefit	 * in attempting to handle errors in parrallel.  Timeouts will	 * be reinstated when the recovery process ends.	 */	if ((bccb->flags & BCCB_DEVICE_RESET) == 0) {		struct ccb_hdr *ccb_h;		if ((bccb->flags & BCCB_RELEASE_SIMQ) == 0) {			xpt_freeze_simq(bt->sim, /*count*/1);			bccb->flags |= BCCB_RELEASE_SIMQ;		}		ccb_h = LIST_FIRST(&bt->pending_ccbs);		while (ccb_h != NULL) {			struct bt_ccb *pending_bccb;			pending_bccb = (struct bt_ccb *)ccb_h->ccb_bccb_ptr;			untimeout(bttimeout, pending_bccb, ccb_h->timeout_ch);			ccb_h = LIST_NEXT(ccb_h, sim_links.le);		}	}	if ((bccb->flags & BCCB_DEVICE_RESET) != 0	 || bt->cur_outbox->action_code != BMBO_FREE	 || ((bccb->hccb.tag_enable == TRUE)	  && (bt->firmware_ver[0] < '5'))) {		/*		 * Try a full host adapter/SCSI bus reset.		 * We do this only if we have already attempted		 * to clear the condition with a BDR, or we cannot		 * attempt a BDR for lack of mailbox resources		 * or because of faulty firmware.  It turns out		 * that firmware versions prior to 5.xx treat BDRs		 * as untagged commands that cannot be sent until		 * all outstanding tagged commands have been processed.		 * This makes it somewhat difficult to use a BDR to		 * clear up a problem with an uncompleted tagged command.		 */		ccb->ccb_h.status = CAM_CMD_TIMEOUT;		btreset(bt, /*hardreset*/TRUE);		printf("%s: No longer in timeout\n", bt_name(bt));	} else {		/*    		 * Send a Bus Device Reset message:		 * The target that is holding up the bus may not		 * be the same as the one that triggered this timeout		 * (different commands have different timeout lengths),		 * but we have no way of determining this from our		 * timeout handler.  Our strategy here is to queue a		 * BDR message to the target of the timed out command.		 * If this fails, we'll get another timeout 2 seconds		 * later which will attempt a bus reset.		 */		bccb->flags |= BCCB_DEVICE_RESET;		ccb->ccb_h.timeout_ch =		    timeout(bttimeout, (caddr_t)bccb, 2 * hz);		bt->recovery_bccb->hccb.opcode = INITIATOR_BUS_DEV_RESET;		/* No Data Transfer */		bt->recovery_bccb->hccb.datain = TRUE;		bt->recovery_bccb->hccb.dataout = TRUE;		bt->recovery_bccb->hccb.btstat = 0;		bt->recovery_bccb->hccb.sdstat = 0;		bt->recovery_bccb->hccb.target_id = ccb->ccb_h.target_id;		/* Tell the adapter about this command */		bt->cur_outbox->ccb_addr = btccbvtop(bt, bt->recovery_bccb);		bt->cur_outbox->action_code = BMBO_START;		bt_outb(bt, COMMAND_REG, BOP_START_MBOX);		btnextoutbox(bt);	}	splx(s);}

⌨️ 快捷键说明

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