示例#1
0
static int
smic_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
{
	u_char *cp, data;
	int i, state;

	/* First, start the message with the address. */
	if (!smic_start_write(sc, req->ir_addr))
		return (0);
#ifdef SMIC_DEBUG
	device_printf(sc->ipmi_dev, "SMIC: WRITE_START address: %02x\n",
	    req->ir_addr);
#endif

	if (req->ir_requestlen == 0) {
		/* Send the command as the last byte. */
		if (!smic_write_last(sc, req->ir_command))
			return (0);
#ifdef SMIC_DEBUG
		device_printf(sc->ipmi_dev, "SMIC: Wrote command: %02x\n",
		    req->ir_command);
#endif
	} else {
		/* Send the command. */
		if (!smic_write_next(sc, req->ir_command))
			return (0);
#ifdef SMIC_DEBUG
		device_printf(sc->ipmi_dev, "SMIC: Wrote command: %02x\n",
		    req->ir_command);
#endif

		/* Send the payload. */
		cp = req->ir_request;
		for (i = 0; i < req->ir_requestlen - 1; i++) {
			if (!smic_write_next(sc, *cp++))
				return (0);
#ifdef SMIC_DEBUG
			device_printf(sc->ipmi_dev, "SMIC: Wrote data: %02x\n",
			    cp[-1]);
#endif
		}
		if (!smic_write_last(sc, *cp))
			return (0);
#ifdef SMIC_DEBUG
		device_printf(sc->ipmi_dev, "SMIC: Write last data: %02x\n",
		    *cp);
#endif
	}

	/* Start the read phase by reading the NetFn/LUN. */
	if (smic_start_read(sc, &data) != 1)
		return (0);
#ifdef SMIC_DEBUG
	device_printf(sc->ipmi_dev, "SMIC: Read address: %02x\n", data);
#endif
	if (data != IPMI_REPLY_ADDR(req->ir_addr)) {
		device_printf(sc->ipmi_dev, "SMIC: Reply address mismatch\n");
		return (0);
	}

	/* Read the command. */
	if (smic_read_byte(sc, &data) != 1)
		return (0);
#ifdef SMIC_DEBUG
	device_printf(sc->ipmi_dev, "SMIC: Read command: %02x\n", data);
#endif
	if (data != req->ir_command) {
		device_printf(sc->ipmi_dev, "SMIC: Command mismatch\n");
		return (0);
	}

	/* Read the completion code. */
	state = smic_read_byte(sc, &req->ir_compcode);
	if (state == 0)
		return (0);
#ifdef SMIC_DEBUG
	device_printf(sc->ipmi_dev, "SMIC: Read completion code: %02x\n",
	    req->ir_compcode);
#endif

	/* Finally, read the reply from the BMC. */
	i = 0;
	while (state == 1) {
		state = smic_read_byte(sc, &data);
		if (state == 0)
			return (0);
		if (i < req->ir_replybuflen) {
			req->ir_reply[i] = data;
#ifdef SMIC_DEBUG
			device_printf(sc->ipmi_dev, "SMIC: Read data: %02x\n",
			    data);
		} else {
			device_printf(sc->ipmi_dev,
			    "SMIC: Read short %02x byte %d\n", data, i + 1);
#endif
		}
		i++;
	}

	/* Terminate the transfer. */
	if (!smic_read_end(sc))
		return (0);
	req->ir_replylen = i;
#ifdef SMIC_DEBUG
	device_printf(sc->ipmi_dev, "SMIC: READ finished (%d bytes)\n", i);
	if (req->ir_replybuflen < i)
#else
	if (req->ir_replybuflen < i && req->ir_replybuflen != 0)
#endif
		device_printf(sc->ipmi_dev,
		    "SMIC: Read short: %zd buffer, %d actual\n",
		    req->ir_replybuflen, i);
	return (1);
}
示例#2
0
static int
ssif_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
{
	u_char ssif_buf[SMBUS_DATA_SIZE];
	device_t dev = sc->ipmi_dev;
	device_t smbus = sc->ipmi_ssif_smbus;
	u_char *cp, block, count, offset;
	size_t len;
	int error;

	/* Acquire the bus while we send the request. */
	if (smbus_request_bus(smbus, dev, SMB_WAIT) != 0)
		return (0);

	/*
	 * First, send out the request.  Begin by filling out the first
	 * packet which includes the NetFn/LUN and command.
	 */
	ssif_buf[0] = req->ir_addr;
	ssif_buf[1] = req->ir_command;
	if (req->ir_requestlen > 0)
		bcopy(req->ir_request, &ssif_buf[2],
		    min(req->ir_requestlen, SMBUS_DATA_SIZE - 2));

	/* Small requests are sent with a single command. */
	if (req->ir_requestlen <= 30) {
#ifdef SSIF_DEBUG
		dump_buffer(dev, "WRITE_SINGLE", ssif_buf,
		    req->ir_requestlen + 2);
#endif
		error = smbus_error(smbus_bwrite(smbus,
			sc->ipmi_ssif_smbus_address, SMBUS_WRITE_SINGLE,
			req->ir_requestlen + 2, ssif_buf));
		if (error) {
#ifdef SSIF_ERROR_DEBUG
			device_printf(dev, "SSIF: WRITE_SINGLE error %d\n",
			    error);
#endif
			goto fail;
		}
	} else {
		/* Longer requests are sent out in 32-byte messages. */
#ifdef SSIF_DEBUG
		dump_buffer(dev, "WRITE_START", ssif_buf, SMBUS_DATA_SIZE);
#endif
		error = smbus_error(smbus_bwrite(smbus,
			sc->ipmi_ssif_smbus_address, SMBUS_WRITE_START,
			SMBUS_DATA_SIZE, ssif_buf));
		if (error) {
#ifdef SSIF_ERROR_DEBUG
			device_printf(dev, "SSIF: WRITE_START error %d\n",
			    error);
#endif
			goto fail;
		}

		len = req->ir_requestlen - (SMBUS_DATA_SIZE - 2);
		cp = req->ir_request + (SMBUS_DATA_SIZE - 2);
		while (len > 0) {
#ifdef SSIF_DEBUG
			dump_buffer(dev, "WRITE_CONT", cp,
			    min(len, SMBUS_DATA_SIZE));
#endif
			error = smbus_error(smbus_bwrite(smbus,
			    sc->ipmi_ssif_smbus_address, SMBUS_WRITE_CONT,
			    min(len, SMBUS_DATA_SIZE), cp));
			if (error) {
#ifdef SSIF_ERROR_DEBUG
				device_printf(dev, "SSIF: WRITE_CONT error %d\n",
				    error);
#endif
				goto fail;
			}
			cp += SMBUS_DATA_SIZE;
			len -= SMBUS_DATA_SIZE;
		}

		/*
		 * The final WRITE_CONT transaction has to have a non-zero
		 * length that is also not SMBUS_DATA_SIZE.  If our last
		 * WRITE_CONT transaction in the loop sent SMBUS_DATA_SIZE
		 * bytes, then len will be 0, and we send an extra 0x00 byte
		 * to terminate the transaction.
		 */
		if (len == 0) {
			char c = 0;

#ifdef SSIF_DEBUG
			dump_buffer(dev, "WRITE_CONT", &c, 1);
#endif
			error = smbus_error(smbus_bwrite(smbus,
				sc->ipmi_ssif_smbus_address, SMBUS_WRITE_CONT,
				1, &c));
			if (error) {
#ifdef SSIF_ERROR_DEBUG
				device_printf(dev, "SSIF: WRITE_CONT error %d\n",
				    error);
#endif
				goto fail;
			}
		}
	}

	/* Release the bus. */
	smbus_release_bus(smbus, dev);

	/* Give the BMC 100ms to chew on the request. */
	pause("ssifwt", hz / 10);

	/* Try to read the first packet. */
read_start:
	if (smbus_request_bus(smbus, dev, SMB_WAIT) != 0)
		return (0);
	count = SMBUS_DATA_SIZE;
	error = smbus_error(smbus_bread(smbus,
	    sc->ipmi_ssif_smbus_address, SMBUS_READ_START, &count, ssif_buf));
	if (error == ENXIO || error == EBUSY) {
		smbus_release_bus(smbus, dev);
#ifdef SSIF_DEBUG
		device_printf(dev, "SSIF: READ_START retry\n");
#endif
		/* Give the BMC another 10ms. */
		pause("ssifwt", hz / 100);
		goto read_start;
	}
	if (error) {
#ifdef SSIF_ERROR_DEBUG
		device_printf(dev, "SSIF: READ_START failed: %d\n", error);
#endif
		goto fail;
	}
#ifdef SSIF_DEBUG
	device_printf("SSIF: READ_START: ok\n");
#endif

	/*
	 * If this is the first part of a multi-part read, then we need to
	 * skip the first two bytes.
	 */
	if (count == SMBUS_DATA_SIZE && ssif_buf[0] == 0 && ssif_buf[1] == 1)
		offset = 2;
	else
		offset = 0;

	/* We had better get the reply header. */
	if (count < 3) {
		device_printf(dev, "SSIF: Short reply packet\n");
		goto fail;
	}

	/* Verify the NetFn/LUN. */
	if (ssif_buf[offset] != IPMI_REPLY_ADDR(req->ir_addr)) {
		device_printf(dev, "SSIF: Reply address mismatch\n");
		goto fail;
	}

	/* Verify the command. */
	if (ssif_buf[offset + 1] != req->ir_command) {
		device_printf(dev, "SMIC: Command mismatch\n");
		goto fail;
	}

	/* Read the completion code. */
	req->ir_compcode = ssif_buf[offset + 2];

	/* If this is a single read, just copy the data and return. */
	if (offset == 0) {
#ifdef SSIF_DEBUG
		dump_buffer(dev, "READ_SINGLE", ssif_buf, count);
#endif
		len = count - 3;
		bcopy(&ssif_buf[3], req->ir_reply,
		    min(req->ir_replybuflen, len));
		goto done;
	}

	/*
	 * This is the first part of a multi-read transaction, so copy
	 * out the payload and start looping.
	 */
#ifdef SSIF_DEBUG
	dump_buffer(dev, "READ_START", ssif_buf + 2, count - 2);
#endif
	bcopy(&ssif_buf[5], req->ir_reply, min(req->ir_replybuflen, count - 5));
	len = count - 5;
	block = 1;

	for (;;) {
		/* Read another packet via READ_CONT. */
		count = SMBUS_DATA_SIZE;
		error = smbus_error(smbus_bread(smbus,
		    sc->ipmi_ssif_smbus_address, SMBUS_READ_CONT, &count,
		    ssif_buf));
		if (error) {
#ifdef SSIF_ERROR_DEBUG
			printf("SSIF: READ_CONT failed: %d\n", error);
#endif
			goto fail;
		}
#ifdef SSIF_DEBUG
		device_printf(dev, "SSIF: READ_CONT... ok\n");
#endif

		/* Verify the block number.  0xff marks the last block. */
		if (ssif_buf[0] != 0xff && ssif_buf[0] != block) {
			device_printf(dev, "SSIF: Read wrong block %d %d\n",
			    ssif_buf[0], block);
			goto fail;
		}
		if (ssif_buf[0] != 0xff && count < SMBUS_DATA_SIZE) {
			device_printf(dev,
			    "SSIF: Read short middle block, length %d\n",
			    count);
			goto fail;
		}
#ifdef SSIF_DEBUG
		if (ssif_buf[0] == 0xff)
			dump_buffer(dev, "READ_END", ssif_buf + 1, count - 1);
		else
			dump_buffer(dev, "READ_CONT", ssif_buf + 1, count - 1);
#endif
		if (len < req->ir_replybuflen)
			bcopy(&ssif_buf[1], &req->ir_reply[len],
			    min(req->ir_replybuflen - len, count - 1));
		len += count - 1;

		/* If this was the last block we are done. */
		if (ssif_buf[0] != 0xff)
			break;
		block++;
	}

done:
	/* Save the total length and return success. */
	req->ir_replylen = len;
	smbus_release_bus(smbus, dev);
	return (1);

fail:
	smbus_release_bus(smbus, dev);
	return (0);
}
示例#3
0
文件: ipmi_kcs.c 项目: coyizumi/cs111
/*
 * Send a request message and collect the reply.  Returns true if we
 * succeed.
 */
