Blame src/plugins/usb/usb.c

Packit Service ed0f68
/*
Packit Service ed0f68
 * Copyright (c) 2015 American Megatrends, Inc.
Packit Service ed0f68
 * All rights reserved.
Packit Service ed0f68
 *
Packit Service ed0f68
 * Redistribution and use in source and binary forms, with or without
Packit Service ed0f68
 * modification, are permitted provided that the following conditions
Packit Service ed0f68
 * are met:
Packit Service ed0f68
 *
Packit Service ed0f68
 * 1. Redistributions of source code must retain the above copyright notice,
Packit Service ed0f68
 *    this list of conditions and the following disclaimer.
Packit Service ed0f68
 *
Packit Service ed0f68
 * 2. Redistributions in binary form must reproduce the above copyright notice,
Packit Service ed0f68
 *    this list of conditions and the following disclaimer in the documentation
Packit Service ed0f68
 *    and/or other materials provided with the distribution.
Packit Service ed0f68
 *
Packit Service ed0f68
 * 3. Neither the name of the copyright holder nor the names of its
Packit Service ed0f68
 *    contributors may be used to endorse or promote products derived from this
Packit Service ed0f68
 *    software without specific prior written permission.
Packit Service ed0f68
 *
Packit Service ed0f68
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit Service ed0f68
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit Service ed0f68
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service ed0f68
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
Packit Service ed0f68
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
Packit Service ed0f68
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
Packit Service ed0f68
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit Service ed0f68
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
Packit Service ed0f68
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit Service ed0f68
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Packit Service ed0f68
 * POSSIBILITY OF SUCH DAMAGE.
Packit Service ed0f68
 */
Packit Service ed0f68
Packit Service ed0f68
#define _BSD_SOURCE
Packit Service ed0f68
Packit Service ed0f68
#include <ipmitool/helper.h>
Packit Service ed0f68
#include <ipmitool/log.h>
Packit Service ed0f68
#include <ipmitool/bswap.h>
Packit Service ed0f68
#include <ipmitool/ipmi.h>
Packit Service ed0f68
#include <ipmitool/ipmi_intf.h>
Packit Service ed0f68
#include <ipmitool/ipmi_oem.h>
Packit Service ed0f68
#include <ipmitool/ipmi_strings.h>
Packit Service ed0f68
#include <ipmitool/ipmi_constants.h>
Packit Service ed0f68
#include <scsi/sg.h>
Packit Service ed0f68
#include <sys/ioctl.h>
Packit Service ed0f68
#include <scsi/scsi_ioctl.h>
Packit Service ed0f68
#include <scsi/scsi.h>
Packit Service ed0f68
#include <sys/file.h>
Packit Service ed0f68
#include <sys/stat.h>
Packit Service ed0f68
#include <sys/types.h>
Packit Service ed0f68
#include <fcntl.h>
Packit Service ed0f68
#include <errno.h>
Packit Service ed0f68
#include <unistd.h>
Packit Service ed0f68
Packit Service ed0f68
#define PACKED __attribute__ ((packed))
Packit Service ed0f68
#define BEGIN_SIG                   "$G2-CONFIG-HOST$"
Packit Service ed0f68
#define BEGIN_SIG_LEN               16
Packit Service ed0f68
#define MAX_REQUEST_SIZE            64 * 1024
Packit Service ed0f68
#define CMD_RESERVED                0x0000
Packit Service ed0f68
#define SCSI_AMICMD_CURI_WRITE      0xE2
Packit Service ed0f68
#define SCSI_AMICMD_CURI_READ       0xE3
Packit Service ed0f68
#define SCSI_AMIDEF_CMD_SECTOR      0x01
Packit Service ed0f68
#define SCSI_AMIDEF_DATA_SECTOR     0x02
Packit Service ed0f68
#define ERR_SUCCESS                 0       /* Success */
Packit Service ed0f68
#define ERR_BIG_DATA                1       /* Too Much Data */
Packit Service ed0f68
#define ERR_NO_DATA                 2       /* No/Less Data Available */
Packit Service ed0f68
#define ERR_UNSUPPORTED             3       /* Unsupported Command */
Packit Service ed0f68
#define IN_PROCESS                  0x8000  /* Bit 15 of Status */
Packit Service ed0f68
#define SCSI_AMICMD_ID              0xEE
Packit Service ed0f68
Packit Service ed0f68
/* SCSI Command Packets */
Packit Service ed0f68
typedef struct {
Packit Service ed0f68
	unsigned char   OpCode;
Packit Service ed0f68
	unsigned char   Lun;
Packit Service ed0f68
	unsigned int    Lba;
Packit Service ed0f68
	union {
Packit Service ed0f68
		struct {
Packit Service ed0f68
			unsigned char   Reserved6;
Packit Service ed0f68
			unsigned short  Length;
Packit Service ed0f68
			unsigned char   Reserved9[3];
Packit Service ed0f68
		} PACKED Cmd10;
Packit Service ed0f68
		struct Len32 {
Packit Service ed0f68
			unsigned int    Length32;
Packit Service ed0f68
			unsigned char   Reserved10[2];
Packit Service ed0f68
		} PACKED Cmd12;
Packit Service ed0f68
	} PACKED CmdLen;
Packit Service ed0f68
} PACKED SCSI_COMMAND_PACKET;
Packit Service ed0f68
Packit Service ed0f68
typedef struct {
Packit Service ed0f68
	uint8_t byNetFnLUN;
Packit Service ed0f68
	uint8_t byCmd;
Packit Service ed0f68
	uint8_t byData[MAX_REQUEST_SIZE];
Packit Service ed0f68
} PACKED IPMIUSBRequest_T;
Packit Service ed0f68
Packit Service ed0f68
typedef struct {
Packit Service ed0f68
	uint8_t   BeginSig[BEGIN_SIG_LEN];
Packit Service ed0f68
	uint16_t  Command;
Packit Service ed0f68
	uint16_t  Status;
Packit Service ed0f68
	uint32_t  DataInLen;
Packit Service ed0f68
	uint32_t  DataOutLen;
Packit Service ed0f68
	uint32_t  InternalUseDataIn;
Packit Service ed0f68
	uint32_t  InternalUseDataOut;
Packit Service ed0f68
} CONFIG_CMD;
Packit Service ed0f68
Packit Service ed0f68
static int ipmi_usb_setup(struct ipmi_intf *intf);
Packit Service ed0f68
static struct ipmi_rs *ipmi_usb_send_cmd(struct ipmi_intf *intf,
Packit Service ed0f68
		struct ipmi_rq *req);
