Beispiel #1
0
static u_int16_t
pcibios_get_version(void)
{
	struct bios_regs args;

	if (PCIbios.ventry == 0) {
		PRVERB(("pcibios: No call entry point\n"));
		return (0);
	}
	args.eax = PCIBIOS_BIOS_PRESENT;
	if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
		PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
		return (0);
	}
	if (args.edx != 0x20494350) {
		PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
		return (0);
	}
	return (args.ebx & 0xffff);
}
Beispiel #2
0
/*
 * Probe the adapter and verify that the card is an Adaptec.
 */
int
aha_probe(struct aha_softc* aha)
{
	u_int	 status;
	u_int	 intstat;
	int	 error;
	board_id_data_t	board_id;

	/*
	 * See if the three I/O ports look reasonable.
	 * Touch the minimal number of registers in the
	 * failure case.
	 */
	status = aha_inb(aha, STATUS_REG);
	if ((status == 0) ||
	    (status & (DIAG_ACTIVE|CMD_REG_BUSY | STATUS_REG_RSVD)) != 0) {
		PRVERB((aha->dev, "status reg test failed %x\n", status));
		return (ENXIO);
	}

	intstat = aha_inb(aha, INTSTAT_REG);
	if ((intstat & INTSTAT_REG_RSVD) != 0) {
		PRVERB((aha->dev, "Failed Intstat Reg Test\n"));
		return (ENXIO);
	}

	/*
	 * Looking good so far.  Final test is to reset the
	 * adapter and fetch the board ID and ensure we aren't
	 * looking at a BusLogic.
	 */
	if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) {
		PRVERB((aha->dev, "Failed Reset\n"));
		return (ENXIO);
	}

	/*
	 * Get the board ID.  We use this to see if we're dealing with
	 * a buslogic card or an aha card (or clone).
	 */
	error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0,
	    (uint8_t*)&board_id, sizeof(board_id), DEFAULT_CMD_TIMEOUT);
	if (error != 0) {
		PRVERB((aha->dev, "INQUIRE failed %x\n", error));
		return (ENXIO);
	}
	aha->fw_major = board_id.firmware_rev_major;
	aha->fw_minor = board_id.firmware_rev_minor;
	aha->boardid = board_id.board_type;

	/*
	 * The Buslogic cards have an id of either 0x41 or 0x42.  So
	 * if those come up in the probe, we test the geometry register
	 * of the board.  Adaptec boards that are this old will not have
	 * this register, and return 0xff, while buslogic cards will return
	 * something different.
	 *
	 * It appears that for reasons unknow, for the for the
	 * aha-1542B cards, we need to wait a little bit before trying
	 * to read the geometry register.  I picked 10ms since we have
	 * reports that a for loop to 1000 did the trick, and this
	 * errs on the side of conservatism.  Besides, no one will
	 * notice a 10mS delay here, even the 1542B card users :-)
	 *
	 * Some compatible cards return 0 here.  Some cards also
	 * seem to return 0x7f.
	 *
	 * XXX I'm not sure how this will impact other cloned cards
	 *
	 * This really should be replaced with the esetup command, since
	 * that appears to be more reliable.  This becomes more and more
	 * true over time as we discover more cards that don't read the
	 * geometry register consistently.
	 */
	if (aha->boardid <= 0x42) {
		/* Wait 10ms before reading */
		DELAY(10000);
		status = aha_inb(aha, GEOMETRY_REG);
		if (status != 0xff && status != 0x00 && status != 0x7f) {
			PRVERB((aha->dev, "Geometry Register test failed %#x\n",
				status));
			return (ENXIO);
		}
	}

	return (0);
}
Beispiel #3
0
/*
 * Send a command to the adapter.
 */