static int
kcs_polled_request(struct ipmi_softc *sc, struct ipmi_request *req)
{
	u_char *cp, data;
	int i, state;

	IPMI_IO_LOCK(sc);

	/* Send the request. */
	if (!kcs_start_write(sc)) {
		device_printf(sc->ipmi_dev, "KCS: Failed to start write\n");
		goto fail;
	}
#ifdef KCS_DEBUG
	device_printf(sc->ipmi_dev, "KCS: WRITE_START... ok\n");
#endif

	if (!kcs_write_byte(sc, req->ir_addr)) {
		device_printf(sc->ipmi_dev, "KCS: Failed to write address\n");
		goto fail;
	}
#ifdef KCS_DEBUG
	device_printf(sc->ipmi_dev, "KCS: Wrote address: %02x\n", req->ir_addr);
#endif

	if (req->ir_requestlen == 0) {
		if (!kcs_write_last_byte(sc, req->ir_command)) {
			device_printf(sc->ipmi_dev,
			    "KCS: Failed to write command\n");
			goto fail;
		}
#ifdef KCS_DEBUG
		device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n",
		    req->ir_command);
#endif
	} else {
		if (!kcs_write_byte(sc, req->ir_command)) {
			device_printf(sc->ipmi_dev,
			    "KCS: Failed to write command\n");
			goto fail;
		}
#ifdef KCS_DEBUG
		device_printf(sc->ipmi_dev, "KCS: Wrote command: %02x\n",
		    req->ir_command);
#endif

		cp = req->ir_request;
		for (i = 0; i < req->ir_requestlen - 1; i++) {
			if (!kcs_write_byte(sc, *cp++)) {
				device_printf(sc->ipmi_dev,
				    "KCS: Failed to write data byte %d\n",
				    i + 1);
				goto fail;
			}
#ifdef KCS_DEBUG
			device_printf(sc->ipmi_dev, "KCS: Wrote data: %02x\n",
			    cp[-1]);
#endif
		}

		if (!kcs_write_last_byte(sc, *cp)) {
			device_printf(sc->ipmi_dev,
			    "KCS: Failed to write last dta byte\n");
			goto fail;
		}
#ifdef KCS_DEBUG
		device_printf(sc->ipmi_dev, "KCS: Wrote last data: %02x\n",
		    *cp);
#endif
	}

	/* Read the reply.  First, read the NetFn/LUN. */
	if (kcs_read_byte(sc, &data) != 1) {
		device_printf(sc->ipmi_dev, "KCS: Failed to read address\n");
		goto fail;
	}
