8 # include <sys/ioctl.h>
9 # ifdef HAVE_LINUX_COMPILER_H
10 # include <linux/compiler.h>
12 # if defined(HAVE_LINUX_CCISS_IOCTL_H)
13 # include <linux/cciss_ioctl.h>
16 # include <asm/byteorder.h>
17 # define be32toh __be32_to_cpu
18 #elif defined(__FreeBSD__) && defined(HAVE_DEV_CISS_CISSIO_H)
19 # include <sys/endian.h>
20 # include <dev/ciss/cissio.h>
22 #elif defined(__FreeBSD_kernel__) && defined(HAVE_DEV_CISS_CISSIO_H)
24 # include <dev/ciss/cissio.h>
33 const char *cciss_c_cvsid
="$Id: cciss.cpp,v 1.9 2008/07/30 20:42:53 chrfranke Exp $"
34 CONFIG_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID
;
36 typedef struct _ReportLUNdata_struct
38 uint32_t LUNListLength
; /* always big-endian */
40 uint8_t LUN
[CISS_MAX_LUN
][8];
41 } ReportLunData_struct
;
43 /* Structure/defines of Report Physical LUNS of drive */
45 #define CISS_MAX_LUN 16
47 #define CISS_MAX_PHYS_LUN 1024
48 #define CISS_REPORT_PHYS 0xc3
50 #define LSCSI_DRIVER_SENSE 0x8 /* alternate CHECK CONDITION indication */
51 #define SEND_IOCTL_RESP_SENSE_LEN 16 /* ioctl limitation */
53 static int cciss_getlun(int device
, int target
, unsigned char *physlun
, int report
);
54 static int cciss_sendpassthru(unsigned int cmdtype
, unsigned char *CDB
,
55 unsigned int CDBlen
, char *buff
,
56 unsigned int size
, unsigned int LunID
,
57 unsigned char *scsi3addr
, int fd
);
60 This is an interface that uses the cciss passthrough to talk to the SMART controller on
61 the HP system. The cciss driver provides a way to send SCSI cmds through the CCISS passthrough.
63 int cciss_io_interface(int device
, int target
, struct scsi_cmnd_io
* iop
, int report
)
65 unsigned char pBuf
[512] = {0};
66 unsigned char phylun
[8] = {0};
69 int len
= 0; // used later in the code.
71 status
= cciss_getlun(device
, target
, phylun
, report
);
73 printf(" cciss_getlun(%d, %d) = 0x%x; scsi3addr: %02x %02x %02x %02x %02x %02x %02x %02x\n",
74 device
, target
, status
,
75 phylun
[0], phylun
[1], phylun
[2], phylun
[3], phylun
[4], phylun
[5], phylun
[6], phylun
[7]);
77 return -ENXIO
; /* give up, assume no device there */
80 status
= cciss_sendpassthru( 2, iop
->cmnd
, iop
->cmnd_len
, (char*) pBuf
, iBufLen
, 1, phylun
, device
);
85 printf(" status=0\n");
86 if (DXFER_FROM_DEVICE
== iop
->dxfer_dir
)
88 memcpy(iop
->dxferp
, pBuf
, iop
->dxfer_len
);
91 int trunc
= (iop
->dxfer_len
> 256) ? 1 : 0;
92 printf(" Incoming data, len=%d%s:\n", (int)iop
->dxfer_len
,
93 (trunc
? " [only first 256 bytes shown]" : ""));
94 dStrHex((const char*)iop
->dxferp
, (trunc
? 256 : iop
->dxfer_len
) , 1);
99 iop
->scsi_status
= status
& 0x7e; /* bits 0 and 7 used to be for vendors */
100 if (LSCSI_DRIVER_SENSE
== ((status
>> 24) & 0xf))
101 iop
->scsi_status
= SCSI_STATUS_CHECK_CONDITION
;
102 len
= (SEND_IOCTL_RESP_SENSE_LEN
< iop
->max_sense_len
) ?
103 SEND_IOCTL_RESP_SENSE_LEN
: iop
->max_sense_len
;
104 if ((SCSI_STATUS_CHECK_CONDITION
== iop
->scsi_status
) &&
105 iop
->sensep
&& (len
> 0))
107 memcpy(iop
->sensep
, pBuf
, len
);
108 iop
->resp_sense_len
= iBufLen
;
111 printf(" >>> Sense buffer, len=%d:\n", (int)len
);
112 dStrHex((const char *)pBuf
, len
, 1);
117 if (SCSI_STATUS_CHECK_CONDITION
== iop
->scsi_status
) {
118 printf(" status=%x: sense_key=%x asc=%x ascq=%x\n", status
& 0xff,
119 pBuf
[2] & 0xf, pBuf
[12], pBuf
[13]);
122 printf(" status=0x%x\n", status
);
124 if (iop
->scsi_status
> 0)
129 printf(" ioctl status=0x%x but scsi status=0, fail with ENXIO\n", status
);
130 return -ENXIO
; /* give up, assume no device there */
134 static int cciss_sendpassthru(unsigned int cmdtype
, unsigned char *CDB
,
135 unsigned int CDBlen
, char *buff
,
136 unsigned int size
, unsigned int LunID
,
137 unsigned char *scsi3addr
, int fd
)
140 IOCTL_Command_struct iocommand
;
142 memset(&iocommand
, 0, sizeof(iocommand
));
146 // To controller; nothing to do
148 else if (cmdtype
== 1)
150 iocommand
.LUN_info
.LogDev
.VolId
= LunID
;
151 iocommand
.LUN_info
.LogDev
.Mode
= 1;
153 else if (cmdtype
== 2)
155 memcpy(&iocommand
.LUN_info
.LunAddrBytes
,scsi3addr
,8);
156 iocommand
.LUN_info
.LogDev
.Mode
= 0;
160 fprintf(stderr
, "cciss_sendpassthru: bad cmdtype\n");
164 memcpy(&iocommand
.Request
.CDB
[0], CDB
, CDBlen
);
165 iocommand
.Request
.CDBLen
= CDBlen
;
166 iocommand
.Request
.Type
.Type
= TYPE_CMD
;
167 iocommand
.Request
.Type
.Attribute
= ATTR_SIMPLE
;
168 iocommand
.Request
.Type
.Direction
= XFER_READ
;
169 iocommand
.Request
.Timeout
= 0;
171 iocommand
.buf_size
= size
;
172 iocommand
.buf
= (unsigned char *)buff
;
174 if ((err
= ioctl(fd
, CCISS_PASSTHRU
, &iocommand
)))
176 fprintf(stderr
, "CCISS ioctl error %d (fd %d CDBLen %d buf_size %d)\n",
177 fd
, err
, CDBlen
, size
);
182 static int cciss_getlun(int device
, int target
, unsigned char *physlun
, int report
)
184 unsigned char CDB
[16]= {0};
185 ReportLunData_struct
*luns
;
186 int reportlunsize
= sizeof(*luns
) + CISS_MAX_PHYS_LUN
* 8;
189 luns
= (ReportLunData_struct
*)malloc(reportlunsize
);
191 memset(luns
, 0, reportlunsize
);
193 /* Get Physical LUN Info (for physical device) */
194 CDB
[0] = CISS_REPORT_PHYS
;
195 CDB
[6] = (reportlunsize
>> 24) & 0xFF; /* MSB */
196 CDB
[7] = (reportlunsize
>> 16) & 0xFF;
197 CDB
[8] = (reportlunsize
>> 8) & 0xFF;
198 CDB
[9] = reportlunsize
& 0xFF;
200 if ((ret
= cciss_sendpassthru(0, CDB
, 12, (char *)luns
, reportlunsize
, 0, NULL
, device
)))
209 unsigned char *stuff
= (unsigned char *)luns
;
211 pout("\n===== [%s] DATA START (BASE-16) =====\n", "LUN DATA");
212 for (i
=0; i
<(sizeof(_ReportLUNdata_struct
)+15)/16; i
++){
213 pout("%03d-%03d: ", 16*i
, 16*(i
+1)-1);
215 pout("%02x ",*stuff
++);
216 pout("%02x\n",*stuff
++);
218 pout("===== [%s] DATA END (%u Bytes) =====\n\n", "LUN DATA", (unsigned)sizeof(_ReportLUNdata_struct
));
221 if (target
>= 0 && target
< (int) be32toh(luns
->LUNListLength
) / 8)
223 memcpy(physlun
, luns
->LUN
[target
], 8);