1 /* 2 * Copyright (c) 2016-2021 Chuck Tuffli <chuck@tuffli.net> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <fcntl.h> 19 #include <string.h> 20 #include <err.h> 21 #include <errno.h> 22 #include <camlib.h> 23 #include <cam/scsi/scsi_message.h> 24 25 #include "libsmart.h" 26 #include "libsmart_priv.h" 27 #include "libsmart_dev.h" 28 29 /* Provide compatibility for FreeBSD 11.0 */ 30 #if (__FreeBSD_version < 1101000) 31 32 struct scsi_log_informational_exceptions { 33 struct scsi_log_param_header hdr; 34 #define SLP_IE_GEN 0x0000 35 uint8_t ie_asc; 36 uint8_t ie_ascq; 37 uint8_t temperature; 38 }; 39 40 #endif 41 42 struct fbsd_smart { 43 smart_t common; 44 struct cam_device *camdev; 45 }; 46 47 static smart_protocol_e __device_get_proto(struct fbsd_smart *); 48 static bool __device_proto_tunneled(struct fbsd_smart *); 49 static int32_t __device_get_info(struct fbsd_smart *); 50 51 smart_h 52 device_open(smart_protocol_e protocol, char *devname) 53 { 54 struct fbsd_smart *h = NULL; 55 56 h = malloc(sizeof(struct fbsd_smart)); 57 if (h == NULL) 58 return NULL; 59 60 memset(h, 0, sizeof(struct fbsd_smart)); 61 62 h->common.protocol = SMART_PROTO_MAX; 63 h->camdev = cam_open_device(devname, O_RDWR); 64 if (h->camdev == NULL) { 65 printf("%s: error opening %s - %s\n", 66 __func__, devname, 67 cam_errbuf); 68 free(h); 69 h = NULL; 70 } else { 71 smart_protocol_e proto = __device_get_proto(h); 72 73 if ((protocol == SMART_PROTO_AUTO) || 74 (protocol == proto)) { 75 h->common.protocol = proto; 76 } else { 77 printf("%s: protocol mismatch %d vs %d\n", 78 __func__, protocol, proto); 79 } 80 81 if (proto == SMART_PROTO_SCSI) { 82 if (__device_proto_tunneled(h)) { 83 h->common.protocol = SMART_PROTO_ATA; 84 h->common.info.tunneled = 1; 85 } 86 } 87 88 __device_get_info(h); 89 } 90 91 return h; 92 } 93 94 void 95 device_close(smart_h h) 96 { 97 struct fbsd_smart *fsmart = h; 98 99 if (fsmart != NULL) { 100 if (fsmart->camdev != NULL) { 101 cam_close_device(fsmart->camdev); 102 } 103 104 free(fsmart); 105 } 106 } 107 108 static const uint8_t smart_read_data[] = { 109 0xb0, 0xd0, 0x00, 0x4f, 0xc2, 0x00, 110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 111 }; 112 113 static const uint8_t smart_return_status[] = { 114 0xb0, 0xda, 0x00, 0x4f, 0xc2, 0x00, 115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 116 }; 117 118 static int32_t 119 __device_read_ata(smart_h h, uint32_t page, void *buf, size_t bsize, union ccb *ccb) 120 { 121 struct fbsd_smart *fsmart = h; 122 const uint8_t *smart_fis; 123 uint32_t smart_fis_size = 0; 124 uint32_t flags = 0; 125 uint16_t sector_count = 0; 126 uint8_t protocol = 0; 127 128 switch (page) { 129 case PAGE_ID_ATA_SMART_READ_DATA: /* Support SMART READ DATA */ 130 smart_fis = smart_read_data; 131 smart_fis_size = sizeof(smart_read_data); 132 flags = CAM_DIR_IN; 133 sector_count = 1; 134 protocol = AP_PROTO_PIO_IN; 135 break; 136 case PAGE_ID_ATA_SMART_RET_STATUS: /* Support SMART RETURN STATUS */ 137 smart_fis = smart_return_status; 138 smart_fis_size = sizeof(smart_return_status); 139 /* Command has no data but uses the return status */ 140 flags = CAM_DIR_NONE; 141 protocol = AP_PROTO_NON_DATA; 142 bsize = 0; 143 break; 144 default: 145 return EINVAL; 146 } 147 148 if (fsmart->common.info.tunneled) { 149 struct ata_pass_16 *cdb; 150 uint8_t cdb_flags; 151 152 if (bsize > 0) { 153 cdb_flags = AP_FLAG_TDIR_FROM_DEV | 154 AP_FLAG_BYT_BLOK_BLOCKS | 155 AP_FLAG_TLEN_SECT_CNT; 156 } else { 157 cdb_flags = AP_FLAG_CHK_COND | 158 AP_FLAG_TDIR_FROM_DEV | 159 AP_FLAG_BYT_BLOK_BLOCKS; 160 } 161 162 cdb = (struct ata_pass_16 *)ccb->csio.cdb_io.cdb_bytes; 163 memset(cdb, 0, sizeof(*cdb)); 164 165 scsi_ata_pass_16(&ccb->csio, 166 /*retries*/ 1, 167 /*cbfcnp*/ NULL, 168 /*flags*/ flags, 169 /*tag_action*/ MSG_SIMPLE_Q_TAG, 170 /*protocol*/ protocol, 171 /*ata_flags*/ cdb_flags, 172 /*features*/ page, 173 /*sector_count*/sector_count, 174 /*lba*/ 0, 175 /*command*/ ATA_SMART_CMD, 176 /*control*/ 0, 177 /*data_ptr*/ buf, 178 /*dxfer_len*/ bsize, 179 /*sense_len*/ SSD_FULL_SIZE, 180 /*timeout*/ 5000 181 ); 182 cdb->lba_mid = 0x4f; 183 cdb->lba_high = 0xc2; 184 cdb->device = 0; /* scsi_ata_pass_16() sets this */ 185 } else { 186 memcpy(&ccb->ataio.cmd.command, smart_fis, smart_fis_size); 187 188 cam_fill_ataio(&ccb->ataio, 189 /* retries */1, 190 /* cbfcnp */NULL, 191 /* flags */flags, 192 /* tag_action */0, 193 /* data_ptr */buf, 194 /* dxfer_len */bsize, 195 /* timeout */5000); 196 ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT; 197 ccb->ataio.cmd.control = 0; 198 } 199 200 return 0; 201 } 202 203 static int32_t 204 __device_read_scsi(__attribute__((unused)) smart_h h, uint32_t page, void *buf, size_t bsize, union ccb *ccb) 205 { 206 207 scsi_log_sense(&ccb->csio, 208 /* retries */1, 209 /* cbfcnp */NULL, 210 /* tag_action */0, 211 /* page_code */SLS_PAGE_CTRL_CUMULATIVE, 212 /* page */page, 213 /* save_pages */0, 214 /* ppc */0, 215 /* paramptr */0, 216 /* param_buf */buf, 217 /* param_len */bsize, 218 /* sense_len */0, 219 /* timeout */5000); 220 221 return 0; 222 } 223 224 static int32_t 225 __device_read_nvme(__attribute__((unused)) smart_h h, uint32_t page, void *buf, size_t bsize, union ccb *ccb) 226 { 227 struct ccb_nvmeio *nvmeio = &ccb->nvmeio; 228 uint32_t numd = 0; /* number of dwords */ 229 230 /* 231 * NVME CAM passthru 232 * 1200000 > version > 1101510 uses nvmeio->cmd.opc 233 * 1200059 > version > 1200038 uses nvmeio->cmd.opc 234 * 1200081 > version > 1200058 uses nvmeio->cmd.opc_fuse 235 * > 1200080 uses nvmeio->cmd.opc 236 * This code doesn't support the brief 'opc_fuse' period. 237 */ 238 #if ((__FreeBSD_version > 1200038) || ((__FreeBSD_version > 1101510) && (__FreeBSD_version < 1200000))) 239 switch (page) { 240 case NVME_LOG_HEALTH_INFORMATION: 241 numd = (sizeof(struct nvme_health_information_page) / sizeof(uint32_t)); 242 break; 243 default: 244 /* Unsupported log page */ 245 return EINVAL; 246 } 247 248 /* Subtract 1 because NUMD is a zero based value */ 249 numd--; 250 251 nvmeio->cmd.opc = NVME_OPC_GET_LOG_PAGE; 252 nvmeio->cmd.nsid = NVME_GLOBAL_NAMESPACE_TAG; 253 nvmeio->cmd.cdw10 = page | (numd << 16); 254 255 cam_fill_nvmeadmin(&ccb->nvmeio, 256 /* retries */1, 257 /* cbfcnp */NULL, 258 /* flags */CAM_DIR_IN, 259 /* data_ptr */buf, 260 /* dxfer_len */bsize, 261 /* timeout */5000); 262 #endif 263 return 0; 264 } 265 266 /* 267 * Retrieve the SMART RETURN STATUS 268 * 269 * SMART RETURN STATUS provides the reliability status of the 270 * device and can be used as a high-level indication of health. 271 */ 272 static int32_t 273 __device_status_ata(smart_h h, union ccb *ccb) 274 { 275 struct fbsd_smart *fsmart = h; 276 uint8_t *buf = NULL; 277 uint32_t page = 0; 278 uint8_t lba_high = 0, lba_mid = 0, device = 0, status = 0; 279 280 if (fsmart->common.info.tunneled) { 281 struct ata_res_pass16 { 282 u_int16_t reserved[5]; 283 u_int8_t flags; 284 u_int8_t error; 285 u_int8_t sector_count_exp; 286 u_int8_t sector_count; 287 u_int8_t lba_low_exp; 288 u_int8_t lba_low; 289 u_int8_t lba_mid_exp; 290 u_int8_t lba_mid; 291 u_int8_t lba_high_exp; 292 u_int8_t lba_high; 293 u_int8_t device; 294 u_int8_t status; 295 } *res_pass16 = (struct ata_res_pass16 *)(uintptr_t) 296 &ccb->csio.sense_data; 297 298 buf = ccb->csio.data_ptr; 299 page = ((struct ata_pass_16 *)ccb->csio.cdb_io.cdb_bytes)->features; 300 lba_high = res_pass16->lba_high; 301 lba_mid = res_pass16->lba_mid; 302 device = res_pass16->device; 303 status = res_pass16->status; 304 305 /* 306 * Note that this generates an expected CHECK CONDITION. 307 * Mask it so the outer function doesn't print an error 308 * message. 309 */ 310 ccb->ccb_h.status &= ~CAM_STATUS_MASK; 311 ccb->ccb_h.status |= CAM_REQ_CMP; 312 } else { 313 struct ccb_ataio *ataio = (struct ccb_ataio *)&ccb->ataio; 314 315 buf = ataio->data_ptr; 316 page = ataio->cmd.features; 317 lba_high = ataio->res.lba_high; 318 lba_mid = ataio->res.lba_mid; 319 device = ataio->res.device; 320 status = ataio->res.status; 321 } 322 323 switch (page) { 324 case PAGE_ID_ATA_SMART_RET_STATUS: 325 /* 326 * Typically, SMART related log pages return data, but this 327 * command is different in that the data is encoded in the 328 * result registers. 329 * 330 * Handle this in a UNIX-like way by writing a 0 (no errors) 331 * or 1 (threshold exceeded condition) to the output buffer. 332 */ 333 dprintf("SMART_RET_STATUS: lba mid=%#x high=%#x device=%#x status=%#x\n", 334 lba_mid, 335 lba_high, 336 device, 337 status); 338 if ((lba_high == 0x2c) && (lba_mid == 0xf4)) { 339 buf[0] = 1; 340 } else if ((lba_high == 0xc2) && (lba_mid == 0x4f)) { 341 buf[0] = 0; 342 } else { 343 /* Ruh-roh ... */ 344 buf[0] = 255; 345 } 346 break; 347 default: 348 ; 349 } 350 351 return 0; 352 } 353 354 int32_t 355 device_read_log(smart_h h, uint32_t page, void *buf, size_t bsize) 356 { 357 struct fbsd_smart *fsmart = h; 358 union ccb *ccb = NULL; 359 int rc = 0; 360 361 if (fsmart == NULL) 362 return EINVAL; 363 364 dprintf("read log page %#x\n", page); 365 366 ccb = cam_getccb(fsmart->camdev); 367 if (ccb == NULL) 368 return ENOMEM; 369 370 CCB_CLEAR_ALL_EXCEPT_HDR(ccb); 371 372 switch (fsmart->common.protocol) { 373 case SMART_PROTO_ATA: 374 rc = __device_read_ata(h, page, buf, bsize, ccb); 375 break; 376 case SMART_PROTO_SCSI: 377 rc = __device_read_scsi(h, page, buf, bsize, ccb); 378 break; 379 case SMART_PROTO_NVME: 380 rc = __device_read_nvme(h, page, buf, bsize, ccb); 381 break; 382 default: 383 warnx("unsupported protocol %d", fsmart->common.protocol); 384 cam_freeccb(ccb); 385 return ENODEV; 386 } 387 388 if (rc) { 389 if (rc == EINVAL) 390 warnx("unsupported page %#x", page); 391 392 return rc; 393 } 394 395 if (((rc = cam_send_ccb(fsmart->camdev, ccb)) < 0) 396 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 397 if (rc < 0) 398 warn("error sending command"); 399 } 400 401 /* 402 * Most commands don't need any post-processing. But then there's 403 * ATA. It's why we can't have nice things :( 404 */ 405 switch (fsmart->common.protocol) { 406 case SMART_PROTO_ATA: 407 __device_status_ata(h, ccb); 408 break; 409 default: 410 ; 411 } 412 413 if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 414 cam_error_print(fsmart->camdev, ccb, CAM_ESF_ALL, 415 CAM_EPF_ALL, stderr); 416 } 417 418 cam_freeccb(ccb); 419 420 return 0; 421 } 422 423 /* 424 * The SCSI / ATA Translation (SAT) requires devices to support the ATA 425 * Information VPD Page (T10/2126-D Revision 04). Use the existence of 426 * this page to identify tunneled devices. 427 */ 428 static bool 429 __device_proto_tunneled(struct fbsd_smart *fsmart) 430 { 431 union ccb *ccb = NULL; 432 struct scsi_vpd_supported_page_list supportedp; 433 uint32_t i; 434 bool is_tunneled = false; 435 436 if (fsmart->common.protocol != SMART_PROTO_SCSI) { 437 return false; 438 } 439 440 ccb = cam_getccb(fsmart->camdev); 441 if (!ccb) { 442 warn("Allocation failure ccb=%p", ccb); 443 goto __device_proto_tunneled_out; 444 } 445 446 scsi_inquiry(&ccb->csio, 447 3, // retries 448 NULL, // callback function 449 MSG_SIMPLE_Q_TAG, // tag action 450 (uint8_t *)&supportedp, 451 sizeof(struct scsi_vpd_supported_page_list), 452 1, // EVPD 453 SVPD_SUPPORTED_PAGE_LIST, // page code 454 SSD_FULL_SIZE, // sense length 455 5000); // timeout 456 457 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 458 459 if ((cam_send_ccb(fsmart->camdev, ccb) >= 0) && 460 ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) { 461 dprintf("Looking for page %#x (total = %u):\n", SVPD_ATA_INFORMATION, 462 supportedp.length); 463 for (i = 0; i < supportedp.length; i++) { 464 dprintf("\t[%u] = %#x\n", i, supportedp.list[i]); 465 if (supportedp.list[i] == SVPD_ATA_INFORMATION) { 466 is_tunneled = true; 467 break; 468 } 469 } 470 } 471 472 cam_freeccb(ccb); 473 474 __device_proto_tunneled_out: 475 return is_tunneled; 476 } 477 478 /** 479 * Retrieve the device protocol type via the transport settings 480 * 481 * @return protocol type or SMART_PROTO_MAX on error 482 */ 483 static smart_protocol_e 484 __device_get_proto(struct fbsd_smart *fsmart) 485 { 486 smart_protocol_e proto = SMART_PROTO_MAX; 487 union ccb *ccb; 488 489 if (!fsmart || !fsmart->camdev) { 490 warn("Bad handle %p", fsmart); 491 return proto; 492 } 493 494 ccb = cam_getccb(fsmart->camdev); 495 if (ccb != NULL) { 496 CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->cts); 497 498 ccb->ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 499 ccb->cts.type = CTS_TYPE_CURRENT_SETTINGS; 500 501 if (cam_send_ccb(fsmart->camdev, ccb) >= 0) { 502 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 503 struct ccb_trans_settings *cts = &ccb->cts; 504 505 switch (cts->protocol) { 506 case PROTO_ATA: 507 proto = SMART_PROTO_ATA; 508 break; 509 case PROTO_SCSI: 510 proto = SMART_PROTO_SCSI; 511 break; 512 case PROTO_NVME: 513 proto = SMART_PROTO_NVME; 514 break; 515 default: 516 printf("%s: unknown protocol %d\n", 517 __func__, 518 cts->protocol); 519 } 520 } 521 } 522 523 cam_freeccb(ccb); 524 } 525 526 return proto; 527 } 528 529 static int32_t 530 __device_info_ata(struct fbsd_smart *fsmart, struct ccb_getdev *cgd) 531 { 532 smart_info_t *sinfo = NULL; 533 534 if (!fsmart || !cgd) { 535 return -1; 536 } 537 538 sinfo = &fsmart->common.info; 539 540 sinfo->supported = cgd->ident_data.support.command1 & 541 ATA_SUPPORT_SMART; 542 543 dprintf("ATA command1 = %#x\n", cgd->ident_data.support.command1); 544 545 cam_strvis((uint8_t *)sinfo->device, cgd->ident_data.model, 546 sizeof(cgd->ident_data.model), 547 sizeof(sinfo->device)); 548 cam_strvis((uint8_t *)sinfo->rev, cgd->ident_data.revision, 549 sizeof(cgd->ident_data.revision), 550 sizeof(sinfo->rev)); 551 cam_strvis((uint8_t *)sinfo->serial, cgd->ident_data.serial, 552 sizeof(cgd->ident_data.serial), 553 sizeof(sinfo->serial)); 554 555 return 0; 556 } 557 558 static int32_t 559 __device_info_scsi(struct fbsd_smart *fsmart, struct ccb_getdev *cgd) 560 { 561 smart_info_t *sinfo = NULL; 562 union ccb *ccb = NULL; 563 struct scsi_vpd_unit_serial_number *snum = NULL; 564 struct scsi_log_informational_exceptions ie = {0}; 565 566 if (!fsmart || !cgd) { 567 return -1; 568 } 569 570 sinfo = &fsmart->common.info; 571 572 cam_strvis((uint8_t *)sinfo->vendor, (uint8_t *)cgd->inq_data.vendor, 573 sizeof(cgd->inq_data.vendor), 574 sizeof(sinfo->vendor)); 575 cam_strvis((uint8_t *)sinfo->device, (uint8_t *)cgd->inq_data.product, 576 sizeof(cgd->inq_data.product), 577 sizeof(sinfo->device)); 578 cam_strvis((uint8_t *)sinfo->rev, (uint8_t *)cgd->inq_data.revision, 579 sizeof(cgd->inq_data.revision), 580 sizeof(sinfo->rev)); 581 582 ccb = cam_getccb(fsmart->camdev); 583 snum = malloc(sizeof(struct scsi_vpd_unit_serial_number)); 584 if (!ccb || !snum) { 585 warn("Allocation failure ccb=%p snum=%p", ccb, snum); 586 goto __device_info_scsi_out; 587 } 588 589 /* Get the serial number */ 590 CCB_CLEAR_ALL_EXCEPT_HDR(&ccb->csio); 591 592 scsi_inquiry(&ccb->csio, 593 3, // retries 594 NULL, // callback function 595 MSG_SIMPLE_Q_TAG, // tag action 596 (uint8_t *)snum, 597 sizeof(struct scsi_vpd_unit_serial_number), 598 1, // EVPD 599 SVPD_UNIT_SERIAL_NUMBER, // page code 600 SSD_FULL_SIZE, // sense length 601 5000); // timeout 602 603 ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 604 605 if ((cam_send_ccb(fsmart->camdev, ccb) >= 0) && 606 ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) { 607 cam_strvis((uint8_t *)sinfo->serial, snum->serial_num, 608 snum->length, 609 sizeof(sinfo->serial)); 610 sinfo->serial[sizeof(sinfo->serial) - 1] = '\0'; 611 } 612 613 memset(ccb, 0, sizeof(*ccb)); 614 615 scsi_log_sense(&ccb->csio, 616 /* retries */1, 617 /* cbfcnp */NULL, 618 /* tag_action */0, 619 /* page_code */SLS_PAGE_CTRL_CUMULATIVE, 620 /* page */SLS_IE_PAGE, 621 /* save_pages */0, 622 /* ppc */0, 623 /* paramptr */0, 624 /* param_buf */(uint8_t *)&ie, 625 /* param_len */sizeof(ie), 626 /* sense_len */0, 627 /* timeout */5000); 628 629 /* 630 * Note: The existance of the Informational Exceptions (IE) log page 631 * appears to be the litmus test for SMART support in SCSI 632 * devices. Confusingly, smartctl will report SMART health 633 * status as 'OK' if the device doesn't support the IE page. 634 * For now, just report the facts. 635 */ 636 if ((cam_send_ccb(fsmart->camdev, ccb) >= 0) && 637 ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) { 638 if ((ie.hdr.param_len < 4) || ie.ie_asc || ie.ie_ascq) { 639 printf("Log Sense, Informational Exceptions failed " 640 "(length=%u asc=%#x ascq=%#x)\n", 641 ie.hdr.param_len, ie.ie_asc, ie.ie_ascq); 642 } else { 643 sinfo->supported = true; 644 } 645 } 646 647 __device_info_scsi_out: 648 free(snum); 649 if (ccb) 650 cam_freeccb(ccb); 651 652 return 0; 653 } 654 655 static int32_t 656 __device_info_nvme(struct fbsd_smart *fsmart, struct ccb_getdev *cgd) 657 { 658 union ccb *ccb; 659 smart_info_t *sinfo = NULL; 660 struct nvme_controller_data cd; 661 662 if (!fsmart || !cgd) { 663 return -1; 664 } 665 666 sinfo = &fsmart->common.info; 667 668 sinfo->supported = true; 669 670 ccb = cam_getccb(fsmart->camdev); 671 if (ccb != NULL) { 672 struct ccb_dev_advinfo *cdai = &ccb->cdai; 673 674 CCB_CLEAR_ALL_EXCEPT_HDR(cdai); 675 676 cdai->ccb_h.func_code = XPT_DEV_ADVINFO; 677 cdai->ccb_h.flags = CAM_DIR_IN; 678 cdai->flags = CDAI_FLAG_NONE; 679 #ifdef CDAI_TYPE_NVME_CNTRL 680 cdai->buftype = CDAI_TYPE_NVME_CNTRL; 681 #else 682 cdai->buftype = 6; 683 #endif 684 cdai->bufsiz = sizeof(struct nvme_controller_data); 685 cdai->buf = (uint8_t *)&cd; 686 687 if (cam_send_ccb(fsmart->camdev, ccb) >= 0) { 688 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 689 cam_strvis((uint8_t *)sinfo->device, cd.mn, 690 sizeof(cd.mn), 691 sizeof(sinfo->device)); 692 cam_strvis((uint8_t *)sinfo->rev, cd.fr, 693 sizeof(cd.fr), 694 sizeof(sinfo->rev)); 695 cam_strvis((uint8_t *)sinfo->serial, cd.sn, 696 sizeof(cd.sn), 697 sizeof(sinfo->serial)); 698 } 699 } 700 701 cam_freeccb(ccb); 702 } 703 704 return 0; 705 } 706 707 static int32_t 708 __device_info_tunneled_ata(struct fbsd_smart *fsmart) 709 { 710 struct ata_params ident_data; 711 union ccb *ccb = NULL; 712 int32_t rc = -1; 713 714 ccb = cam_getccb(fsmart->camdev); 715 if (ccb == NULL) { 716 goto __device_info_tunneled_ata_out; 717 } 718 719 memset(&ident_data, 0, sizeof(struct ata_params)); 720 721 CCB_CLEAR_ALL_EXCEPT_HDR(ccb); 722 723 scsi_ata_pass_16(&ccb->csio, 724 /*retries*/ 1, 725 /*cbfcnp*/ NULL, 726 /*flags*/ CAM_DIR_IN, 727 /*tag_action*/ MSG_SIMPLE_Q_TAG, 728 /*protocol*/ AP_PROTO_PIO_IN, 729 /*ata_flags*/ AP_FLAG_TLEN_SECT_CNT | 730 AP_FLAG_BYT_BLOK_BLOCKS | 731 AP_FLAG_TDIR_FROM_DEV, 732 /*features*/ 0, 733 /*sector_count*/sizeof(struct ata_params), 734 /*lba*/ 0, 735 /*command*/ ATA_ATA_IDENTIFY, 736 /*control*/ 0, 737 /*data_ptr*/ (uint8_t *)&ident_data, 738 /*dxfer_len*/ sizeof(struct ata_params), 739 /*sense_len*/ SSD_FULL_SIZE, 740 /*timeout*/ 5000 741 ); 742 743 rc = cam_send_ccb(fsmart->camdev, ccb); 744 if (rc != 0) { 745 warnx("%s: scsi_ata_pass_16() failed (programmer error?)", 746 __func__); 747 goto __device_info_tunneled_ata_out; 748 } 749 750 fsmart->common.info.supported = ident_data.support.command1 & 751 ATA_SUPPORT_SMART; 752 753 dprintf("ATA command1 = %#x\n", ident_data.support.command1); 754 755 __device_info_tunneled_ata_out: 756 if (ccb) { 757 cam_freeccb(ccb); 758 } 759 760 return rc; 761 } 762 763 /** 764 * Retrieve the device information and use to populate the info structure 765 */ 766 static int32_t 767 __device_get_info(struct fbsd_smart *fsmart) 768 { 769 union ccb *ccb; 770 int32_t rc = -1; 771 772 if (!fsmart || !fsmart->camdev) { 773 warn("Bad handle %p", fsmart); 774 return -1; 775 } 776 777 ccb = cam_getccb(fsmart->camdev); 778 if (ccb != NULL) { 779 struct ccb_getdev *cgd = &ccb->cgd; 780 781 CCB_CLEAR_ALL_EXCEPT_HDR(cgd); 782 783 /* 784 * GDEV_TYPE doesn't support NVMe. What we do get is: 785 * - device (ata/model, scsi/product) 786 * - revision (ata, scsi) 787 * - serial (ata) 788 * - vendor (scsi) 789 * - supported (ata) 790 * 791 * Serial # for all proto via ccb_dev_advinfo (buftype CDAI_TYPE_SERIAL_NUM) 792 */ 793 ccb->ccb_h.func_code = XPT_GDEV_TYPE; 794 795 if (cam_send_ccb(fsmart->camdev, ccb) >= 0) { 796 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) { 797 switch (cgd->protocol) { 798 case PROTO_ATA: 799 rc = __device_info_ata(fsmart, cgd); 800 break; 801 case PROTO_SCSI: 802 rc = __device_info_scsi(fsmart, cgd); 803 if (!rc && fsmart->common.protocol == SMART_PROTO_ATA) { 804 rc = __device_info_tunneled_ata(fsmart); 805 } 806 break; 807 case PROTO_NVME: 808 rc = __device_info_nvme(fsmart, cgd); 809 break; 810 default: 811 printf("%s: unsupported protocol %d\n", 812 __func__, cgd->protocol); 813 } 814 } 815 } 816 817 cam_freeccb(ccb); 818 } 819 820 return rc; 821 } 822