int
aha_cmd(struct aha_softc *aha, aha_op_t opcode, uint8_t *params,
	u_int param_len, uint8_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	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;

	/*
	 * All commands except for the "start mailbox" and the "enable
	 * outgoing mailbox read interrupt" commands cannot be issued
	 * while there are pending transactions.  Freeze our SIMQ
	 * and wait for all completions to occur if necessary.
	 */
	timeout = 10000;
	while (LIST_FIRST(&aha->pending_ccbs) != NULL && --timeout) {
		/* Fire the interrupt handler in case interrupts are blocked */
		aha_intr(aha);
		DELAY(10);
	}

	if (timeout == 0) {
		device_printf(aha->dev, 
		    "aha_cmd: Timeout waiting for adapter idle\n");
		return (ETIMEDOUT);
	}
	aha->command_cmp = 0;
	/*
	 * Wait up to 10 sec. for the adapter to become
	 * ready to accept commands.
	 */
	timeout = 100000;
	while (--timeout) {
		status = aha_inb(aha, 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)aha_inb(aha, DATAIN_REG);
		DELAY(100);
	}
	if (timeout == 0) {
		device_printf(aha->dev, "aha_cmd: Timeout waiting for adapter"
		    " ready, status = 0x%x\n", status);
		return (ETIMEDOUT);
	}

	/*
	 * Send the opcode followed by any necessary parameter bytes.
	 */
	aha_outb(aha, COMMAND_REG, opcode);

	/*
	 * Wait for up to 1sec to get the parameter list sent
	 */
	timeout = 10000;
	while (param_len && --timeout) {
		DELAY(100);
		status = aha_inb(aha, STATUS_REG);
		intstat = aha_inb(aha, INTSTAT_REG);

		if ((intstat & (INTR_PENDING|CMD_COMPLETE))
		 == (INTR_PENDING|CMD_COMPLETE)) {
			saved_status = status;
			cmd_complete = 1;
			break;
		}

		if (aha->command_cmp != 0) {
			saved_status = aha->latched_status;
			cmd_complete = 1;
			break;
		}
		if ((status & DATAIN_REG_READY) != 0)
			break;
		if ((status & CMD_REG_BUSY) == 0) {
			aha_outb(aha, COMMAND_REG, *params++);
			param_len--;
			timeout = 10000;
		}
	}
	if (timeout == 0) {
		device_printf(aha->dev, "aha_cmd: Timeout sending parameters, "
		    "status = 0x%x\n", status);
		error = ETIMEDOUT;
	}

	/*
	 * For all other commands, we wait for any output data
	 * and the final comand completion interrupt.
	 */
	while (cmd_complete == 0 && --cmd_timeout) {

		status = aha_inb(aha, STATUS_REG);
		intstat = aha_inb(aha, INTSTAT_REG);

		if (aha->command_cmp != 0) {
			cmd_complete = 1;
			saved_status = aha->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;
		}
		if ((status & DATAIN_REG_READY) != 0) {
			uint8_t data;

			data = aha_inb(aha, DATAIN_REG);
			if (reply_len < reply_buf_size) {
				*reply_data++ = data;
			} else {
				device_printf(aha->dev, 
				    "aha_cmd - Discarded reply data "
				    "byte for opcode 0x%x\n", opcode);
			}
			/*
			 * Reset timeout to ensure at least a second
			 * between response bytes.
			 */
			cmd_timeout = MAX(cmd_timeout, 10000);
			reply_len++;
		}
		DELAY(100);
	}
	if (cmd_timeout == 0) {
		device_printf(aha->dev, "aha_cmd: Timeout: status = 0x%x, "
		    "intstat = 0x%x, reply_len = %d\n", status, intstat,
		    reply_len);
		return (ETIMEDOUT);
	}

	/*
	 * Clear any pending interrupts.  Block interrupts so our
	 * interrupt handler is not re-entered.
	 */
	aha_intr(aha);

	if (error != 0)
		return (error);

	/*
	 * If the command was rejected by the controller, tell the caller.
	 */
	if ((saved_status & CMD_INVALID) != 0) {
		PRVERB((aha->dev, "Invalid Command 0x%x\n", opcode));
		/*
		 * 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.
      		 */
		DELAY(1000);
		status = aha_inb(aha, 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))
			ahareset(aha, /*hard_reset*/FALSE);
		return (EINVAL);
	}

	if (param_len > 0) {
		/* The controller did not accept the full argument list */
		PRVERB((aha->dev, "Controller did not accept full argument "
		    "list (%d > 0)\n", param_len));
	 	return (E2BIG);
	}

	if (reply_len != reply_buf_size) {
		/* Too much or too little data received */
		PRVERB((aha->dev, "data received mismatch (%d != %d)\n",
		    reply_len, reply_buf_size));
		return (EMSGSIZE);
	}

	/* We were successful */
	return (0);
}
Beispiel #4
0
static int
ahareset(struct aha_softc* aha, int hard_reset)
{
	struct	 ccb_hdr *ccb_h;
	u_int	 status;
	u_int	 timeout;
	uint8_t reset_type;

	if (hard_reset != 0)
		reset_type = HARD_RESET;
	else
		reset_type = SOFT_RESET;
	aha_outb(aha, CONTROL_REG, reset_type);

	/* Wait 5sec. for Diagnostic start */
	timeout = 5 * 10000;
	while (--timeout) {
		status = aha_inb(aha, STATUS_REG);
		if ((status & DIAG_ACTIVE) != 0)
			break;
		DELAY(100);
	}
	if (timeout == 0) {
		PRVERB((aha->dev, "ahareset - Diagnostic Active failed to "
		    "assert. status = %#x\n", status));
		return (ETIMEDOUT);
	}

	/* Wait 10sec. for Diagnostic end */
	timeout = 10 * 10000;
	while (--timeout) {
		status = aha_inb(aha, STATUS_REG);
		if ((status & DIAG_ACTIVE) == 0)
			break;
		DELAY(100);
	}
	if (timeout == 0) {
		panic("%s: ahareset - Diagnostic Active failed to drop. "
		    "status = 0x%x\n", aha_name(aha), status);
		return (ETIMEDOUT);
	}

	/* Wait for the host adapter to become ready or report a failure */
	timeout = 10000;
	while (--timeout) {
		status = aha_inb(aha, STATUS_REG);
		if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0)
			break;
		DELAY(100);
	}
	if (timeout == 0) {
		device_printf(aha->dev, "ahareset - Host adapter failed to "
		    "come ready. status = 0x%x\n", status);
		return (ETIMEDOUT);
	}

	/* If the diagnostics failed, tell the user */
	if ((status & DIAG_FAIL) != 0
	 || (status & HA_READY) == 0) {
		device_printf(aha->dev, "ahareset - Adapter failed diag\n");

		if ((status & DATAIN_REG_READY) != 0)
			device_printf(aha->dev, "ahareset - Host Adapter "
			    "Error code = 0x%x\n", aha_inb(aha, DATAIN_REG));
		return (ENXIO);
	}

	/* If we've attached to the XPT, tell it about the event */
	if (aha->path != NULL)
		xpt_async(AC_BUS_RESET, aha->path, NULL);

	/*
	 * Perform completion processing for all outstanding CCBs.
	 */
	while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) {
		struct aha_ccb *pending_accb;

		pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
		pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET;
		ahadone(aha, pending_accb, AMBI_ERROR);
	}

	/* If we've allocated mailboxes, initialize them */
	/* Must be done after we've aborted our queue, or aha_cmd fails */
	if (aha->init_level > 4)
		ahainitmboxes(aha);

	return (0);
}