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