xref: /openbmc/ipmitool/src/plugins/usb/usb.c (revision e2c5b322)
1*e2c5b322SZdenek Styblik /*
2*e2c5b322SZdenek Styblik  * Copyright (c) 2015 American Megatrends, Inc.
3*e2c5b322SZdenek Styblik  * All rights reserved.
4*e2c5b322SZdenek Styblik  *
5*e2c5b322SZdenek Styblik  * Redistribution and use in source and binary forms, with or without
6*e2c5b322SZdenek Styblik  * modification, are permitted provided that the following conditions
7*e2c5b322SZdenek Styblik  * are met:
8*e2c5b322SZdenek Styblik  *
9*e2c5b322SZdenek Styblik  * 1. Redistributions of source code must retain the above copyright notice,
10*e2c5b322SZdenek Styblik  *    this list of conditions and the following disclaimer.
11*e2c5b322SZdenek Styblik  *
12*e2c5b322SZdenek Styblik  * 2. Redistributions in binary form must reproduce the above copyright notice,
13*e2c5b322SZdenek Styblik  *    this list of conditions and the following disclaimer in the documentation
14*e2c5b322SZdenek Styblik  *    and/or other materials provided with the distribution.
15*e2c5b322SZdenek Styblik  *
16*e2c5b322SZdenek Styblik  * 3. Neither the name of the copyright holder nor the names of its
17*e2c5b322SZdenek Styblik  *    contributors may be used to endorse or promote products derived from this
18*e2c5b322SZdenek Styblik  *    software without specific prior written permission.
19*e2c5b322SZdenek Styblik  *
20*e2c5b322SZdenek Styblik  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21*e2c5b322SZdenek Styblik  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*e2c5b322SZdenek Styblik  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*e2c5b322SZdenek Styblik  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24*e2c5b322SZdenek Styblik  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25*e2c5b322SZdenek Styblik  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26*e2c5b322SZdenek Styblik  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27*e2c5b322SZdenek Styblik  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28*e2c5b322SZdenek Styblik  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*e2c5b322SZdenek Styblik  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30*e2c5b322SZdenek Styblik  * POSSIBILITY OF SUCH DAMAGE.
31*e2c5b322SZdenek Styblik  */
32*e2c5b322SZdenek Styblik 
33*e2c5b322SZdenek Styblik #define _BSD_SOURCE
34*e2c5b322SZdenek Styblik 
35*e2c5b322SZdenek Styblik #include <ipmitool/helper.h>
36*e2c5b322SZdenek Styblik #include <ipmitool/log.h>
37*e2c5b322SZdenek Styblik #include <ipmitool/bswap.h>
38*e2c5b322SZdenek Styblik #include <ipmitool/ipmi.h>
39*e2c5b322SZdenek Styblik #include <ipmitool/ipmi_intf.h>
40*e2c5b322SZdenek Styblik #include <ipmitool/ipmi_oem.h>
41*e2c5b322SZdenek Styblik #include <ipmitool/ipmi_strings.h>
42*e2c5b322SZdenek Styblik #include <ipmitool/ipmi_constants.h>
43*e2c5b322SZdenek Styblik #include <scsi/sg.h>
44*e2c5b322SZdenek Styblik #include <sys/ioctl.h>
45*e2c5b322SZdenek Styblik #include <scsi/scsi_ioctl.h>
46*e2c5b322SZdenek Styblik #include <scsi/scsi.h>
47*e2c5b322SZdenek Styblik #include <sys/file.h>
48*e2c5b322SZdenek Styblik #include <sys/stat.h>
49*e2c5b322SZdenek Styblik #include <sys/types.h>
50*e2c5b322SZdenek Styblik #include <fcntl.h>
51*e2c5b322SZdenek Styblik #include <errno.h>
52*e2c5b322SZdenek Styblik #include <unistd.h>
53*e2c5b322SZdenek Styblik 
54*e2c5b322SZdenek Styblik #define PACKED __attribute__ ((packed))
55*e2c5b322SZdenek Styblik #define BEGIN_SIG                   "$G2-CONFIG-HOST$"
56*e2c5b322SZdenek Styblik #define BEGIN_SIG_LEN               16
57*e2c5b322SZdenek Styblik #define MAX_REQUEST_SIZE            64 * 1024
58*e2c5b322SZdenek Styblik #define CMD_RESERVED                0x0000
59*e2c5b322SZdenek Styblik #define SCSI_AMICMD_CURI_WRITE      0xE2
60*e2c5b322SZdenek Styblik #define SCSI_AMICMD_CURI_READ       0xE3
61*e2c5b322SZdenek Styblik #define SCSI_AMIDEF_CMD_SECTOR      0x01
62*e2c5b322SZdenek Styblik #define SCSI_AMIDEF_DATA_SECTOR     0x02
63*e2c5b322SZdenek Styblik #define ERR_SUCCESS                 0       /* Success */
64*e2c5b322SZdenek Styblik #define ERR_BIG_DATA                1       /* Too Much Data */
65*e2c5b322SZdenek Styblik #define ERR_NO_DATA                 2       /* No/Less Data Available */
66*e2c5b322SZdenek Styblik #define ERR_UNSUPPORTED             3       /* Unsupported Command */
67*e2c5b322SZdenek Styblik #define IN_PROCESS                  0x8000  /* Bit 15 of Status */
68*e2c5b322SZdenek Styblik #define SCSI_AMICMD_ID              0xEE
69*e2c5b322SZdenek Styblik 
70*e2c5b322SZdenek Styblik /* SCSI Command Packets */
71*e2c5b322SZdenek Styblik typedef struct {
72*e2c5b322SZdenek Styblik 	unsigned char   OpCode;
73*e2c5b322SZdenek Styblik 	unsigned char   Lun;
74*e2c5b322SZdenek Styblik 	unsigned int    Lba;
75*e2c5b322SZdenek Styblik 	union {
76*e2c5b322SZdenek Styblik 		struct {
77*e2c5b322SZdenek Styblik 			unsigned char   Reserved6;
78*e2c5b322SZdenek Styblik 			unsigned short  Length;
79*e2c5b322SZdenek Styblik 			unsigned char   Reserved9[3];
80*e2c5b322SZdenek Styblik 		} PACKED Cmd10;
81*e2c5b322SZdenek Styblik 		struct Len32 {
82*e2c5b322SZdenek Styblik 			unsigned int    Length32;
83*e2c5b322SZdenek Styblik 			unsigned char   Reserved10[2];
84*e2c5b322SZdenek Styblik 		} PACKED Cmd12;
85*e2c5b322SZdenek Styblik 	} PACKED CmdLen;
86*e2c5b322SZdenek Styblik } PACKED SCSI_COMMAND_PACKET;
87*e2c5b322SZdenek Styblik 
88*e2c5b322SZdenek Styblik typedef struct {
89*e2c5b322SZdenek Styblik 	uint8_t byNetFnLUN;
90*e2c5b322SZdenek Styblik 	uint8_t byCmd;
91*e2c5b322SZdenek Styblik 	uint8_t byData[MAX_REQUEST_SIZE];
92*e2c5b322SZdenek Styblik } PACKED IPMIUSBRequest_T;
93*e2c5b322SZdenek Styblik 
94*e2c5b322SZdenek Styblik typedef struct {
95*e2c5b322SZdenek Styblik 	uint8_t   BeginSig[BEGIN_SIG_LEN];
96*e2c5b322SZdenek Styblik 	uint16_t  Command;
97*e2c5b322SZdenek Styblik 	uint16_t  Status;
98*e2c5b322SZdenek Styblik 	uint32_t  DataInLen;
99*e2c5b322SZdenek Styblik 	uint32_t  DataOutLen;
100*e2c5b322SZdenek Styblik 	uint32_t  InternalUseDataIn;
101*e2c5b322SZdenek Styblik 	uint32_t  InternalUseDataOut;
102*e2c5b322SZdenek Styblik } CONFIG_CMD;
103*e2c5b322SZdenek Styblik 
104*e2c5b322SZdenek Styblik static int ipmi_usb_setup(struct ipmi_intf *intf);
105*e2c5b322SZdenek Styblik static struct ipmi_rs *ipmi_usb_send_cmd(struct ipmi_intf *intf,
106*e2c5b322SZdenek Styblik 		struct ipmi_rq *req);
107*e2c5b322SZdenek Styblik 
108*e2c5b322SZdenek Styblik struct ipmi_intf ipmi_usb_intf = {
109*e2c5b322SZdenek Styblik 	.name = "usb",
110*e2c5b322SZdenek Styblik 	.desc = "IPMI USB Interface(OEM Interface for AMI Devices)",
111*e2c5b322SZdenek Styblik 	.setup = ipmi_usb_setup,
112*e2c5b322SZdenek Styblik 	.sendrecv = ipmi_usb_send_cmd,
113*e2c5b322SZdenek Styblik };
114*e2c5b322SZdenek Styblik 
115*e2c5b322SZdenek Styblik int
scsiProbeNew(int * num_ami_devices,int * sg_nos)116*e2c5b322SZdenek Styblik scsiProbeNew(int *num_ami_devices, int *sg_nos)
117*e2c5b322SZdenek Styblik {
118*e2c5b322SZdenek Styblik 	int inplen = *num_ami_devices;
119*e2c5b322SZdenek Styblik 	int numdevfound = 0;
120*e2c5b322SZdenek Styblik 	char linebuf[81];
121*e2c5b322SZdenek Styblik 	char vendor[81];
122*e2c5b322SZdenek Styblik 	int lineno = 0;
123*e2c5b322SZdenek Styblik 	FILE *fp;
124*e2c5b322SZdenek Styblik 
125*e2c5b322SZdenek Styblik 	fp = fopen("/proc/scsi/sg/device_strs", "r");
126*e2c5b322SZdenek Styblik 	if (fp == NULL) {
127*e2c5b322SZdenek Styblik 		/* Return 1 on error */
128*e2c5b322SZdenek Styblik 		return 1;
129*e2c5b322SZdenek Styblik 	}
130*e2c5b322SZdenek Styblik 
131*e2c5b322SZdenek Styblik 	while (1) {
132*e2c5b322SZdenek Styblik 		/* Read line by line and search for "AMI" */
133*e2c5b322SZdenek Styblik 		if (fgets(linebuf, 80, fp) == NULL) {
134*e2c5b322SZdenek Styblik 			if (fp != NULL) {
135*e2c5b322SZdenek Styblik 				fclose(fp);
136*e2c5b322SZdenek Styblik 			}
137*e2c5b322SZdenek Styblik 			/* Return 1 on error */
138*e2c5b322SZdenek Styblik 			return 1;
139*e2c5b322SZdenek Styblik 		}
140*e2c5b322SZdenek Styblik 
141*e2c5b322SZdenek Styblik 		if (sscanf(linebuf, "%s", vendor) == 1) {
142*e2c5b322SZdenek Styblik 			if (strncmp(vendor, "AMI", strlen("AMI")) == 0) {
143*e2c5b322SZdenek Styblik 				numdevfound++;
144*e2c5b322SZdenek Styblik 				sg_nos[numdevfound - 1] = lineno;
145*e2c5b322SZdenek Styblik 				if (numdevfound == inplen) {
146*e2c5b322SZdenek Styblik 					break;
147*e2c5b322SZdenek Styblik 				}
148*e2c5b322SZdenek Styblik 			}
149*e2c5b322SZdenek Styblik 			lineno++;
150*e2c5b322SZdenek Styblik 		}
151*e2c5b322SZdenek Styblik 	}
152*e2c5b322SZdenek Styblik 
153*e2c5b322SZdenek Styblik 	*num_ami_devices = numdevfound;
154*e2c5b322SZdenek Styblik 	if (fp != NULL) {
155*e2c5b322SZdenek Styblik 		fclose(fp);
156*e2c5b322SZdenek Styblik 	}
157*e2c5b322SZdenek Styblik 
158*e2c5b322SZdenek Styblik 	return 0;
159*e2c5b322SZdenek Styblik }
160*e2c5b322SZdenek Styblik 
161*e2c5b322SZdenek Styblik int
OpenCD(struct ipmi_intf * intf,char * CDName)162*e2c5b322SZdenek Styblik OpenCD(struct ipmi_intf *intf, char *CDName)
163*e2c5b322SZdenek Styblik {
164*e2c5b322SZdenek Styblik 	intf->fd = open(CDName, O_RDWR);
165*e2c5b322SZdenek Styblik 	if (intf->fd == (-1)) {
166*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR, "OpenCD:Unable to open device, %s",
167*e2c5b322SZdenek Styblik 				strerror(errno));
168*e2c5b322SZdenek Styblik 		return 1;
169*e2c5b322SZdenek Styblik 	}
170*e2c5b322SZdenek Styblik 	return 0;
171*e2c5b322SZdenek Styblik }
172*e2c5b322SZdenek Styblik 
173*e2c5b322SZdenek Styblik int
sendscsicmd_SGIO(int cd_desc,unsigned char * cdb_buf,unsigned char cdb_len,void * data_buf,unsigned int * data_len,int direction,void * sense_buf,unsigned char slen,unsigned int timeout)174*e2c5b322SZdenek Styblik sendscsicmd_SGIO(int cd_desc, unsigned char *cdb_buf, unsigned char cdb_len,
175*e2c5b322SZdenek Styblik 		void *data_buf, unsigned int *data_len, int direction,
176*e2c5b322SZdenek Styblik 		void *sense_buf, unsigned char slen, unsigned int timeout)
177*e2c5b322SZdenek Styblik {
178*e2c5b322SZdenek Styblik 	sg_io_hdr_t io_hdr;
179*e2c5b322SZdenek Styblik 
180*e2c5b322SZdenek Styblik 	/* Prepare command */
181*e2c5b322SZdenek Styblik 	memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
182*e2c5b322SZdenek Styblik 	io_hdr.interface_id = 'S';
183*e2c5b322SZdenek Styblik 	io_hdr.cmd_len = cdb_len;
184*e2c5b322SZdenek Styblik 
185*e2c5b322SZdenek Styblik 	/* Transfer direction and length */
186*e2c5b322SZdenek Styblik 	io_hdr.dxfer_direction = direction;
187*e2c5b322SZdenek Styblik 	io_hdr.dxfer_len = *data_len;
188*e2c5b322SZdenek Styblik 
189*e2c5b322SZdenek Styblik 	io_hdr.dxferp = data_buf;
190*e2c5b322SZdenek Styblik 
191*e2c5b322SZdenek Styblik 	io_hdr.cmdp = cdb_buf;
192*e2c5b322SZdenek Styblik 
193*e2c5b322SZdenek Styblik 	io_hdr.sbp = (unsigned char *)sense_buf;
194*e2c5b322SZdenek Styblik 	io_hdr.mx_sb_len = slen;
195*e2c5b322SZdenek Styblik 
196*e2c5b322SZdenek Styblik 	io_hdr.timeout = timeout;
197*e2c5b322SZdenek Styblik 
198*e2c5b322SZdenek Styblik 	if (!timeout) {
199*e2c5b322SZdenek Styblik 		io_hdr.timeout = 20000;
200*e2c5b322SZdenek Styblik 	}
201*e2c5b322SZdenek Styblik 
202*e2c5b322SZdenek Styblik 	if (ioctl(cd_desc, SG_IO, &io_hdr) < 0) {
203*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR, "sendscsicmd_SGIO: SG_IO ioctl error");
204*e2c5b322SZdenek Styblik 		return 1;
205*e2c5b322SZdenek Styblik 	} else {
206*e2c5b322SZdenek Styblik 		if (io_hdr.status != 0) {
207*e2c5b322SZdenek Styblik 			return 1;
208*e2c5b322SZdenek Styblik 		}
209*e2c5b322SZdenek Styblik 	}
210*e2c5b322SZdenek Styblik 
211*e2c5b322SZdenek Styblik 	if (!timeout) {
212*e2c5b322SZdenek Styblik 		return 0;
213*e2c5b322SZdenek Styblik 	}
214*e2c5b322SZdenek Styblik 
215*e2c5b322SZdenek Styblik 	if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
216*e2c5b322SZdenek Styblik 		lprintf(LOG_DEBUG, "sendscsicmd_SGIO: SG_INFO_OK - Not OK");
217*e2c5b322SZdenek Styblik 	} else {
218*e2c5b322SZdenek Styblik 		lprintf(LOG_DEBUG, "sendscsicmd_SGIO: SG_INFO_OK - OK");
219*e2c5b322SZdenek Styblik 		return 0;
220*e2c5b322SZdenek Styblik 	}
221*e2c5b322SZdenek Styblik 
222*e2c5b322SZdenek Styblik 	return 1;
223*e2c5b322SZdenek Styblik }
224*e2c5b322SZdenek Styblik 
225*e2c5b322SZdenek Styblik int
AMI_SPT_CMD_Identify(int cd_desc,char * szSignature)226*e2c5b322SZdenek Styblik AMI_SPT_CMD_Identify(int cd_desc, char *szSignature)
227*e2c5b322SZdenek Styblik {
228*e2c5b322SZdenek Styblik 	SCSI_COMMAND_PACKET IdPkt = {0};
229*e2c5b322SZdenek Styblik 	int ret;
230*e2c5b322SZdenek Styblik 	unsigned int siglen = 10;
231*e2c5b322SZdenek Styblik 
232*e2c5b322SZdenek Styblik 	IdPkt.OpCode = SCSI_AMICMD_ID;
233*e2c5b322SZdenek Styblik 	ret = sendscsicmd_SGIO(cd_desc, (unsigned char *)&IdPkt,
234*e2c5b322SZdenek Styblik 				10, szSignature, &siglen, SG_DXFER_FROM_DEV,
235*e2c5b322SZdenek Styblik 				NULL, 0, 5000);
236*e2c5b322SZdenek Styblik 
237*e2c5b322SZdenek Styblik 	return ret;
238*e2c5b322SZdenek Styblik }
239*e2c5b322SZdenek Styblik 
240*e2c5b322SZdenek Styblik int
IsG2Drive(int cd_desc)241*e2c5b322SZdenek Styblik IsG2Drive(int cd_desc)
242*e2c5b322SZdenek Styblik {
243*e2c5b322SZdenek Styblik 	char szSignature[15];
244*e2c5b322SZdenek Styblik 	int ret;
245*e2c5b322SZdenek Styblik 
246*e2c5b322SZdenek Styblik 	memset(szSignature, 0, 15);
247*e2c5b322SZdenek Styblik 
248*e2c5b322SZdenek Styblik 	flock(cd_desc, LOCK_EX);
249*e2c5b322SZdenek Styblik 	ret = AMI_SPT_CMD_Identify(cd_desc, szSignature);
250*e2c5b322SZdenek Styblik 	flock(cd_desc, LOCK_UN);
251*e2c5b322SZdenek Styblik 	if (ret != 0) {
252*e2c5b322SZdenek Styblik 		lprintf(LOG_DEBUG,
253*e2c5b322SZdenek Styblik 				"IsG2Drive:Unable to send ID command to the device");
254*e2c5b322SZdenek Styblik 		return 1;
255*e2c5b322SZdenek Styblik 	}
256*e2c5b322SZdenek Styblik 
257*e2c5b322SZdenek Styblik 	if (strncmp(szSignature, "$$$AMI$$$", strlen("$$$AMI$$$")) != 0) {
258*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR,
259*e2c5b322SZdenek Styblik 				"IsG2Drive:Signature mismatch when ID command sent");
260*e2c5b322SZdenek Styblik 		return 1;
261*e2c5b322SZdenek Styblik 	}
262*e2c5b322SZdenek Styblik 
263*e2c5b322SZdenek Styblik 	return 0;
264*e2c5b322SZdenek Styblik }
265*e2c5b322SZdenek Styblik 
266*e2c5b322SZdenek Styblik int
FindG2CDROM(struct ipmi_intf * intf)267*e2c5b322SZdenek Styblik FindG2CDROM(struct ipmi_intf *intf)
268*e2c5b322SZdenek Styblik {
269*e2c5b322SZdenek Styblik 	int err = 0;
270*e2c5b322SZdenek Styblik 	char device[256];
271*e2c5b322SZdenek Styblik 	int devarray[8];
272*e2c5b322SZdenek Styblik 	int numdev = 8;
273*e2c5b322SZdenek Styblik 	int iter;
274*e2c5b322SZdenek Styblik 	err = scsiProbeNew(&numdev, devarray);
275*e2c5b322SZdenek Styblik 
276*e2c5b322SZdenek Styblik 	if (err == 0 && numdev > 0) {
277*e2c5b322SZdenek Styblik 		for (iter = 0; iter < numdev; iter++) {
278*e2c5b322SZdenek Styblik 			sprintf(device, "/dev/sg%d", devarray[iter]);
279*e2c5b322SZdenek Styblik 
280*e2c5b322SZdenek Styblik 			if (!OpenCD(intf, device)) {
281*e2c5b322SZdenek Styblik 				if (!IsG2Drive(intf->fd)) {
282*e2c5b322SZdenek Styblik 					lprintf(LOG_DEBUG, "USB Device found");
283*e2c5b322SZdenek Styblik 					return 1;
284*e2c5b322SZdenek Styblik 				}
285*e2c5b322SZdenek Styblik 				close(intf->fd);
286*e2c5b322SZdenek Styblik 			}
287*e2c5b322SZdenek Styblik 		}
288*e2c5b322SZdenek Styblik 	} else {
289*e2c5b322SZdenek Styblik 		lprintf(LOG_DEBUG, "Unable to find Virtual CDROM Device");
290*e2c5b322SZdenek Styblik 	}
291*e2c5b322SZdenek Styblik 
292*e2c5b322SZdenek Styblik 	return 0;
293*e2c5b322SZdenek Styblik }
294*e2c5b322SZdenek Styblik 
295*e2c5b322SZdenek Styblik static int
ipmi_usb_setup(struct ipmi_intf * intf)296*e2c5b322SZdenek Styblik ipmi_usb_setup(struct ipmi_intf *intf)
297*e2c5b322SZdenek Styblik {
298*e2c5b322SZdenek Styblik 	if (FindG2CDROM(intf) == 0) {
299*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR, "Error in USB session setup \n");
300*e2c5b322SZdenek Styblik 		return (-1);
301*e2c5b322SZdenek Styblik 	}
302*e2c5b322SZdenek Styblik 	intf->opened = 1;
303*e2c5b322SZdenek Styblik 	return 0;
304*e2c5b322SZdenek Styblik }
305*e2c5b322SZdenek Styblik 
306*e2c5b322SZdenek Styblik void
InitCmdHeader(CONFIG_CMD * pG2CDCmdHeader)307*e2c5b322SZdenek Styblik InitCmdHeader(CONFIG_CMD *pG2CDCmdHeader)
308*e2c5b322SZdenek Styblik {
309*e2c5b322SZdenek Styblik 	memset(pG2CDCmdHeader, 0, sizeof(CONFIG_CMD));
310*e2c5b322SZdenek Styblik 	memcpy((char *)pG2CDCmdHeader->BeginSig, BEGIN_SIG, BEGIN_SIG_LEN);
311*e2c5b322SZdenek Styblik }
312*e2c5b322SZdenek Styblik 
313*e2c5b322SZdenek Styblik int
AMI_SPT_CMD_SendCmd(int cd_desc,char * Buffer,char type,uint16_t buflen,unsigned int timeout)314*e2c5b322SZdenek Styblik AMI_SPT_CMD_SendCmd(int cd_desc, char *Buffer, char type, uint16_t buflen,
315*e2c5b322SZdenek Styblik 		unsigned int timeout)
316*e2c5b322SZdenek Styblik {
317*e2c5b322SZdenek Styblik 	SCSI_COMMAND_PACKET Cmdpkt;
318*e2c5b322SZdenek Styblik 	char sensebuff[32];
319*e2c5b322SZdenek Styblik 	int ret;
320*e2c5b322SZdenek Styblik 	unsigned int pktLen;
321*e2c5b322SZdenek Styblik 	int count = 3;
322*e2c5b322SZdenek Styblik 
323*e2c5b322SZdenek Styblik 	memset(&Cmdpkt, 0, sizeof(SCSI_COMMAND_PACKET));
324*e2c5b322SZdenek Styblik 
325*e2c5b322SZdenek Styblik 	Cmdpkt.OpCode = SCSI_AMICMD_CURI_WRITE;
326*e2c5b322SZdenek Styblik 	Cmdpkt.Lba = htonl(type);
327*e2c5b322SZdenek Styblik 	Cmdpkt.CmdLen.Cmd10.Length = htons(1);
328*e2c5b322SZdenek Styblik 
329*e2c5b322SZdenek Styblik 	pktLen = buflen;
330*e2c5b322SZdenek Styblik 	while (count > 0) {
331*e2c5b322SZdenek Styblik 		ret = sendscsicmd_SGIO(cd_desc, (unsigned char *)&Cmdpkt,
332*e2c5b322SZdenek Styblik 				10, Buffer, &pktLen, SG_DXFER_TO_DEV,
333*e2c5b322SZdenek Styblik 				sensebuff, 32, timeout);
334*e2c5b322SZdenek Styblik 		count--;
335*e2c5b322SZdenek Styblik 		if (ret == 0) {
336*e2c5b322SZdenek Styblik 			break;
337*e2c5b322SZdenek Styblik 		} else {
338*e2c5b322SZdenek Styblik 			ret = (-1);
339*e2c5b322SZdenek Styblik 		}
340*e2c5b322SZdenek Styblik 	}
341*e2c5b322SZdenek Styblik 
342*e2c5b322SZdenek Styblik 	return ret;
343*e2c5b322SZdenek Styblik }
344*e2c5b322SZdenek Styblik 
345*e2c5b322SZdenek Styblik int
AMI_SPT_CMD_RecvCmd(int cd_desc,char * Buffer,char type,uint16_t buflen)346*e2c5b322SZdenek Styblik AMI_SPT_CMD_RecvCmd(int cd_desc, char *Buffer, char type, uint16_t buflen)
347*e2c5b322SZdenek Styblik {
348*e2c5b322SZdenek Styblik 	SCSI_COMMAND_PACKET Cmdpkt;
349*e2c5b322SZdenek Styblik 	char sensebuff[32];
350*e2c5b322SZdenek Styblik 	int ret;
351*e2c5b322SZdenek Styblik 	unsigned int pktLen;
352*e2c5b322SZdenek Styblik 	int count = 3;
353*e2c5b322SZdenek Styblik 
354*e2c5b322SZdenek Styblik 	memset(&Cmdpkt, 0, sizeof(SCSI_COMMAND_PACKET));
355*e2c5b322SZdenek Styblik 
356*e2c5b322SZdenek Styblik 	Cmdpkt.OpCode = SCSI_AMICMD_CURI_READ;
357*e2c5b322SZdenek Styblik 	Cmdpkt.Lba = htonl(type);
358*e2c5b322SZdenek Styblik 	Cmdpkt.CmdLen.Cmd10.Length = htons(1);
359*e2c5b322SZdenek Styblik 
360*e2c5b322SZdenek Styblik 	pktLen = buflen;
361*e2c5b322SZdenek Styblik 	while (count > 0) {
362*e2c5b322SZdenek Styblik 		ret = sendscsicmd_SGIO(cd_desc, (unsigned char *)&Cmdpkt,
363*e2c5b322SZdenek Styblik 				10, Buffer, &pktLen, SG_DXFER_FROM_DEV,
364*e2c5b322SZdenek Styblik 				sensebuff, 32, 5000);
365*e2c5b322SZdenek Styblik 		count--;
366*e2c5b322SZdenek Styblik 		if (0 == ret) {
367*e2c5b322SZdenek Styblik 			break;
368*e2c5b322SZdenek Styblik 		} else {
369*e2c5b322SZdenek Styblik 			ret = (-1);
370*e2c5b322SZdenek Styblik 		}
371*e2c5b322SZdenek Styblik 	}
372*e2c5b322SZdenek Styblik 
373*e2c5b322SZdenek Styblik 	return ret;
374*e2c5b322SZdenek Styblik }
375*e2c5b322SZdenek Styblik 
376*e2c5b322SZdenek Styblik int
ReadCD(int cd_desc,char CmdData,char * Buffer,uint32_t DataLen)377*e2c5b322SZdenek Styblik ReadCD(int cd_desc, char CmdData, char *Buffer, uint32_t DataLen)
378*e2c5b322SZdenek Styblik {
379*e2c5b322SZdenek Styblik 	int ret;
380*e2c5b322SZdenek Styblik 
381*e2c5b322SZdenek Styblik 	ret = AMI_SPT_CMD_RecvCmd(cd_desc, Buffer, CmdData, DataLen);
382*e2c5b322SZdenek Styblik 	if (ret != 0) {
383*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR, "Error while reading CD-Drive");
384*e2c5b322SZdenek Styblik 		return (-1);
385*e2c5b322SZdenek Styblik 	}
386*e2c5b322SZdenek Styblik 	return 0;
387*e2c5b322SZdenek Styblik }
388*e2c5b322SZdenek Styblik 
389*e2c5b322SZdenek Styblik int
WriteCD(int cd_desc,char CmdData,char * Buffer,unsigned int timeout,uint32_t DataLen)390*e2c5b322SZdenek Styblik WriteCD(int cd_desc, char CmdData, char *Buffer, unsigned int timeout,
391*e2c5b322SZdenek Styblik 		uint32_t DataLen)
392*e2c5b322SZdenek Styblik {
393*e2c5b322SZdenek Styblik 	int ret;
394*e2c5b322SZdenek Styblik 
395*e2c5b322SZdenek Styblik 	ret = AMI_SPT_CMD_SendCmd(cd_desc, Buffer, CmdData, DataLen, timeout);
396*e2c5b322SZdenek Styblik 	if (ret != 0) {
397*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR, "Error while writing to CD-Drive");
398*e2c5b322SZdenek Styblik 		return (-1);
399*e2c5b322SZdenek Styblik 	}
400*e2c5b322SZdenek Styblik 	return 0;
401*e2c5b322SZdenek Styblik }
402*e2c5b322SZdenek Styblik 
403*e2c5b322SZdenek Styblik int
WriteSplitData(struct ipmi_intf * intf,char * Buffer,char Sector,uint32_t NumBytes,uint32_t timeout)404*e2c5b322SZdenek Styblik WriteSplitData(struct ipmi_intf *intf, char *Buffer, char Sector,
405*e2c5b322SZdenek Styblik 			uint32_t NumBytes, uint32_t timeout)
406*e2c5b322SZdenek Styblik {
407*e2c5b322SZdenek Styblik 	uint32_t BytesWritten = 0;
408*e2c5b322SZdenek Styblik 	int retVal;
409*e2c5b322SZdenek Styblik 
410*e2c5b322SZdenek Styblik 	if (NumBytes == 0) {
411*e2c5b322SZdenek Styblik 		return 0;
412*e2c5b322SZdenek Styblik 	}
413*e2c5b322SZdenek Styblik 
414*e2c5b322SZdenek Styblik 	while (BytesWritten < NumBytes) {
415*e2c5b322SZdenek Styblik 		if ((retVal = WriteCD(intf->fd, Sector,
416*e2c5b322SZdenek Styblik 						(Buffer + BytesWritten),
417*e2c5b322SZdenek Styblik 						timeout, NumBytes)) != 0) {
418*e2c5b322SZdenek Styblik 			return retVal;
419*e2c5b322SZdenek Styblik 		}
420*e2c5b322SZdenek Styblik 
421*e2c5b322SZdenek Styblik 		BytesWritten += NumBytes;
422*e2c5b322SZdenek Styblik 	}
423*e2c5b322SZdenek Styblik 
424*e2c5b322SZdenek Styblik 	return 0;
425*e2c5b322SZdenek Styblik }
426*e2c5b322SZdenek Styblik 
427*e2c5b322SZdenek Styblik int
ReadSplitData(struct ipmi_intf * intf,char * Buffer,char Sector,uint32_t NumBytes)428*e2c5b322SZdenek Styblik ReadSplitData(struct ipmi_intf *intf, char *Buffer, char Sector,
429*e2c5b322SZdenek Styblik 				uint32_t NumBytes)
430*e2c5b322SZdenek Styblik {
431*e2c5b322SZdenek Styblik 	uint32_t BytesRead = 0;
432*e2c5b322SZdenek Styblik 
433*e2c5b322SZdenek Styblik 	if (NumBytes == 0) {
434*e2c5b322SZdenek Styblik 		return 0;
435*e2c5b322SZdenek Styblik 	}
436*e2c5b322SZdenek Styblik 
437*e2c5b322SZdenek Styblik 	while (BytesRead < NumBytes) {
438*e2c5b322SZdenek Styblik 		if (ReadCD(intf->fd, Sector, (Buffer + BytesRead),
439*e2c5b322SZdenek Styblik 					NumBytes) == (-1)) {
440*e2c5b322SZdenek Styblik 			return 1;
441*e2c5b322SZdenek Styblik 		}
442*e2c5b322SZdenek Styblik 		BytesRead += NumBytes;
443*e2c5b322SZdenek Styblik 	}
444*e2c5b322SZdenek Styblik 
445*e2c5b322SZdenek Styblik 	return 0;
446*e2c5b322SZdenek Styblik }
447*e2c5b322SZdenek Styblik 
448*e2c5b322SZdenek Styblik int
WaitForCommandCompletion(struct ipmi_intf * intf,CONFIG_CMD * pG2CDCmdHeader,uint32_t timeout,uint32_t DataLen)449*e2c5b322SZdenek Styblik WaitForCommandCompletion(struct ipmi_intf *intf, CONFIG_CMD *pG2CDCmdHeader,
450*e2c5b322SZdenek Styblik 		uint32_t timeout, uint32_t DataLen)
451*e2c5b322SZdenek Styblik {
452*e2c5b322SZdenek Styblik 	uint32_t TimeCounter = 0;
453*e2c5b322SZdenek Styblik 
454*e2c5b322SZdenek Styblik 	do {
455*e2c5b322SZdenek Styblik 		if (ReadCD(intf->fd, SCSI_AMIDEF_CMD_SECTOR,
456*e2c5b322SZdenek Styblik 					(char *)(pG2CDCmdHeader), DataLen) == (-1)) {
457*e2c5b322SZdenek Styblik 			lprintf(LOG_ERR, "ReadCD returned ERROR");
458*e2c5b322SZdenek Styblik 			return 1;
459*e2c5b322SZdenek Styblik 		}
460*e2c5b322SZdenek Styblik 
461*e2c5b322SZdenek Styblik 		if (pG2CDCmdHeader->Status & IN_PROCESS) {
462*e2c5b322SZdenek Styblik 			usleep(1000);
463*e2c5b322SZdenek Styblik 			if (timeout > 0) {
464*e2c5b322SZdenek Styblik 				TimeCounter++;
465*e2c5b322SZdenek Styblik 				if (TimeCounter == (timeout + 1)) {
466*e2c5b322SZdenek Styblik 					return 2;
467*e2c5b322SZdenek Styblik 				}
468*e2c5b322SZdenek Styblik 			}
469*e2c5b322SZdenek Styblik 		} else {
470*e2c5b322SZdenek Styblik 			lprintf(LOG_DEBUG, "Command completed");
471*e2c5b322SZdenek Styblik 			break;
472*e2c5b322SZdenek Styblik 		}
473*e2c5b322SZdenek Styblik 	} while (1);
474*e2c5b322SZdenek Styblik 
475*e2c5b322SZdenek Styblik 	return 0;
476*e2c5b322SZdenek Styblik }
477*e2c5b322SZdenek Styblik 
478*e2c5b322SZdenek Styblik int
SendDataToUSBDriver(struct ipmi_intf * intf,char * ReqBuffer,unsigned int ReqBuffLen,unsigned char * ResBuffer,int * ResBuffLen,unsigned int timeout)479*e2c5b322SZdenek Styblik SendDataToUSBDriver(struct ipmi_intf *intf, char *ReqBuffer,
480*e2c5b322SZdenek Styblik 			unsigned int ReqBuffLen, unsigned char *ResBuffer,
481*e2c5b322SZdenek Styblik 			int *ResBuffLen, unsigned int timeout)
482*e2c5b322SZdenek Styblik {
483*e2c5b322SZdenek Styblik 	char CmdHeaderBuffer[sizeof(CONFIG_CMD)];
484*e2c5b322SZdenek Styblik 	int retVal;
485*e2c5b322SZdenek Styblik 	int waitretval = 0;
486*e2c5b322SZdenek Styblik 	unsigned int to = 0;
487*e2c5b322SZdenek Styblik 	uint32_t DataLen = 0;
488*e2c5b322SZdenek Styblik 
489*e2c5b322SZdenek Styblik 	CONFIG_CMD *pG2CDCmdHeader = (CONFIG_CMD *)CmdHeaderBuffer;
490*e2c5b322SZdenek Styblik 
491*e2c5b322SZdenek Styblik 	/* FillHeader */
492*e2c5b322SZdenek Styblik 	InitCmdHeader(pG2CDCmdHeader);
493*e2c5b322SZdenek Styblik 
494*e2c5b322SZdenek Styblik 	/* Set command number */
495*e2c5b322SZdenek Styblik 	pG2CDCmdHeader->Command = CMD_RESERVED;
496*e2c5b322SZdenek Styblik 
497*e2c5b322SZdenek Styblik 	/* Fill Lengths */
498*e2c5b322SZdenek Styblik 	pG2CDCmdHeader->DataOutLen = *ResBuffLen;
499*e2c5b322SZdenek Styblik 	pG2CDCmdHeader->DataInLen = ReqBuffLen;
500*e2c5b322SZdenek Styblik 
501*e2c5b322SZdenek Styblik 	if (!timeout) {
502*e2c5b322SZdenek Styblik 		to = 3000;
503*e2c5b322SZdenek Styblik 	}
504*e2c5b322SZdenek Styblik 
505*e2c5b322SZdenek Styblik 	DataLen = sizeof(CONFIG_CMD);
506*e2c5b322SZdenek Styblik 
507*e2c5b322SZdenek Styblik 	if (WriteCD(intf->fd, SCSI_AMIDEF_CMD_SECTOR,
508*e2c5b322SZdenek Styblik 				(char *)(pG2CDCmdHeader), to, DataLen) == (-1)) {
509*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR,
510*e2c5b322SZdenek Styblik 				"Error in Write CD of SCSI_AMIDEF_CMD_SECTOR");
511*e2c5b322SZdenek Styblik 		return (-1);
512*e2c5b322SZdenek Styblik 	}
513*e2c5b322SZdenek Styblik 
514*e2c5b322SZdenek Styblik 	/* Write the data to hard disk */
515*e2c5b322SZdenek Styblik 	if ((retVal = WriteSplitData(intf, ReqBuffer,
516*e2c5b322SZdenek Styblik 					SCSI_AMIDEF_DATA_SECTOR,
517*e2c5b322SZdenek Styblik 					ReqBuffLen, timeout)) != 0) {
518*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR,
519*e2c5b322SZdenek Styblik 				"Error in WriteSplitData of SCSI_AMIDEF_DATA_SECTOR");
520*e2c5b322SZdenek Styblik 		return (-1);
521*e2c5b322SZdenek Styblik 	}
522*e2c5b322SZdenek Styblik 
523*e2c5b322SZdenek Styblik 	if (!timeout) {
524*e2c5b322SZdenek Styblik 		return 0;
525*e2c5b322SZdenek Styblik 	}
526*e2c5b322SZdenek Styblik 
527*e2c5b322SZdenek Styblik 	/* Read Status now */
528*e2c5b322SZdenek Styblik 	waitretval = WaitForCommandCompletion(intf, pG2CDCmdHeader, timeout,
529*e2c5b322SZdenek Styblik 			DataLen);
530*e2c5b322SZdenek Styblik 	if (waitretval != 0) {
531*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR, "WaitForCommandComplete failed");
532*e2c5b322SZdenek Styblik 		return (0 - waitretval);
533*e2c5b322SZdenek Styblik 	} else {
534*e2c5b322SZdenek Styblik 		lprintf(LOG_DEBUG, "WaitForCommandCompletion SUCCESS");
535*e2c5b322SZdenek Styblik 	}
536*e2c5b322SZdenek Styblik 
537*e2c5b322SZdenek Styblik 	switch (pG2CDCmdHeader->Status) {
538*e2c5b322SZdenek Styblik 		case ERR_SUCCESS:
539*e2c5b322SZdenek Styblik 			*ResBuffLen = pG2CDCmdHeader->DataOutLen;
540*e2c5b322SZdenek Styblik 			lprintf(LOG_DEBUG, "Before ReadSplitData %x", *ResBuffLen);
541*e2c5b322SZdenek Styblik 			if (ReadSplitData(intf, (char *)ResBuffer,
542*e2c5b322SZdenek Styblik 						SCSI_AMIDEF_DATA_SECTOR,
543*e2c5b322SZdenek Styblik 						pG2CDCmdHeader->DataOutLen) != 0) {
544*e2c5b322SZdenek Styblik 				lprintf(LOG_ERR,
545*e2c5b322SZdenek Styblik 						"Err ReadSplitData SCSI_AMIDEF_DATA_SCTR");
546*e2c5b322SZdenek Styblik 				return (-1);
547*e2c5b322SZdenek Styblik 			}
548*e2c5b322SZdenek Styblik 			/* Additional read to see verify there was not problem
549*e2c5b322SZdenek Styblik 			 * with the previous read
550*e2c5b322SZdenek Styblik 			 */
551*e2c5b322SZdenek Styblik 			DataLen = sizeof(CONFIG_CMD);
552*e2c5b322SZdenek Styblik 			ReadCD(intf->fd, SCSI_AMIDEF_CMD_SECTOR,
553*e2c5b322SZdenek Styblik 					(char *)(pG2CDCmdHeader), DataLen);
554*e2c5b322SZdenek Styblik 			break;
555*e2c5b322SZdenek Styblik 		case ERR_BIG_DATA:
556*e2c5b322SZdenek Styblik 			lprintf(LOG_ERR, "Too much data");
557*e2c5b322SZdenek Styblik 			break;
558*e2c5b322SZdenek Styblik 		case ERR_NO_DATA:
559*e2c5b322SZdenek Styblik 			lprintf(LOG_ERR, "Too little data");
560*e2c5b322SZdenek Styblik 			break;
561*e2c5b322SZdenek Styblik 		case ERR_UNSUPPORTED:
562*e2c5b322SZdenek Styblik 			lprintf(LOG_ERR, "Unsupported command");
563*e2c5b322SZdenek Styblik 			break;
564*e2c5b322SZdenek Styblik 		default:
565*e2c5b322SZdenek Styblik 			lprintf(LOG_ERR, "Unknown status");
566*e2c5b322SZdenek Styblik 	}
567*e2c5b322SZdenek Styblik 
568*e2c5b322SZdenek Styblik 	return pG2CDCmdHeader->Status;
569*e2c5b322SZdenek Styblik }
570*e2c5b322SZdenek Styblik 
571*e2c5b322SZdenek Styblik static struct ipmi_rs *
ipmi_usb_send_cmd(struct ipmi_intf * intf,struct ipmi_rq * req)572*e2c5b322SZdenek Styblik ipmi_usb_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req)
573*e2c5b322SZdenek Styblik {
574*e2c5b322SZdenek Styblik 	static struct ipmi_rs rsp;
575*e2c5b322SZdenek Styblik 	long timeout = 20000;
576*e2c5b322SZdenek Styblik 	uint8_t byRet = 0;
577*e2c5b322SZdenek Styblik 	char ReqBuff[MAX_REQUEST_SIZE] = {0};
578*e2c5b322SZdenek Styblik 	IPMIUSBRequest_T *pReqPkt = (IPMIUSBRequest_T *)ReqBuff;
579*e2c5b322SZdenek Styblik 	int retries = 0;
580*e2c5b322SZdenek Styblik 	/********** FORM IPMI PACKET *****************/
581*e2c5b322SZdenek Styblik 	pReqPkt->byNetFnLUN = req->msg.netfn << 2;
582*e2c5b322SZdenek Styblik 	pReqPkt->byNetFnLUN += req->msg.lun;
583*e2c5b322SZdenek Styblik 	pReqPkt->byCmd = req->msg.cmd;
584*e2c5b322SZdenek Styblik 	if (req->msg.data_len) {
585*e2c5b322SZdenek Styblik 		memcpy(pReqPkt->byData, req->msg.data, req->msg.data_len);
586*e2c5b322SZdenek Styblik 	}
587*e2c5b322SZdenek Styblik 
588*e2c5b322SZdenek Styblik 	/********** SEND DATA TO USB ******************/
589*e2c5b322SZdenek Styblik 	while (retries < 3) {
590*e2c5b322SZdenek Styblik 		retries++;
591*e2c5b322SZdenek Styblik 		byRet = SendDataToUSBDriver(intf, ReqBuff,
592*e2c5b322SZdenek Styblik 				2 + req->msg.data_len, rsp.data,
593*e2c5b322SZdenek Styblik 				&rsp.data_len,timeout);
594*e2c5b322SZdenek Styblik 
595*e2c5b322SZdenek Styblik 		if (byRet == 0) {
596*e2c5b322SZdenek Styblik 			break;
597*e2c5b322SZdenek Styblik 		}
598*e2c5b322SZdenek Styblik 	}
599*e2c5b322SZdenek Styblik 
600*e2c5b322SZdenek Styblik 	if (retries == 3) {
601*e2c5b322SZdenek Styblik 		lprintf(LOG_ERR,
602*e2c5b322SZdenek Styblik 				"Error while sending command using",
603*e2c5b322SZdenek Styblik 				"SendDataToUSBDriver");
604*e2c5b322SZdenek Styblik 		rsp.ccode = byRet;
605*e2c5b322SZdenek Styblik 		return &rsp;
606*e2c5b322SZdenek Styblik 	}
607*e2c5b322SZdenek Styblik 
608*e2c5b322SZdenek Styblik 	rsp.ccode = rsp.data[0];
609*e2c5b322SZdenek Styblik 
610*e2c5b322SZdenek Styblik 	/* Save response data for caller */
611*e2c5b322SZdenek Styblik 	if ((rsp.ccode == 0) && (rsp.data_len > 0)) {
612*e2c5b322SZdenek Styblik 		memmove(rsp.data, rsp.data + 1, rsp.data_len - 1);
613*e2c5b322SZdenek Styblik 		rsp.data[rsp.data_len] = 0;
614*e2c5b322SZdenek Styblik 		rsp.data_len -= 1;
615*e2c5b322SZdenek Styblik 	}
616*e2c5b322SZdenek Styblik 	return &rsp;
617*e2c5b322SZdenek Styblik }
618