Packit Service ed0f68
Packit Service ed0f68
struct ipmi_intf ipmi_usb_intf = {
Packit Service ed0f68
	.name = "usb",
Packit Service ed0f68
	.desc = "IPMI USB Interface(OEM Interface for AMI Devices)",
Packit Service ed0f68
	.setup = ipmi_usb_setup,
Packit Service ed0f68
	.sendrecv = ipmi_usb_send_cmd,
Packit Service ed0f68
};
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
scsiProbeNew(int *num_ami_devices, int *sg_nos)
Packit Service ed0f68
{
Packit Service ed0f68
	int inplen = *num_ami_devices;
Packit Service ed0f68
	int numdevfound = 0;
Packit Service ed0f68
	char linebuf[81];
Packit Service ed0f68
	char vendor[81];
Packit Service ed0f68
	int lineno = 0;
Packit Service ed0f68
	FILE *fp;
Packit Service ed0f68
Packit Service ed0f68
	fp = fopen("/proc/scsi/sg/device_strs", "r");
Packit Service ed0f68
	if (fp == NULL) {
Packit Service ed0f68
		/* Return 1 on error */
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	while (1) {
Packit Service ed0f68
		/* Read line by line and search for "AMI" */
Packit Service ed0f68
		if (fgets(linebuf, 80, fp) == NULL) {
Packit Service ed0f68
			break;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		if (sscanf(linebuf, "%s", vendor) == 1) {
Packit Service ed0f68
			if (strncmp(vendor, "AMI", strlen("AMI")) == 0) {
Packit Service ed0f68
				numdevfound++;
Packit Service ed0f68
				sg_nos[numdevfound - 1] = lineno;
Packit Service ed0f68
				if (numdevfound == inplen) {
Packit Service ed0f68
					break;
Packit Service ed0f68
				}
Packit Service ed0f68
			}
Packit Service ed0f68
			lineno++;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	*num_ami_devices = numdevfound;
Packit Service ed0f68
	if (fp != NULL) {
Packit Service ed0f68
		fclose(fp);
Packit Service ed0f68
		fp = NULL;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
OpenCD(struct ipmi_intf *intf, char *CDName)
Packit Service ed0f68
{
Packit Service ed0f68
	intf->fd = open(CDName, O_RDWR);
Packit Service ed0f68
	if (intf->fd == (-1)) {
Packit Service ed0f68
		lprintf(LOG_ERR, "OpenCD:Unable to open device, %s",
Packit Service ed0f68
				strerror(errno));
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
sendscsicmd_SGIO(int cd_desc, unsigned char *cdb_buf, unsigned char cdb_len,
Packit Service ed0f68
		void *data_buf, unsigned int *data_len, int direction,
Packit Service ed0f68
		void *sense_buf, unsigned char slen, unsigned int timeout)
Packit Service ed0f68
{
Packit Service ed0f68
	sg_io_hdr_t io_hdr;
Packit Service ed0f68
Packit Service ed0f68
	/* Prepare command */
Packit Service ed0f68
	memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
Packit Service ed0f68
	io_hdr.interface_id = 'S';
Packit Service ed0f68
	io_hdr.cmd_len = cdb_len;
Packit Service ed0f68
Packit Service ed0f68
	/* Transfer direction and length */
Packit Service ed0f68
	io_hdr.dxfer_direction = direction;
Packit Service ed0f68
	io_hdr.dxfer_len = *data_len;
Packit Service ed0f68
Packit Service ed0f68
	io_hdr.dxferp = data_buf;
Packit Service ed0f68
Packit Service ed0f68
	io_hdr.cmdp = cdb_buf;
Packit Service ed0f68
Packit Service ed0f68
	io_hdr.sbp = (unsigned char *)sense_buf;
Packit Service ed0f68
	io_hdr.mx_sb_len = slen;
Packit Service ed0f68
Packit Service ed0f68
	io_hdr.timeout = timeout;
Packit Service ed0f68
Packit Service ed0f68
	if (!timeout) {
Packit Service ed0f68
		io_hdr.timeout = 20000;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (ioctl(cd_desc, SG_IO, &io_hdr) < 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "sendscsicmd_SGIO: SG_IO ioctl error");
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	} else {
Packit Service ed0f68
		if (io_hdr.status != 0) {
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (!timeout) {
Packit Service ed0f68
		return 0;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
Packit Service ed0f68
		lprintf(LOG_DEBUG, "sendscsicmd_SGIO: SG_INFO_OK - Not OK");
Packit Service ed0f68
	} else {
Packit Service ed0f68
		lprintf(LOG_DEBUG, "sendscsicmd_SGIO: SG_INFO_OK - OK");
Packit Service ed0f68
		return 0;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 1;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
AMI_SPT_CMD_Identify(int cd_desc, char *szSignature)
Packit Service ed0f68
{
Packit Service ed0f68
	SCSI_COMMAND_PACKET IdPkt = {0};
Packit Service ed0f68
	int ret;
Packit Service ed0f68
	unsigned int siglen = 10;
Packit Service ed0f68
Packit Service ed0f68
	IdPkt.OpCode = SCSI_AMICMD_ID;
Packit Service ed0f68
	ret = sendscsicmd_SGIO(cd_desc, (unsigned char *)&IdPkt,
Packit Service ed0f68
				10, szSignature, &siglen, SG_DXFER_FROM_DEV,
Packit Service ed0f68
				NULL, 0, 5000);
Packit Service ed0f68
Packit Service ed0f68
	return ret;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
IsG2Drive(int cd_desc)
Packit Service ed0f68
{
Packit Service ed0f68
	char szSignature[15];
Packit Service ed0f68
	int ret;
Packit Service ed0f68
Packit Service ed0f68
	memset(szSignature, 0, 15);
Packit Service ed0f68
Packit Service ed0f68
	flock(cd_desc, LOCK_EX);
Packit Service ed0f68
	ret = AMI_SPT_CMD_Identify(cd_desc, szSignature);
Packit Service ed0f68
	flock(cd_desc, LOCK_UN);
Packit Service ed0f68
	if (ret != 0) {
Packit Service ed0f68
		lprintf(LOG_DEBUG,
Packit Service ed0f68
				"IsG2Drive:Unable to send ID command to the device");
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (strncmp(szSignature, "$$$AMI$$$", strlen("$$$AMI$$$")) != 0) {
Packit Service ed0f68
		lprintf(LOG_ERR,
Packit Service ed0f68
				"IsG2Drive:Signature mismatch when ID command sent");
Packit Service ed0f68
		return 1;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
FindG2CDROM(struct ipmi_intf *intf)
Packit Service ed0f68
{
Packit Service ed0f68
	int err = 0;
Packit Service ed0f68
	char device[256];
Packit Service ed0f68
	int devarray[16];
Packit Service ed0f68
	int numdev = 16;
Packit Service ed0f68
	int iter;
Packit Service ed0f68
	err = scsiProbeNew(&numdev, devarray);
Packit Service ed0f68
Packit Service ed0f68
	if (err == 0 && numdev > 0) {
Packit Service ed0f68
		for (iter = 0; iter < numdev; iter++) {
Packit Service ed0f68
			sprintf(device, "/dev/sg%d", devarray[iter]);
Packit Service ed0f68
Packit Service ed0f68
			if (!OpenCD(intf, device)) {
Packit Service ed0f68
				if (!IsG2Drive(intf->fd)) {
Packit Service ed0f68
					lprintf(LOG_DEBUG, "USB Device found");
Packit Service ed0f68
					return 1;
Packit Service ed0f68
				}
Packit Service ed0f68
				close(intf->fd);
Packit Service ed0f68
			}
Packit Service ed0f68
		}
Packit Service ed0f68
	} else {
Packit Service ed0f68
		lprintf(LOG_DEBUG, "Unable to find Virtual CDROM Device");
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static int
Packit Service ed0f68
ipmi_usb_setup(struct ipmi_intf *intf)
Packit Service ed0f68
{
Packit Service ed0f68
	if (FindG2CDROM(intf) == 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error in USB session setup \n");
Packit Service ed0f68
		return (-1);
Packit Service ed0f68
	}
Packit Service ed0f68
	intf->opened = 1;
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
void
Packit Service ed0f68
InitCmdHeader(CONFIG_CMD *pG2CDCmdHeader)
Packit Service ed0f68
{
Packit Service ed0f68
	memset(pG2CDCmdHeader, 0, sizeof(CONFIG_CMD));
Packit Service ed0f68
	memcpy((char *)pG2CDCmdHeader->BeginSig, BEGIN_SIG, BEGIN_SIG_LEN);
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
AMI_SPT_CMD_SendCmd(int cd_desc, char *Buffer, char type, uint16_t buflen,
Packit Service ed0f68
		unsigned int timeout)
Packit Service ed0f68
{
Packit Service ed0f68
	SCSI_COMMAND_PACKET Cmdpkt;
Packit Service ed0f68
	char sensebuff[32];
Packit Service ed0f68
	int ret;
Packit Service ed0f68
	unsigned int pktLen;
Packit Service ed0f68
	int count = 3;
Packit Service ed0f68
Packit Service ed0f68
	memset(&Cmdpkt, 0, sizeof(SCSI_COMMAND_PACKET));
Packit Service ed0f68
Packit Service ed0f68
	Cmdpkt.OpCode = SCSI_AMICMD_CURI_WRITE;
Packit Service ed0f68
	Cmdpkt.Lba = htonl(type);
Packit Service ed0f68
	Cmdpkt.CmdLen.Cmd10.Length = htons(1);
Packit Service ed0f68
Packit Service ed0f68
	pktLen = buflen;
Packit Service ed0f68
	while (count > 0) {
Packit Service ed0f68
		ret = sendscsicmd_SGIO(cd_desc, (unsigned char *)&Cmdpkt,
Packit Service ed0f68
				10, Buffer, &pktLen, SG_DXFER_TO_DEV,
Packit Service ed0f68
				sensebuff, 32, timeout);
Packit Service ed0f68
		count--;
Packit Service ed0f68
		if (ret == 0) {
Packit Service ed0f68
			break;
Packit Service ed0f68
		} else {
Packit Service ed0f68
			ret = (-1);
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return ret;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
AMI_SPT_CMD_RecvCmd(int cd_desc, char *Buffer, char type, uint16_t buflen)
Packit Service ed0f68
{
Packit Service ed0f68
	SCSI_COMMAND_PACKET Cmdpkt;
Packit Service ed0f68
	char sensebuff[32];
Packit Service ed0f68
	int ret;
Packit Service ed0f68
	unsigned int pktLen;
Packit Service ed0f68
	int count = 3;
Packit Service ed0f68
Packit Service ed0f68
	memset(&Cmdpkt, 0, sizeof(SCSI_COMMAND_PACKET));
Packit Service ed0f68
Packit Service ed0f68
	Cmdpkt.OpCode = SCSI_AMICMD_CURI_READ;
Packit Service ed0f68
	Cmdpkt.Lba = htonl(type);
Packit Service ed0f68
	Cmdpkt.CmdLen.Cmd10.Length = htons(1);
Packit Service ed0f68
Packit Service ed0f68
	pktLen = buflen;
Packit Service ed0f68
	while (count > 0) {
Packit Service ed0f68
		ret = sendscsicmd_SGIO(cd_desc, (unsigned char *)&Cmdpkt,
Packit Service ed0f68
				10, Buffer, &pktLen, SG_DXFER_FROM_DEV,
Packit Service ed0f68
				sensebuff, 32, 5000);
Packit Service ed0f68
		count--;
Packit Service ed0f68
		if (0 == ret) {
Packit Service ed0f68
			break;
Packit Service ed0f68
		} else {
Packit Service ed0f68
			ret = (-1);
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return ret;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
ReadCD(int cd_desc, char CmdData, char *Buffer, uint32_t DataLen)
Packit Service ed0f68
{
Packit Service ed0f68
	int ret;
Packit Service ed0f68
Packit Service ed0f68
	ret = AMI_SPT_CMD_RecvCmd(cd_desc, Buffer, CmdData, DataLen);
Packit Service ed0f68
	if (ret != 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error while reading CD-Drive");
Packit Service ed0f68
		return (-1);
Packit Service ed0f68
	}
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
WriteCD(int cd_desc, char CmdData, char *Buffer, unsigned int timeout,
Packit Service ed0f68
		uint32_t DataLen)
Packit Service ed0f68
{
Packit Service ed0f68
	int ret;
Packit Service ed0f68
Packit Service ed0f68
	ret = AMI_SPT_CMD_SendCmd(cd_desc, Buffer, CmdData, DataLen, timeout);
Packit Service ed0f68
	if (ret != 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "Error while writing to CD-Drive");
Packit Service ed0f68
		return (-1);
Packit Service ed0f68
	}
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
WriteSplitData(struct ipmi_intf *intf, char *Buffer, char Sector,
Packit Service ed0f68
			uint32_t NumBytes, uint32_t timeout)
Packit Service ed0f68
{
Packit Service ed0f68
	uint32_t BytesWritten = 0;
Packit Service ed0f68
	int retVal;
Packit Service ed0f68
Packit Service ed0f68
	if (NumBytes == 0) {
Packit Service ed0f68
		return 0;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	while (BytesWritten < NumBytes) {
Packit Service ed0f68
		if ((retVal = WriteCD(intf->fd, Sector,
Packit Service ed0f68
						(Buffer + BytesWritten),
Packit Service ed0f68
						timeout, NumBytes)) != 0) {
Packit Service ed0f68
			return retVal;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		BytesWritten += NumBytes;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
ReadSplitData(struct ipmi_intf *intf, char *Buffer, char Sector,
Packit Service ed0f68
				uint32_t NumBytes)
Packit Service ed0f68
{
Packit Service ed0f68
	uint32_t BytesRead = 0;
Packit Service ed0f68
Packit Service ed0f68
	if (NumBytes == 0) {
Packit Service ed0f68
		return 0;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	while (BytesRead < NumBytes) {
Packit Service ed0f68
		if (ReadCD(intf->fd, Sector, (Buffer + BytesRead),
Packit Service ed0f68
					NumBytes) == (-1)) {
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
		BytesRead += NumBytes;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
WaitForCommandCompletion(struct ipmi_intf *intf, CONFIG_CMD *pG2CDCmdHeader,
Packit Service ed0f68
		uint32_t timeout, uint32_t DataLen)
Packit Service ed0f68
{
Packit Service ed0f68
	uint32_t TimeCounter = 0;
Packit Service ed0f68
Packit Service ed0f68
	do {
Packit Service ed0f68
		if (ReadCD(intf->fd, SCSI_AMIDEF_CMD_SECTOR,
Packit Service ed0f68
					(char *)(pG2CDCmdHeader), DataLen) == (-1)) {
Packit Service ed0f68
			lprintf(LOG_ERR, "ReadCD returned ERROR");
Packit Service ed0f68
			return 1;
Packit Service ed0f68
		}
Packit Service ed0f68
Packit Service ed0f68
		if (pG2CDCmdHeader->Status & IN_PROCESS) {
Packit Service ed0f68
			usleep(1000);
Packit Service ed0f68
			if (timeout > 0) {
Packit Service ed0f68
				TimeCounter++;
Packit Service ed0f68
				if (TimeCounter == (timeout + 1)) {
Packit Service ed0f68
					return 2;
Packit Service ed0f68
				}
Packit Service ed0f68
			}
Packit Service ed0f68
		} else {
Packit Service ed0f68
			lprintf(LOG_DEBUG, "Command completed");
Packit Service ed0f68
			break;
Packit Service ed0f68
		}
Packit Service ed0f68
	} while (1);
Packit Service ed0f68
Packit Service ed0f68
	return 0;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
int
Packit Service ed0f68
SendDataToUSBDriver(struct ipmi_intf *intf, char *ReqBuffer,
Packit Service ed0f68
			unsigned int ReqBuffLen, unsigned char *ResBuffer,
Packit Service ed0f68
			int *ResBuffLen, unsigned int timeout)
Packit Service ed0f68
{
Packit Service ed0f68
	char CmdHeaderBuffer[sizeof(CONFIG_CMD)];
Packit Service ed0f68
	int retVal;
Packit Service ed0f68
	int waitretval = 0;
Packit Service ed0f68
	unsigned int to = 0;
Packit Service ed0f68
	uint32_t DataLen = 0;
Packit Service ed0f68
Packit Service ed0f68
	CONFIG_CMD *pG2CDCmdHeader = (CONFIG_CMD *)CmdHeaderBuffer;
Packit Service ed0f68
Packit Service ed0f68
	/* FillHeader */
Packit Service ed0f68
	InitCmdHeader(pG2CDCmdHeader);
Packit Service ed0f68
Packit Service ed0f68
	/* Set command number */
Packit Service ed0f68
	pG2CDCmdHeader->Command = CMD_RESERVED;
Packit Service ed0f68
Packit Service ed0f68
	/* Fill Lengths */
Packit Service ed0f68
	pG2CDCmdHeader->DataOutLen = *ResBuffLen;
Packit Service ed0f68
	pG2CDCmdHeader->DataInLen = ReqBuffLen;
Packit Service ed0f68
Packit Service ed0f68
	if (!timeout) {
Packit Service ed0f68
		to = 3000;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	DataLen = sizeof(CONFIG_CMD);
Packit Service ed0f68
Packit Service ed0f68
	if (WriteCD(intf->fd, SCSI_AMIDEF_CMD_SECTOR,
Packit Service ed0f68
				(char *)(pG2CDCmdHeader), to, DataLen) == (-1)) {
Packit Service ed0f68
		lprintf(LOG_ERR,
Packit Service ed0f68
				"Error in Write CD of SCSI_AMIDEF_CMD_SECTOR");
Packit Service ed0f68
		return (-1);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/* Write the data to hard disk */
Packit Service ed0f68
	if ((retVal = WriteSplitData(intf, ReqBuffer,
Packit Service ed0f68
					SCSI_AMIDEF_DATA_SECTOR,
Packit Service ed0f68
					ReqBuffLen, timeout)) != 0) {
Packit Service ed0f68
		lprintf(LOG_ERR,
Packit Service ed0f68
				"Error in WriteSplitData of SCSI_AMIDEF_DATA_SECTOR");
Packit Service ed0f68
		return (-1);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (!timeout) {
Packit Service ed0f68
		return 0;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/* Read Status now */
Packit Service ed0f68
	waitretval = WaitForCommandCompletion(intf, pG2CDCmdHeader, timeout,
Packit Service ed0f68
			DataLen);
Packit Service ed0f68
	if (waitretval != 0) {
Packit Service ed0f68
		lprintf(LOG_ERR, "WaitForCommandComplete failed");
Packit Service ed0f68
		return (0 - waitretval);
Packit Service ed0f68
	} else {
Packit Service ed0f68
		lprintf(LOG_DEBUG, "WaitForCommandCompletion SUCCESS");
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	switch (pG2CDCmdHeader->Status) {
Packit Service ed0f68
		case ERR_SUCCESS:
Packit Service ed0f68
			*ResBuffLen = pG2CDCmdHeader->DataOutLen;
Packit Service ed0f68
			lprintf(LOG_DEBUG, "Before ReadSplitData %x", *ResBuffLen);
Packit Service ed0f68
			if (ReadSplitData(intf, (char *)ResBuffer,
Packit Service ed0f68
						SCSI_AMIDEF_DATA_SECTOR,
Packit Service ed0f68
						pG2CDCmdHeader->DataOutLen) != 0) {
Packit Service ed0f68
				lprintf(LOG_ERR,
Packit Service ed0f68
						"Err ReadSplitData SCSI_AMIDEF_DATA_SCTR");
Packit Service ed0f68
				return (-1);
Packit Service ed0f68
			}
Packit Service ed0f68
			/* Additional read to see verify there was not problem
Packit Service ed0f68
			 * with the previous read
Packit Service ed0f68
			 */
Packit Service ed0f68
			DataLen = sizeof(CONFIG_CMD);
Packit Service ed0f68
			ReadCD(intf->fd, SCSI_AMIDEF_CMD_SECTOR,
Packit Service ed0f68
					(char *)(pG2CDCmdHeader), DataLen);
Packit Service ed0f68
			break;
Packit Service ed0f68
		case ERR_BIG_DATA:
Packit Service ed0f68
			lprintf(LOG_ERR, "Too much data");
Packit Service ed0f68
			break;
Packit Service ed0f68
		case ERR_NO_DATA:
Packit Service ed0f68
			lprintf(LOG_ERR, "Too little data");
Packit Service ed0f68
			break;
Packit Service ed0f68
		case ERR_UNSUPPORTED:
Packit Service ed0f68
			lprintf(LOG_ERR, "Unsupported command");
Packit Service ed0f68
			break;
Packit Service ed0f68
		default:
Packit Service ed0f68
			lprintf(LOG_ERR, "Unknown status");
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	return pG2CDCmdHeader->Status;
Packit Service ed0f68
}
Packit Service ed0f68
Packit Service ed0f68
static struct ipmi_rs *
Packit Service ed0f68
ipmi_usb_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req)
Packit Service ed0f68
{
Packit Service ed0f68
	static struct ipmi_rs rsp;
Packit Service ed0f68
	long timeout = 20000;
Packit Service ed0f68
	uint8_t byRet = 0;
Packit Service ed0f68
	char ReqBuff[MAX_REQUEST_SIZE] = {0};
Packit Service ed0f68
	IPMIUSBRequest_T *pReqPkt = (IPMIUSBRequest_T *)ReqBuff;
Packit Service ed0f68
	int retries = 0;
Packit Service ed0f68
	/********** FORM IPMI PACKET *****************/
Packit Service ed0f68
	pReqPkt->byNetFnLUN = req->msg.netfn << 2;
Packit Service ed0f68
	pReqPkt->byNetFnLUN += req->msg.lun;
Packit Service ed0f68
	pReqPkt->byCmd = req->msg.cmd;
Packit Service ed0f68
	if (req->msg.data_len) {
Packit Service ed0f68
		memcpy(pReqPkt->byData, req->msg.data, req->msg.data_len);
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	/********** SEND DATA TO USB ******************/
Packit Service ed0f68
	while (retries < 3) {
Packit Service ed0f68
		retries++;
Packit Service ed0f68
		byRet = SendDataToUSBDriver(intf, ReqBuff,
Packit Service ed0f68
				2 + req->msg.data_len, rsp.data,
Packit Service ed0f68
				&rsp.data_len,timeout);
Packit Service ed0f68
Packit Service ed0f68
		if (byRet == 0) {
Packit Service ed0f68
			break;
Packit Service ed0f68
		}
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	if (retries == 3) {
Packit Service ed0f68
		lprintf(LOG_ERR,
Packit Service ed0f68
				"Error while sending command using",
Packit Service ed0f68
				"SendDataToUSBDriver");
Packit Service ed0f68
		rsp.ccode = byRet;
Packit Service ed0f68
		return &rsp;
Packit Service ed0f68
	}
Packit Service ed0f68
Packit Service ed0f68
	rsp.ccode = rsp.data[0];
Packit Service ed0f68
Packit Service ed0f68
	/* Save response data for caller */
Packit Service ed0f68
	if ((rsp.ccode == 0) && (rsp.data_len > 0)) {
Packit Service ed0f68
		memmove(rsp.data, rsp.data + 1, rsp.data_len - 1);
Packit Service ed0f68
		rsp.data[rsp.data_len] = 0;
Packit Service ed0f68
		rsp.data_len -= 1;
Packit Service ed0f68
	}
Packit Service ed0f68
	return &rsp;
Packit Service ed0f68
}