12#include <sys/endian.h>
20#include <cam/scsi/scsi_message.h>
21#include <cam/scsi/scsi_pass.h>
22#if defined(__DragonFly__)
33#include <sys/utsname.h>
38#undef ATA_READ_LOG_EXT
49#define USBDEV "/dev/usb"
50#if defined(__FreeBSD_version)
53#define FREEBSDVER __FreeBSD_version
55#define FREEBSDVER __FreeBSD_kernel_version
58#if (FREEBSDVER >= 800000)
59#include <libusb20_desc.h>
61#elif defined(__DragonFly__)
62#include <bus/usb/usb.h>
63#include <bus/usb/usbhid.h>
65#include <dev/usb/usb.h>
66#include <dev/usb/usbhid.h>
72#define CONTROLLER_3WARE_9000_CHAR 0x01
73#define CONTROLLER_3WARE_678K_CHAR 0x02
75#ifndef PATHINQ_SETTINGS_SIZE
76#define PATHINQ_SETTINGS_SIZE 128
79const char *
os_XXXX_c_cvsid=
"$Id: os_freebsd.cpp 5468 2023-03-14 20:01:29Z chrfranke $" \
84#define NO_DISK_3WARE 2
91 if (msgNo >= 0 && msgNo <=
MAX_MSG) {
92 static int printed[] = {0,0,0,0};
93 if (!printed[msgNo]) {
95 static const char* message[]={
96 "The SMART RETURN STATUS return value (smartmontools -H option/Directive)\n can not be retrieved with this version of ATAng, please do not rely on this value\nYou should update to at least 5.2\n",
98 "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_URL
"\nRegister values returned from SMART Status command are:\n",
100 "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n",
102 "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n"
106 pout(
"%s", message[msgNo]);
116#define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) )
117#define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) )
118#define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) )
121#define ATA_DEVICE "/dev/ata"
124#define ARGUSED(x) ((void)(x))
149 virtual bool close();
164static inline void * reallocf(
void *ptr,
size_t size) {
165 void *rv = realloc(ptr,
size);
166 if((rv == NULL) && (
size != 0))
184 "=================================================== SMARTCTL EXAMPLES =====\n\n"
185 " smartctl -a /dev/ad0 (Prints all SMART information)\n\n"
186 " smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n"
187 " (Enables SMART on first disk)\n\n"
188 " smartctl -t long /dev/ad0 (Executes extended disk self-test)\n\n"
189 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n"
190 " (Prints Self-Test & Attribute errors)\n"
191 " (Prints Self-Test & Attribute errors)\n\n"
192 " smartctl -a --device=3ware,2 /dev/twa0\n"
193 " smartctl -a --device=3ware,2 /dev/twe0\n"
194 " smartctl -a --device=3ware,2 /dev/tws0\n"
195 " (Prints all SMART information for ATA disk on\n"
196 " third port of first 3ware RAID controller)\n"
197 " smartctl -a --device=cciss,0 /dev/ciss0\n"
198 " (Prints all SMART information for first disk \n"
199 " on Common Interface for SCSI-3 Support driver)\n"
200 " smartctl -a --device=areca,3/1 /dev/arcmsr0\n"
201 " (Prints all SMART information for 3rd disk in the 1st enclosure \n"
202 " on first ARECA RAID controller)\n"
203 " smartctl -a --device=megaraid,3 /dev/mrsas0\n"
204 " (Prints all SMART information for 3rd disk\n"
205 " on first LSI RAID controller)\n"
234 if(failed)
return false;
250 virtual int do_cmd(
struct ata_ioc_request* request,
bool is_48bit_cmd);
263 ret = ioctl(fd, IOCATAREQUEST, request);
272 bool ata_48bit =
false;
281 set_err(ENOSYS,
"48-bit ATA commands not implemented for legacy controllers");
285 struct ata_ioc_request request;
286 memset(&request, 0,
sizeof(
struct ata_ioc_request));
297 request.flags=ATA_CMD_CONTROL;
300 request.flags=ATA_CMD_READ | ATA_CMD_CONTROL;
301 request.data=(
char *)in.
buffer;
302 request.count=in.
size;
305 request.flags=ATA_CMD_WRITE | ATA_CMD_CONTROL;
306 request.data=(
char *)in.
buffer;
307 request.count=in.
size;
318 return set_err(EIO,
"request failed, error code 0x%02x", request.error);
327#if FREEBSDVER > 800100
331 freebsd_atacam_device(
smart_interface * intf,
const char * dev_name,
const char * req_type)
336 virtual bool close();
340 struct cam_device *m_camdev;
342 virtual int do_cmd(
struct ata_ioc_request* request ,
bool is_48bit_cmd);
345bool freebsd_atacam_device::open(){
346 const char *dev = get_dev_name();
348 if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
352 set_fd(m_camdev->fd);
356bool freebsd_atacam_device::close(){
357 cam_close_device(m_camdev);
362int freebsd_atacam_device::do_cmd(
struct ata_ioc_request* request,
bool is_48bit_cmd)
371#if (FREEBSDVER < 902001)
372 if(!strcmp(
"ata",m_camdev->sim_name) && is_48bit_cmd) {
373 set_err(ENOSYS,
"48-bit ATA commands not implemented for legacy controllers");
378 memset(&ccb, 0,
sizeof(ccb));
380 if (request->count == 0)
381 camflags = CAM_DIR_NONE;
382 else if (request->flags & ATA_CMD_READ)
383 camflags = CAM_DIR_IN;
385 camflags = CAM_DIR_OUT;
387 cam_fill_ataio(&ccb.ataio,
392 (u_int8_t*)request->data,
394 request->timeout * 1000);
396 ccb.ataio.cmd.flags = CAM_ATAIO_NEEDRESULT |
397 (is_48bit_cmd ? CAM_ATAIO_48BIT : 0);
399 ccb.ataio.cmd.command = request->u.ata.command;
400 ccb.ataio.cmd.features = request->u.ata.feature;
401 ccb.ataio.cmd.lba_low = request->u.ata.lba;
402 ccb.ataio.cmd.lba_mid = request->u.ata.lba >> 8;
403 ccb.ataio.cmd.lba_high = request->u.ata.lba >> 16;
405 ccb.ataio.cmd.lba_low_exp = request->u.ata.lba >> 24;
406 ccb.ataio.cmd.lba_mid_exp = request->u.ata.lba >> 32;
407 ccb.ataio.cmd.lba_high_exp = request->u.ata.lba >> 40;
408 ccb.ataio.cmd.device = 0x40 | ((request->u.ata.lba >> 24) & 0x0f);
409 ccb.ataio.cmd.sector_count = request->u.ata.count;
410 ccb.ataio.cmd.sector_count_exp = request->u.ata.count >> 8;;
412 ccb.ccb_h.flags |= CAM_DEV_QFRZDIS;
414 if (cam_send_ccb(m_camdev, &ccb) < 0) {
415 set_err(EIO,
"cam_send_ccb failed");
419 if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
421 cam_error_print(m_camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
427 ((u_int64_t)(ccb.ataio.res.lba_low)) |
428 ((u_int64_t)(ccb.ataio.res.lba_mid) << 8) |
429 ((u_int64_t)(ccb.ataio.res.lba_high) << 16) |
430 ((u_int64_t)(ccb.ataio.res.lba_low_exp) << 24) |
431 ((u_int64_t)(ccb.ataio.res.lba_mid_exp) << 32) |
432 ((u_int64_t)(ccb.ataio.res.lba_high_exp) << 40);
434 request->u.ata.count = ccb.ataio.res.sector_count | (ccb.ataio.res.sector_count_exp << 8);
435 request->error = ccb.ataio.res.error;
451 const char * req_type,
unsigned nsid);
453 virtual bool open()
override;
459 const char * req_type,
unsigned nsid)
470 set_err(EINVAL,
"NVMe controller controller/namespace ids must begin with '%s'",
475 int nsid = -1, ctrlid = -1;
481 set_err(EINVAL,
"Invalid NVMe controller number");
487 &ctrlid, &
nsid, &tmp) == 2)
489 if(ctrlid < 0 ||
nsid < 0) {
490 set_err(EINVAL,
"Invalid NVMe controller/namespace number");
495 set_err(EINVAL,
"Invalid NVMe controller/namespace syntax");
504 if ((fd =
::open(full_path, O_RDWR))<0) {
522 memset(&pt, 0,
sizeof(pt));
524#if __FreeBSD_version >= 1200058 && __FreeBSD_version < 1200081
525 pt.
cmd.opc_fuse = NVME_CMD_SET_OPC(in.
opcode);
543 return set_err(errno,
"NVME_PASSTHROUGH_CMD: %s", strerror(errno));
544#if __FreeBSD_version >= 1200058
545 nvme_completion_swapbytes(&pt.
cpl);
566 int escalade_type,
int disknum);
570 virtual bool open()
override;
578 int escalade_type,
int disknum)
581 m_escalade_type(escalade_type), m_disknum(disknum)
591 if ((fd =
::open(dev,O_RDWR))<0) {
613 TWE_Command_ATA* ata = NULL;
636 "Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n"
643 ata->request_id = 0xFF;
656 ata->drive_head = r.
device;
667 bool readdata =
false;
675 ata->sgl_offset = 0x5;
687 ata->sgl_offset = 0x0;
689 ata->sector_count = 0x0;
692 ata->sgl_offset = 0x5;
735 if (ata->status || (ata->command & 0x21)) {
737 pout(
"Command failed, ata.status=(0x%2.2x), ata.command=(0x%2.2x), ata.flags=(0x%2.2x)\n",ata->status,ata->command,ata->flags);
752 r.
error = ata->features;
757 r.
device = ata->drive_head;
783 virtual bool open()
override;
784 virtual bool close()
override;
794 int senseLen,
void *sense,
int report,
int direction,
int timeout);
796 int senseLen,
void *sense,
int report,
int direction,
int timeout);
800 const char *dev_name,
unsigned int tgt)
803 m_disknum(tgt), m_hba(0),
829 unsigned char req_buff[64] = {0, };
833 set_err(EIO,
"INQUIRY failed");
837 int avail_len = req_buff[4] + 5;
838 int len = (avail_len < req_len ? avail_len : req_len);
843 pout(
"Got MegaRAID inquiry.. %s\n", req_buff+8);
887 const unsigned char * ucp = iop->
cmnd;
890 const int sz = (int)
sizeof(buff);
893 j = snprintf(buff, sz,
" [%s: ", np ? np :
"<unknown opcode>");
894 for (k = 0; k < (int)iop->
cmnd_len; ++k)
895 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"%02x ", ucp[k]);
898 int trunc = (iop->
dxfer_len > 256) ? 1 : 0;
900 snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"]\n Outgoing "
901 "data, len=%d%s:\n", (
int)iop->
dxfer_len,
902 (trunc ?
" [only first 256 bytes shown]" :
""));
906 snprintf(&buff[j], (sz > j ? (sz - j) : 0),
"]\n");
911 if (iop->
cmnd[0] == 0x00)
916 if (iop->
cmnd[2] & (1 << 5))
917 return set_err(ENOSYS,
"ATA return descriptor not supported by controller firmware");
926 return set_err(ENOSYS,
"SMART WRITE LOG SECTOR may cause problems, try with -T permissive to force");
936 int dataLen,
void *
data,
937 int senseLen,
void * sense,
int ,
int dxfer_dir,
int timeout)
943 memset(&uio, 0,
sizeof(uio));
946 pthru->header.cmd_status = 0;
947 pthru->header.scsi_status = 0x0;
949 pthru->header.lun_id = 0;
951 pthru->header.sense_len = senseLen;
952 pthru->sense_addr_lo = (uintptr_t)sense ;
953 pthru->sense_addr_hi = (uintptr_t)((uint64_t)sense >> 32);
955 pthru->header.cdb_len = cdbLen;
973 uio.
mfi_sgl[0].iov_len = dataLen;
975 pthru->header.sg_count = 1;
976 pthru->header.data_len = dataLen;
978 pthru->sgl.sg64[0].addr = (intptr_t)
data;
979 pthru->sgl.sg64[0].len = (uint32_t)dataLen;
990 if (
pthru->header.cmd_status || rc != 0) {
991 if (
pthru->header.cmd_status == 12) {
994 return set_err((errno ? errno : EIO),
"megasas_cmd result: %d.%d = %d/%d",
996 pthru->header.cmd_status);
1011 unsigned char controller,
unsigned char channel,
unsigned char port);
1015 virtual bool open()
override;
1023 unsigned char controller,
unsigned char channel,
unsigned char port)
1036 if ((fd =
::open(dev,O_RDWR))<0) {
1061 param.
in = (
unsigned char *)ids;
1062 param.
in_size =
sizeof(
unsigned int) * 2;
1063 param.
out = (
unsigned char *)&info;
1076 memset(buff, 0,
sizeof(buff));
1079 pide_pt_hdr->lbamid = 0x4f;
1080 pide_pt_hdr->lbahigh = 0xc2;
1095 pide_pt_hdr->lbalow=select;
1110 pide_pt_hdr->sectorcount=select;
1114 pide_pt_hdr->sectorcount=select;
1118 pide_pt_hdr->lbalow=select;
1130 pide_pt_hdr->lbalow=select;
1134 pout(
"Unrecognized command %d in highpoint_command_interface()\n"
1135 "Please contact " PACKAGE_BUGREPORT
"\n", command);
1139 if (pide_pt_hdr->protocol!=0) {
1140 pide_pt_hdr->sectors = 1;
1141 pide_pt_hdr->sectorcount = 1;
1148 param.
in = (
unsigned char *)buff;
1150 param.
out = (
unsigned char *)buff+param.
in_size;
1156 (pide_pt_hdr_out->command & 1)) {
1162 unsigned const char normal_lo=0x4f, normal_hi=0xc2;
1163 unsigned const char failed_lo=0xf4, failed_hi=0x2c;
1164 unsigned char low,high;
1166 high = pide_pt_hdr_out->lbahigh;
1167 low = pide_pt_hdr_out->lbamid;
1170 if (low==normal_lo && high==normal_hi)
1174 if (low==failed_lo && high==failed_hi)
1179 snprintf(buf,
sizeof(buf),
1180 "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n",
1181 (
int)pide_pt_hdr_out->command,
1182 (
int)pide_pt_hdr_out->feature,
1183 (
int)pide_pt_hdr_out->sectorcount,
1184 (
int)pide_pt_hdr_out->lbalow,
1185 (
int)pide_pt_hdr_out->lbamid,
1186 (
int)pide_pt_hdr_out->lbahigh,
1187 (
int)pide_pt_hdr_out->sectors);
1191 data[0] = pide_pt_hdr_out->sectorcount & 0xff;
1192 else if (pide_pt_hdr->protocol==
HPT_READ)
1194 pide_pt_hdr->sectors * 512);
1213 virtual bool open()
override;
1215 virtual bool close()
override;
1224 if ((
m_camdev = cam_open_device(dev, O_RDWR)) == NULL) {
1239 const char * dev_name,
const char * req_type)
1253 const unsigned char * ucp = iop->
cmnd;
1257 pout(
" [%s: ", np ? np :
"<unknown opcode>");
1258 for (k = 0; k < iop->
cmnd_len; ++k)
1259 pout(
"%02x ", ucp[k]);
1262 int trunc = (iop->
dxfer_len > 256) ? 1 : 0;
1265 (trunc ?
" [only first 256 bytes shown]" :
""));
1274 pout(
" error: camdev=0!\n");
1278 if (!(ccb = cam_getccb(
m_camdev))) {
1280 pout(
" error allocating ccb\n");
1285 if(!strcmp(
"mfi",
m_camdev->sim_name)) {
1288 if (iop->
cmnd[2] & (1 << 5))
1289 return set_err(ENOSYS,
"ATA return descriptor not supported by controller firmware");
1299 return set_err(ENOSYS,
"SMART WRITE LOG SECTOR may cause problems, try with -T permissive to force");
1303 memset(&(&ccb->ccb_h)[1], 0,
sizeof(
struct ccb_scsiio) -
sizeof(
struct ccb_hdr));
1305 cam_fill_csio(&ccb->csio,
1315 memcpy(ccb->csio.cdb_io.cdb_bytes,iop->
cmnd,iop->
cmnd_len);
1317 if (cam_send_ccb(
m_camdev,ccb) < 0) {
1319 pout(
" error sending SCSI ccb\n");
1320 cam_error_print(
m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
1327 pout(
" CAM status=0x%x, SCSI status=0x%x, resid=0x%x\n",
1328 ccb->ccb_h.status, ccb->csio.scsi_status, ccb->csio.resid);
1333 trunc = (len > 256) ? 1 : 0;
1335 pout(
" Incoming data, len=%d%s:\n", len,
1336 (trunc ?
" [only first 256 bytes shown]" :
""));
1340 pout(
" Incoming data trimmed to nothing by resid\n");
1344 if (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR)) {
1346 cam_error_print(
m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr);
1351 iop->
resid = ccb->csio.resid;
1353 if (iop->
sensep && (ccb->ccb_h.status & CAM_AUTOSNS_VALID) != 0) {
1355 pout(
" sense_len=0x%x, sense_resid=0x%x\n",
1356 ccb->csio.sense_len, ccb->csio.sense_resid);
1357 iop->
resp_sense_len = ccb->csio.sense_len - ccb->csio.sense_resid;
1369 if ((iop->
sensep[0] & 0x7f) > 0x71)
1370 pout(
" status=0x%x: [desc] sense_key=0x%x asc=0x%x ascq=0x%x\n",
1374 pout(
" status=0x%x: sense_key=0x%x asc=0x%x ascq=0x%x\n",
1389 if((!strcmp(
"mfi",
m_camdev->sim_name) || !strcmp(
"mpt",
m_camdev->sim_name))
1392 pout(
" device on %s controller, patching PDT\n",
m_camdev->sim_name);
1471 int ioctlreturn = 0;
1516 int ioctlreturn = 0;
1555 virtual bool open()
override;
1565 if ((fd =
::open(dev,O_RDWR))<0) {
1574 const char * dev_name,
unsigned char disknum)
1609 unsigned char req_buff[64] = {0, };
1618 set_err(EIO,
"INQUIRY failed");
1623 int avail_len = req_buff[4] + 5;
1624 int len = (avail_len < req_len ? avail_len : req_len);
1631 if (!memcmp(req_buff + 8,
"3ware", 5) || !memcmp(req_buff + 8,
"AMCC", 4) ||
1634 set_err(EINVAL,
"3ware/LSI controller, please try adding '-d 3ware,N',\n"
1635 "you may need to replace %s with /dev/twaN, /dev/tweN or /dev/twsN",
get_dev_name());
1640 if (!memcmp(req_buff + 8,
"DELL PERC", 12) || !memcmp(req_buff + 8,
"MegaRAID", 8)
1641 || !memcmp(req_buff + 16,
"PERC ", 5) || !memcmp(req_buff + 8,
"LSI\0",4)
1644 set_err(EINVAL,
"DELL or MegaRaid controller, use '-d megaraid,N'");
1653 if(!strcmp(
"mfi",
m_camdev->sim_name)) {
1655 newdev->
set_err(ENOSYS,
"SATA device detected,\n"
1656 "MegaRAID SAT layer is reportedly buggy, use '-d sat' to try anyhow");
1679 const char * pattern = 0)
override;
1684#if FREEBSDVER > 800100
1685 virtual ata_device * get_atacam_device(
const char * name,
const char * type);
1691 unsigned nsid)
override;
1703 size_t bufsize, uint8_t *
mbox,
size_t mboxlen, uint8_t *statusp);
1711 struct utsname osname;
1713 return strprintf(
"%s %s %s", osname.sysname, osname.release, osname.machine);
1718 if (!strcmp(appname,
"smartctl"))
1728#if FREEBSDVER > 800100
1729ata_device * freebsd_smart_interface::get_atacam_device(
const char * name,
const char * type)
1731 return new freebsd_atacam_device(
this, name, type);
1763 if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
1764 if (errno == ENOENT)
1767 pout(
"%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno));
1773 memset(&ccb, 0,
sizeof(
union ccb));
1775 ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
1776 ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
1777 ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
1779 ccb.ccb_h.func_code = XPT_DEV_MATCH;
1780 int bufsize =
sizeof(
struct dev_match_result) *
MAX_NUM_DEV;
1781 ccb.cdm.match_buf_len = bufsize;
1783 ccb.cdm.matches = (
struct dev_match_result *)malloc(bufsize);
1784 memset(ccb.cdm.matches, 0, bufsize);
1786 if (ccb.cdm.matches == NULL) {
1788 throw std::bad_alloc();
1790 ccb.cdm.num_matches = 0;
1791 ccb.cdm.num_patterns = 0;
1792 ccb.cdm.pattern_buf_len = 0;
1798 int skip_device = 0, skip_bus = 0, changed = 0;
1799 std::string devname;
1801 if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
1803 pout(
"error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno));
1804 free(ccb.cdm.matches);
1810 if ((ccb.ccb_h.status != CAM_REQ_CMP)
1811 || ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
1812 && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
1813 pout(
"got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status);
1814 free(ccb.cdm.matches);
1820 for (
unsigned i = 0; i < ccb.cdm.num_matches; i++) {
1821 struct device_match_result *dev_result;
1822 struct periph_match_result *periph_result;
1824 if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) {
1825 struct bus_match_result *bus_result;
1827 bus_result = &ccb.cdm.matches[i].result.bus_result;
1829 if (strcmp(bus_result->dev_name,
"xpt") == 0)
1834 }
else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) {
1835 dev_result = &ccb.cdm.matches[i].result.device_result;
1837 if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1)
1843 if (dev_result->inq_data.device == T_ENCLOSURE)
1850 }
else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH &&
1851 (skip_device == 0 || show_all)) {
1855 periph_result = &ccb.cdm.matches[i].result.periph_result;
1857 if (devname.empty() || strncmp(periph_result->periph_name,
"pass", 4) != 0) {
1858 devname =
strprintf(
"%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number);
1862 if ((changed == 1 || show_all) && !devname.empty()) {
1863 names.push_back(devname);
1869 }
while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE));
1871 if (!devname.empty())
1872 names.push_back(devname);
1874 free(ccb.cdm.matches);
1889 struct ata_ioc_devices
devices;
1890 int fd=-1,maxchannel,serrno=-1,n=0;
1896 if (errno == ENOENT)
1899 pout(
"%s control device can't be opened: %s\n",
ATA_DEVICE, strerror(errno));
1904 if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) {
1906 pout(
"ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno));
1915 pout(
"Out of memory constructing scan device list (on line %d)\n", __LINE__);
1923 if (ioctl(fd, IOCATADEVICES, &
devices) < 0) {
1926 pout(
"ioctl(IOCATADEVICES) on %s channel %d failed: %s\n",
ATA_DEVICE,
devices.channel, strerror(errno));
1931 if (
devices.name[j][0] !=
'\0') {
1932 asprintf(mp+n,
"%s%s", _PATH_DEV,
devices.name[j]);
1933 if (mp[n] == NULL) {
1934 pout(
"Out of memory constructing scan ATA device list (on line %d)\n", __LINE__);
1944 mp = (
char **)reallocf(mp,n*(
sizeof (
char*)));
1947 pout(
"Out of memory constructing scan device list (on line %d)\n", __LINE__);
1970 const char * type,
const char * pattern )
1973 set_err(EINVAL,
"DEVICESCAN with pattern not implemented yet");
1977#ifdef WITH_NVME_DEVICESCAN
1978 bool scan_nvme = !type || !strcmp(type,
"nvme");
1980 bool scan_nvme = type && !strcmp(type,
"nvme");
1984 char * * atanames = 0;
int numata = 0;
1985 if (!type || !strcmp(type,
"ata")) {
1993 std::vector<std::string> scsinames;
1994 if (!type || !strcmp(type,
"scsi")) {
2005 for (i = 0; i < numata; i++) {
2011 if(numata) free(atanames);
2013 for (i = 0; i < (int)scsinames.size(); i++) {
2039 for (
int ctrlr = 0;; ctrlr++) {
2041 int fd = ::open(ctrlpath, O_RDWR);
2061 for(
unsigned i = 0; i <=32; i++) {
2072 size_t bufsize, uint8_t *
mbox,
size_t mboxlen, uint8_t *statusp)
2078 (
mbox == NULL && mboxlen != 0))
2084 memset(&ioc, 0,
sizeof(ioc));
2090 dcmd->header.data_len = bufsize;
2096 ioc.
mfi_sgl[0].iov_base = buf;
2097 ioc.
mfi_sgl[0].iov_len = bufsize;
2098 dcmd->header.sg_count = 1;
2099 dcmd->header.data_len = bufsize;
2101 dcmd->
sgl.sg64[0].addr = (intptr_t)buf;
2102 dcmd->
sgl.sg64[0].len = (uint32_t)bufsize;
2106 if ((fd = ::open(devname, O_RDWR)) < 0) {
2110 int r = ioctl(fd,
MFI_CMD, &ioc);
2116 if (statusp != NULL)
2119 fprintf(stderr,
"command %x returned error status %x\n",
2135 for (
unsigned list_size = 1024; ; ) {
2136 list =
reinterpret_cast<mfi_pd_list *
>(realloc(list, list_size));
2138 throw std::bad_alloc();
2139 memset(list, 0, list_size);
2146 if (list->
size <= list_size)
2148 list_size = list->
size;
2152 for (
unsigned i = 0; i < list->
count; i++) {
2162#if (FREEBSDVER < 800000)
2165static int usbdevinfo(
int f,
int a,
int rec,
int busno,
unsigned short & vendor_id,
2166 unsigned short & product_id,
unsigned short & version)
2169 struct usb_device_info di;
2173 snprintf(devname,
sizeof(devname),
"umass%d",busno);
2176 e = ioctl(f, USB_DEVICEINFO, &di);
2179 printf(
"addr %d: I/O error\n", a);
2185 for (i = 0; i < USB_MAX_DEVNAMES; i++) {
2186 if (di.udi_devnames[i][0]) {
2187 if(strcmp(di.udi_devnames[i],devname)==0) {
2189 vendor_id = di.udi_vendorNo;
2190 product_id = di.udi_productNo;
2191 version = di.udi_releaseNo;
2199 for (p = 0; p < di.udi_nports; p++) {
2200 int s = di.udi_ports[p];
2201 if (
s >= USB_MAX_DEVICES) {
2205 printf(
"addr 0 should never happen!\n");
2207 if(
usbdevinfo(f,
s, 1, busno, vendor_id, product_id, version))
return 1;
2216 unsigned short & product_id,
unsigned short & version)
2218#if (FREEBSDVER >= 800000)
2219 struct libusb20_device *pdev = NULL;
2220 struct libusb20_backend *pbe;
2221 uint32_t matches = 0;
2225 struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
2227 pbe = libusb20_be_alloc_default();
2229 while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
2232 if (libusb20_dev_open(pdev, 0)) {
2233 warnx(
"libusb20_dev_open: could not open device");
2237 pdesc=libusb20_dev_get_device_desc(pdev);
2239 snprintf(devname,
sizeof(devname),
"umass%d:",busno);
2240 for (n = 0; n != 255; n++) {
2241 if (libusb20_dev_get_iface_desc(pdev, n, buf,
sizeof(buf)))
2245 if(strncmp(buf,devname,strlen(devname))==0){
2247 vendor_id = pdesc->idVendor;
2248 product_id = pdesc->idProduct;
2249 version = pdesc->bcdDevice;
2250 libusb20_dev_close(pdev);
2251 libusb20_be_free(pbe);
2256 libusb20_dev_close(pdev);
2260 printf(
"No device match or lack of permissions.\n");
2263 libusb20_be_free(pbe);
2272 for (ncont = 0, i = 0; i < 10; i++) {
2273 snprintf(buf,
sizeof(buf),
"%s%d",
USBDEV, i);
2274 int f = open(buf, O_RDONLY);
2277 for (a = 1; a < USB_MAX_DEVICES; a++) {
2279 rc =
usbdevinfo(f, a, 1, busno,vendor_id, product_id, version);
2286 if (errno == ENOENT || errno == ENXIO)
2298 unsigned short vendor_id = 0, product_id = 0, version = 0;
2299 struct cam_device *cam_dev;
2302 const char * test_name = name;
2304 memset(&ccb, 0,
sizeof(ccb));
2307 if (!name || !*name)
2312 std::string pathbuf;
2313 if (!lstat(name, &st) && S_ISLNK(st.st_mode)) {
2314 char * p = realpath(name, (
char *)0);
2318 test_name = pathbuf.c_str();
2323 char * * atanames = 0;
int numata = 0;
2327 for (i = 0; i < numata; i++) {
2328 if(!strcmp(atanames[i],test_name)) {
2329 for (
int c = i; c < numata; c++) free(atanames[c]);
2333 else free(atanames[i]);
2339 pout(
"Unable to get ATA device list\n");
2343 std::vector<std::string> scsinames;
2345 pout(
"Unable to get CAM device list\n");
2346 else if (!scsinames.empty()) {
2348 for (i = 0; i < (int)scsinames.size(); i++) {
2349 if(strcmp(scsinames[i].c_str(), test_name)==0)
2351 if(strncmp(scsinames[i].c_str(),
"/dev/pmp", strlen(
"/dev/pmp")) == 0) {
2352 pout(
"Skipping port multiplier [%s]\n", scsinames[i].c_str());
2356 if ((cam_dev = cam_open_device(test_name, O_RDWR)) == NULL) {
2363 ccb.ccb_h.func_code = XPT_PATH_INQ;
2364 if (ioctl(cam_dev->fd, CAMIOCOMMAND, &ccb) == -1) {
2365 warn(
"Get Transfer Settings CCB failed\n"
2366 "%s", strerror(errno));
2367 cam_close_device(cam_dev);
2371 if(strcmp(ccb.cpi.dev_name,
"umass-sim") == 0) {
2372 int bus=ccb.cpi.unit_number;
2373 cam_close_device(cam_dev);
2374 if(
usbdevlist(bus,vendor_id, product_id, version)){
2381#if FREEBSDVER > 800100
2383 if(ccb.cpi.protocol == PROTO_ATA){
2384 cam_close_device(cam_dev);
2385 return new freebsd_atacam_device(
this, test_name,
"");
2389 cam_close_device(cam_dev);
2396 if(!strncmp(
"/dev/mfid", test_name, strlen(
"/dev/mfid"))) {
2397 set_err(EINVAL,
"To access disks on LSI RAID load mfip.ko and use /dev/passX or use -d 'megaraid,N' with /dev/mfiX devices");
2402 set_err(EINVAL,
"To access disks on %s use '-d megaraid,N' device type", test_name);
2407 if(!strncmp(
"/dev/nvme", test_name, strlen(
"/dev/nvme")))
2409 if(!strncmp(
"/dev/nvd", test_name, strlen(
"/dev/nvd")))
2410 set_err(EINVAL,
"To monitor NVMe disks use /dev/nvme* device names");
2419 int disknum = -1, n1 = -1, n2 = -1;
2421 if (sscanf(type,
"3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
2423 static const char * fbsd_dev_twe_ctrl =
"/dev/twe";
2424 static const char * fbsd_dev_twa_ctrl =
"/dev/twa";
2425 static const char * fbsd_dev_tws_ctrl =
"/dev/tws";
2428 if (n2 != (
int)strlen(type)) {
2429 set_err(EINVAL,
"Option -d 3ware,N requires N to be a non-negative integer");
2432 if (!(0 <= disknum && disknum <= 127)) {
2433 set_err(EINVAL,
"Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum);
2442 if (!strncmp(fbsd_dev_twe_ctrl, name, strlen(fbsd_dev_twe_ctrl))){
2447 set_err(EINVAL,
"3ware controller type unknown, use %sX, %sX or %sX devices",
2448 fbsd_dev_twe_ctrl, fbsd_dev_twa_ctrl, fbsd_dev_tws_ctrl);
2455 int controller = -1, channel = -1; disknum = 1;
2456 n1 = n2 = -1;
int n3 = -1;
2457 if (sscanf(type,
"hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) {
2458 int len = strlen(type);
2459 if (!(n2 == len || n3 == len)) {
2460 set_err(EINVAL,
"Option '-d hpt,L/M/N' supports 2-3 items");
2463 if (!(1 <= controller && controller <= 8)) {
2464 set_err(EINVAL,
"Option '-d hpt,L/M/N' invalid controller id L supplied");
2467 if (!(1 <= channel && channel <= 128)) {
2468 set_err(EINVAL,
"Option '-d hpt,L/M/N' invalid channel number M supplied");
2471 if (!(1 <= disknum && disknum <= 15)) {
2472 set_err(EINVAL,
"Option '-d hpt,L/M/N' invalid pmport number N supplied");
2479 disknum = n1 = n2 = -1;
2480 if (sscanf(type,
"cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) {
2481 if (n2 != (
int)strlen(type)) {
2482 set_err(EINVAL,
"Option -d cciss,N requires N to be a non-negative integer");
2485 if (!(0 <= disknum && disknum <= 127)) {
2486 set_err(EINVAL,
"Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum);
2491#if FREEBSDVER > 800100
2493 if(!strcmp(type,
"atacam"))
2494 return new freebsd_atacam_device(
this, name,
"");
2497 disknum = n1 = n2 = -1;
2499 if (sscanf(type,
"areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) {
2500 if (!(1 <= disknum && disknum <= 128)) {
2501 set_err(EINVAL,
"Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum);
2504 if (!(1 <= encnum && encnum <= 8)) {
2505 set_err(EINVAL,
"Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum);
2511 if (sscanf(type,
"megaraid,%d", &disknum) == 1) {
2520 return "3ware,N, hpt,L/M/N, cciss,N, areca,N/E, megaraid,N"
2521#if FREEBSDVER > 800100
#define ATA_SMART_AUTO_OFFLINE
#define ATA_IDENTIFY_DEVICE
#define ATA_SMART_WRITE_LOG_SECTOR
#define ATA_IDENTIFY_PACKET_DEVICE
#define ATA_SMART_READ_VALUES
#define ATA_SMART_READ_THRESHOLDS
#define ATA_SMART_READ_LOG_SECTOR
#define ATA_SMART_IMMEDIATE_OFFLINE
#define ATA_SMART_AUTOSAVE
#define ATA_SMART_DISABLE
#define ATA_CHECK_POWER_MODE
int cciss_io_interface(int device, int target, struct scsi_cmnd_io *iop, int report)
Smart pointer class for device pointers.
device_type * release()
Return the pointer and release ownership.
Adapter class to implement new ATA pass through old interface.
bool ata_cmd_is_ok(const ata_cmd_in &in, bool data_out_support=false, bool multi_sector_support=false, bool ata_48bit_support=false)
Check command input parameters (old version).
virtual int arcmsr_get_dev_type()
void set_disknum(int disknum)
void set_encnum(int encnum)
unsigned get_nsid() const
Get namespace id.
bool set_nvme_err(nvme_cmd_out &out, unsigned status, const char *msg=0)
Set last error number and message if pass-through returns NVMe error status.
void set_nsid(unsigned nsid)
Set namespace id.
freebsd_areca_ata_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
virtual smart_device * autodetect_open() override
Open device with autodetection support.
virtual bool arcmsr_unlock() override
virtual bool arcmsr_lock() override
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop) override
virtual bool arcmsr_lock() override
virtual smart_device * autodetect_open() override
Open device with autodetection support.
virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io *iop) override
virtual bool arcmsr_unlock() override
freebsd_areca_scsi_device(smart_interface *intf, const char *dev_name, int disknum, int encnum=1)
Implement standard ATA support.
virtual int do_cmd(struct ata_ioc_request *request, bool is_48bit_cmd)
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override
ATA pass through.
freebsd_ata_device(smart_interface *intf, const char *dev_name, const char *req_type)
Implement CCISS RAID support with old functions.
virtual bool open() override
Open device, return false on error.
virtual bool scsi_pass_through(scsi_cmnd_io *iop) override
SCSI pass through.
unsigned char m_disknum
Disk number.
freebsd_cciss_device(smart_interface *intf, const char *name, unsigned char disknum)
Implement AMCC/3ware RAID support.
virtual bool ata_pass_through(const ata_cmd_in &in, ata_cmd_out &out) override
ATA pass through.
int m_disknum
Disk number.
virtual bool open() override
Open device, return false on error.
int m_escalade_type
Type string for escalade_command_interface().
freebsd_escalade_device(smart_interface *intf, const char *dev_name, int escalade_type, int disknum)
Implement Highpoint RAID support with old functions.
freebsd_highpoint_device(smart_interface *intf, const char *dev_name, unsigned char controller, unsigned char channel, unsigned char port)
virtual int ata_command_interface(smart_command_set command, int select, char *data) override
Old ATA interface called by ata_pass_through()
virtual bool open() override
Open device, return false on error.
unsigned char m_hpt_data[3]
controller/channel/port
virtual bool close() override
Close device, return false on error.
bool(freebsd_megaraid_device::* pt_cmd)(int cdblen, void *cdb, int dataLen, void *data, int senseLen, void *sense, int report, int direction, int timeout)
virtual smart_device * autodetect_open() override
Open device with autodetection support.
bool megasas_cmd(int cdbLen, void *cdb, int dataLen, void *data, int senseLen, void *sense, int report, int direction, int timeout)
virtual ~freebsd_megaraid_device()
virtual bool open() override
Open device, return false on error.
freebsd_megaraid_device(smart_interface *intf, const char *name, unsigned int tgt)
virtual bool scsi_pass_through(scsi_cmnd_io *iop) override
SCSI pass through.
freebsd_nvme_device(smart_interface *intf, const char *dev_name, const char *req_type, unsigned nsid)
virtual bool nvme_pass_through(const nvme_cmd_in &in, nvme_cmd_out &out) override
NVMe pass through.
virtual bool open() override
Open device, return false on error.
freebsd_scsi_device(smart_interface *intf, const char *dev_name, const char *req_type)
virtual bool open() override
Open device, return false on error.
struct cam_device * m_camdev
virtual bool scsi_pass_through(scsi_cmnd_io *iop) override
SCSI pass through.
virtual bool close() override
Close device, return false on error.
virtual smart_device * autodetect_open() override
SCSI open with autodetection support.
Implement shared open/close routines with old functions.
virtual ~freebsd_smart_device()
virtual bool open()
Open device, return false on error.
virtual bool is_open() const
Return true if device is open.
int get_fd() const
Return filedesc for derived classes.
int m_fd
filedesc, -1 if not open.
virtual bool close()
Close device, return false on error.
Implement platform interface with old functions.
virtual scsi_device * get_scsi_device(const char *name, const char *type) override
Return standard SCSI device.
virtual smart_device * get_custom_smart_device(const char *name, const char *type) override
Return device for platform specific 'type'.
virtual std::string get_app_examples(const char *appname) override
Return example string for program 'appname'.
virtual smart_device * autodetect_smart_device(const char *name) override
Autodetect device if no device type specified.
int megaraid_pd_add_list(const char *devname, smart_device_list &devlist)
bool get_nvme_devlist(smart_device_list &devlist, const char *type)
int megaraid_dcmd_cmd(const char *devname, uint32_t opcode, void *buf, size_t bufsize, uint8_t *mbox, size_t mboxlen, uint8_t *statusp)
bool get_dev_megaraid(smart_device_list &devlist)
virtual ata_device * get_ata_device(const char *name, const char *type) override
Return standard ATA device.
virtual std::string get_os_version_str() override
Return info string about build host and/or OS version.
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0) override
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'.
virtual std::string get_valid_custom_dev_types_str() override
Return valid 'type' args accepted by above.
virtual nvme_device * get_nvme_device(const char *name, const char *type, unsigned nsid) override
Return standard NVMe device.
List of devices for DEVICESCAN.
void push_back(smart_device *dev)
Base class for all devices.
smart_interface * smi()
Get interface which produced this object.
const char * get_req_type() const
Get type requested by user, empty if none.
const char * get_dev_type() const
Get device type.
virtual bool close()=0
Close device, return false on error.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
bool is_ata() const
Return true if ATA device.
device_info & set_info()
R/W access to device info struct.
const char * get_dev_name() const
Get device (path)name.
void clear_err()
Clear last error info.
The platform interface abstraction.
static void set(smart_interface *intf)
Set interface to use, must be called from init().
virtual const char * get_usb_dev_type_by_id(int vendor_id, int product_id, int version=-1)
Get type name for USB device with known VENDOR:PRODUCT ID.
virtual ata_device * get_sat_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI filter for a SAT or USB 'type'.
static void init()
Initialize platform interface and register with smi().
virtual smart_device * get_scsi_passthrough_device(const char *type, scsi_device *scsidev)
Return ATA->SCSI of NVMe->SCSI filter for a SAT, SNT or USB 'type'.
virtual ata_device * autodetect_sat_device(scsi_device *scsidev, const unsigned char *inqdata, unsigned inqsize)
Try to detect a SAT device behind a SCSI interface.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
#define NVME_CTRLR_PREFIX
#define NVME_PASSTHROUGH_CMD
#define nvme_completion_is_error(cpl)
#define MFI_FRAME_DIR_WRITE
#define MFI_FRAME_DIR_NONE
#define MFI_DCMD_PD_GET_LIST
struct megasas_dcmd_frame dcmd
#define MFI_FRAME_DIR_READ
#define MFI_CMD_PD_SCSI_IO
static const char smartctl_examples[]
static int usbdevlist(int busno, unsigned short &vendor_id, unsigned short &product_id, unsigned short &version)
bool get_dev_names_cam(std::vector< std::string > &names, bool show_all)
unsigned char m_controller_type
static int usbdevinfo(int f, int a, int rec, int busno, unsigned short &vendor_id, unsigned short &product_id, unsigned short &version)
static char done[USB_MAX_DEVICES]
int get_dev_names_ata(char ***names)
unsigned char m_controller_port
static struct @44 devices[20]
#define CONTROLLER_3WARE_9000_CHAR
unsigned char failuretest_permissive
const char * os_XXXX_c_cvsid
#define PATHINQ_SETTINGS_SIZE
void printwarning(int msgNo, const char *extra)
#define TW_IOCTL_BUFFER_SIZE
#define CONTROLLER_3WARE_678K_CHAR
struct _HPT_PASS_THROUGH_HEADER * PHPT_PASS_THROUGH_HEADER
#define MRSAS_CTRLR_PREFIX
#define TWE_OP_ATA_PASSTHROUGH
#define HPT_IOCTL_GET_CHANNEL_INFO_V2
#define OS_FREEBSD_H_CVSID
#define HPT_IOCTL_IDE_PASS_THROUGH
struct _HPT_CHANNEL_INFO HPT_CHANNEL_INFO
struct _HPT_CHANNEL_INFO_V2 HPT_CHANNEL_INFO_V2
#define HPT_IOCTL_GET_CHANNEL_INFO
#define TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH
struct _HPT_PASS_THROUGH_HEADER HPT_PASS_THROUGH_HEADER
int scsiStdInquiry(scsi_device *device, uint8_t *pBuf, int bufLen)
void dStrHex(const uint8_t *up, int len, int no_ascii)
unsigned char scsi_debugmode
const char * scsi_get_opcode_name(const uint8_t *cdbp)
#define SAT_ATA_PASSTHROUGH_12
#define DXFER_FROM_DEVICE
#define SCSI_TIMEOUT_DEFAULT
#define SAT_ATA_PASSTHROUGH_16
void pout(const char *fmt,...)
unsigned int devices[PMPORT_PER_CHANNEL]
ATA pass through input parameters.
enum ata_cmd_in::@29 direction
I/O direction.
void * buffer
Pointer to data buffer.
ata_in_regs_48bit in_regs
Input registers.
unsigned size
Size of buffer.
ATA pass through output parameters.
ata_out_regs_48bit out_regs
Output registers.
ATA Input registers for 48-bit commands.
bool is_48bit_cmd() const
Return true if 48-bit command.
ata_reg_alias_16 lba_high_16
ata_reg_alias_16 sector_count_16
ata_reg_alias_16 features_16
ata_reg_alias_16 lba_low_16
ata_reg_alias_16 lba_mid_16
ATA Output registers for 48-bit commands.
ata_reg_alias_16 lba_mid_16
ata_reg_alias_16 sector_count_16
ata_reg_alias_16 lba_low_16
ata_reg_alias_16 lba_high_16
union megasas_dcmd_frame::@38 mbox
struct iovec mfi_sgl[MAX_IOCTL_SGE]
union mfi_ioc_packet::@50 mfi_frame
struct mfi_pd_address addr[MAX_SYS_PDS]
NVMe pass through input parameters.
unsigned char opcode
Opcode (CDW0 07:00)
unsigned size
Size of buffer.
unsigned cdw15
Cmd specific.
unsigned nsid
Namespace ID.
void * buffer
Pointer to data buffer.
NVMe pass through output parameters.
unsigned result
Command specific result (DW0)
struct nvme_completion cpl
std::string info_name
Informal name.
std::string dev_type
Actual device type.
union tw_cl_command_7k cmd_pkt_7k
union tw_cl_command_packet::@48 command
struct tw_cl_driver_packet driver_pkt
struct tw_cl_command_packet cmd_pkt
std::string strprintf(const char *fmt,...)
bool nonempty(const void *data, int size)
bool str_starts_with(const char *str, const char *prefix)