#ifdef KCS_DEBUG
	device_printf(sc->ipmi_dev, "KCS: Read address: %02x\n", data);
#endif
	if (data != IPMI_REPLY_ADDR(req->ir_addr)) {
		device_printf(sc->ipmi_dev, "KCS: Reply address mismatch\n");
		goto fail;
	}

	/* Next we read the command. */
	if (kcs_read_byte(sc, &data) != 1) {
		device_printf(sc->ipmi_dev, "KCS: Failed to read command\n");
		goto fail;
	}
#ifdef KCS_DEBUG
	device_printf(sc->ipmi_dev, "KCS: Read command: %02x\n", data);
#endif
	if (data != req->ir_command) {
		device_printf(sc->ipmi_dev, "KCS: Command mismatch\n");
		goto fail;
	}

	/* Next we read the completion code. */
	if (kcs_read_byte(sc, &req->ir_compcode) != 1) {
		device_printf(sc->ipmi_dev,
		    "KCS: Failed to read completion code\n");
		goto fail;
	}
#ifdef KCS_DEBUG
	device_printf(sc->ipmi_dev, "KCS: Read completion code: %02x\n",
	    req->ir_compcode);
#endif

	/* Finally, read the reply from the BMC. */
	i = 0;
	for (;;) {
		state = kcs_read_byte(sc, &data);
		if (state == 0) {
			device_printf(sc->ipmi_dev,
			    "KCS: Read failed on byte %d\n", i + 1);
			goto fail;
		}
		if (state == 2)
			break;
		if (i < req->ir_replybuflen) {
			req->ir_reply[i] = data;
#ifdef KCS_DEBUG
			device_printf(sc->ipmi_dev, "KCS: Read data %02x\n",
			    data);
		} else {
			device_printf(sc->ipmi_dev,
			    "KCS: Read short %02x byte %d\n", data, i + 1);
#endif
		}
		i++;
	}
	IPMI_IO_UNLOCK(sc);
	req->ir_replylen = i;
#ifdef KCS_DEBUG
	device_printf(sc->ipmi_dev, "KCS: READ finished (%d bytes)\n", i);
	if (req->ir_replybuflen < i)
#else
	if (req->ir_replybuflen < i && req->ir_replybuflen != 0)
#endif
		device_printf(sc->ipmi_dev,
		    "KCS: Read short: %zd buffer, %d actual\n",
		    req->ir_replybuflen, i);
	return (1);
fail:
	kcs_error(sc);
	IPMI_IO_UNLOCK(sc);
	return (0);
}