| 1503 | ///////////////////////////////////////////////////////////////////////////// |
| 1504 | /// 3SNIC RAID support |
| 1505 | |
| 1506 | class linux_sssraid_device |
| 1507 | : public /* implements */ scsi_device, |
| 1508 | public /* extends */ linux_smart_device |
| 1509 | { |
| 1510 | public: |
| 1511 | linux_sssraid_device(smart_interface *intf, const char *name, |
| 1512 | unsigned int eid, unsigned int sid); |
| 1513 | |
| 1514 | virtual bool scsi_pass_through(scsi_cmnd_io *iop) override; |
| 1515 | |
| 1516 | private: |
| 1517 | unsigned int m_eid; |
| 1518 | unsigned int m_sid; |
| 1519 | |
| 1520 | bool scsi_cmd(int cdbLen, void *cdb, int dataLen, void *data, int direction); |
| 1521 | }; |
| 1522 | |
| 1523 | linux_sssraid_device::linux_sssraid_device(smart_interface *intf, |
| 1524 | const char *dev_name, unsigned int eid, unsigned int sid) |
| 1525 | : smart_device(intf, dev_name, "sssraid", "sssraid"), |
| 1526 | linux_smart_device(O_RDWR | O_NONBLOCK), |
| 1527 | m_eid(eid), m_sid(sid) |
| 1528 | { |
| 1529 | set_info().info_name = strprintf("%s [sssraid_disk_%02d_%02d]", dev_name, eid, sid); |
| 1530 | set_info().dev_type = strprintf("sssraid,%d,%d", eid, sid); |
| 1531 | } |
| 1532 | |
| 1533 | bool linux_sssraid_device::scsi_pass_through(scsi_cmnd_io *iop) |
| 1534 | { |
| 1535 | int report = scsi_debugmode; |
| 1536 | if (report > 0) { |
| 1537 | int k, j; |
| 1538 | const unsigned char * ucp = iop->cmnd; |
| 1539 | const char * np; |
| 1540 | char buff[256]; |
| 1541 | const int sz = (int)sizeof(buff); |
| 1542 | |
| 1543 | np = scsi_get_opcode_name(ucp[0]); |
| 1544 | j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); |
| 1545 | for (k = 0; k < (int)iop->cmnd_len; ++k) |
| 1546 | j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); |
| 1547 | if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { |
| 1548 | int trunc = (iop->dxfer_len > 256) ? 1 : 0; |
| 1549 | |
| 1550 | snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " |
| 1551 | "data, len=%d%s:\n", (int)iop->dxfer_len, |
| 1552 | (trunc ? " [only first 256 bytes shown]" : "")); |
| 1553 | dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); |
| 1554 | } |
| 1555 | else |
| 1556 | snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); |
| 1557 | pout("%s", buff); |
| 1558 | } |
| 1559 | |
| 1560 | bool r = scsi_cmd(iop->cmnd_len, iop->cmnd, |
| 1561 | iop->dxfer_len, iop->dxferp, iop->dxfer_dir); |
| 1562 | return r; |
| 1563 | } |
| 1564 | |
| 1565 | /* Issue passthrough scsi commands to sssraid controllers */ |
| 1566 | bool linux_sssraid_device::scsi_cmd(int cdbLen, void *cdb, |
| 1567 | int dataLen, void *data, int dxfer_dir) |
| 1568 | { |
| 1569 | struct sg_io_v4 io_hdr_v4; |
| 1570 | struct cmd_scsi_passthrough scsi_param; |
| 1571 | unsigned char sense_buff[96] = { 0 }; |
| 1572 | struct bsg_ioctl_cmd bsg_param; |
| 1573 | memset(&io_hdr_v4, 0, sizeof(io_hdr_v4)); |
| 1574 | memset(&scsi_param, 0, sizeof(scsi_param)); |
| 1575 | memset(&bsg_param, 0, sizeof(bsg_param)); |
| 1576 | scsi_param.sense_buffer = sense_buff; |
| 1577 | scsi_param.sense_buffer_len = 96; |
| 1578 | scsi_param.cdb_len = cdbLen; |
| 1579 | memcpy(scsi_param.cdb, cdb, cdbLen); |
| 1580 | scsi_param.loc.enc_id = m_eid; |
| 1581 | scsi_param.loc.slot_id = m_sid; |
| 1582 | |
| 1583 | io_hdr_v4.guard = 'Q'; |
| 1584 | io_hdr_v4.protocol = BSG_PROTOCOL_SCSI; |
| 1585 | io_hdr_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; |
| 1586 | io_hdr_v4.response = (uintptr_t)sense_buff; |
| 1587 | io_hdr_v4.max_response_len = ADM_SCSI_CDB_SENSE_MAX_LEN; |
| 1588 | io_hdr_v4.request_len = sizeof(struct bsg_ioctl_cmd); |
| 1589 | io_hdr_v4.request = (uintptr_t)(&bsg_param); |
| 1590 | io_hdr_v4.timeout = BSG_APPEND_TIMEOUT_MS + DEFAULT_CONMMAND_TIMEOUT_MS; |
| 1591 | |
| 1592 | switch (dxfer_dir) { |
| 1593 | case DXFER_NONE: |
| 1594 | case DXFER_FROM_DEVICE: |
| 1595 | io_hdr_v4.din_xferp = (uintptr_t)data; |
| 1596 | io_hdr_v4.din_xfer_len = dataLen; |
| 1597 | bsg_param.ioctl_pthru.opcode = ADM_RAID_READ; |
| 1598 | break; |
| 1599 | case DXFER_TO_DEVICE: |
| 1600 | io_hdr_v4.dout_xferp = (uintptr_t)data; |
| 1601 | io_hdr_v4.dout_xfer_len = dataLen; |
| 1602 | bsg_param.ioctl_pthru.opcode = ADM_RAID_WRITE; |
| 1603 | break; |
| 1604 | default: |
| 1605 | pout("scsi_cmd: bad dxfer_dir\n"); |
| 1606 | return set_err(EINVAL, "scsi_cmd: bad dxfer_dir\n"); |
| 1607 | } |
| 1608 | |
| 1609 | bsg_param.msgcode = ADM_BSG_MSGCODE_SCSI_PTHRU; |
| 1610 | bsg_param.ioctl_pthru.timeout_ms = DEFAULT_CONMMAND_TIMEOUT_MS; |
| 1611 | bsg_param.ioctl_pthru.info_1.subopcode = ADM_CMD_SCSI_PASSTHROUGH; |
| 1612 | bsg_param.ioctl_pthru.addr = (uintptr_t)data; |
| 1613 | bsg_param.ioctl_pthru.data_len = dataLen; |
| 1614 | |
| 1615 | bsg_param.ioctl_pthru.info_0.cdb_len = scsi_param.cdb_len; |
| 1616 | bsg_param.ioctl_pthru.sense_addr = (uintptr_t)scsi_param.sense_buffer; |
| 1617 | bsg_param.ioctl_pthru.info_0.res_sense_len = scsi_param.sense_buffer_len; |
| 1618 | io_hdr_v4.response = (uintptr_t)scsi_param.sense_buffer; |
| 1619 | io_hdr_v4.response_len = scsi_param.sense_buffer_len; |
| 1620 | bsg_param.ioctl_pthru.info_3.eid = scsi_param.loc.enc_id; |
| 1621 | bsg_param.ioctl_pthru.info_3.sid = scsi_param.loc.slot_id; |
| 1622 | bsg_param.ioctl_pthru.info_4.did = scsi_param.loc.did; |
| 1623 | bsg_param.ioctl_pthru.info_4.did_flag = scsi_param.loc.flag; |
| 1624 | |
| 1625 | memcpy(&bsg_param.ioctl_pthru.cdw16, scsi_param.cdb, scsi_param.cdb_len); |
| 1626 | |
| 1627 | int r = ioctl(get_fd(), SG_IO, &io_hdr_v4); |
| 1628 | if (r < 0) { |
| 1629 | return (r); |
| 1630 | } |
| 1631 | |
| 1632 | return true; |
| 1633 | } |
| 1634 | |
| 3152 | // getting devices from 3SNIC Raid, if available |
| 3153 | bool linux_smart_interface::get_dev_sssraid(smart_device_list & devlist) |
| 3154 | { |
| 3155 | /* Scanning of disks on sssraid device */ |
| 3156 | char line[128]; |
| 3157 | FILE * fp = NULL; |
| 3158 | |
| 3159 | // getting bus numbers with 3snic sas devices |
| 3160 | // we are using sysfs to get list of all scsi hosts |
| 3161 | DIR * dp = opendir ("/sys/class/scsi_host/"); |
| 3162 | if (dp != NULL) |
| 3163 | { |
| 3164 | struct dirent *ep; |
| 3165 | while ((ep = readdir (dp)) != NULL) { |
| 3166 | unsigned int host_no = 0; |
| 3167 | if (!sscanf(ep->d_name, "host%u", &host_no)) |
| 3168 | continue; |
| 3169 | /* proc_name should be sssraid */ |
| 3170 | char sysfsdir[256]; |
| 3171 | snprintf(sysfsdir, sizeof(sysfsdir) - 1, |
| 3172 | "/sys/class/scsi_host/host%u/proc_name", host_no); |
| 3173 | if((fp = fopen(sysfsdir, "r")) == NULL) |
| 3174 | continue; |
| 3175 | if(fgets(line, sizeof(line), fp) != NULL && !strncmp(line,"sssraid",7)) { |
| 3176 | sssraid_pd_add_list(host_no, devlist); |
| 3177 | } |
| 3178 | fclose(fp); |
| 3179 | } |
| 3180 | (void) closedir (dp); |
| 3181 | } else { /* sysfs not mounted ? */ |
| 3182 | for(unsigned i = 0; i <=16; i++) // trying to add devices on first 16 buses |
| 3183 | sssraid_pd_add_list(i, devlist); |
| 3184 | } |
| 3185 | return true; |
| 3186 | } |
| 3187 | |
| 3372 | int |
| 3373 | linux_smart_interface::sssraid_pdlist_cmd(int bus_no, uint16_t start_idx_param, void *buf, size_t bufsize, uint8_t *statusp) |
| 3374 | { |
| 3375 | struct sg_io_v4 io_hdr_v4; |
| 3376 | unsigned char sense_buff[ADM_SCSI_CDB_SENSE_MAX_LEN] = { 0 }; |
| 3377 | struct bsg_ioctl_cmd bsg_param; |
| 3378 | u8 cmd_param[24] = { 0 }; |
| 3379 | |
| 3380 | memset(&io_hdr_v4, 0, sizeof(io_hdr_v4)); |
| 3381 | memset(&bsg_param, 0, sizeof(bsg_param)); |
| 3382 | io_hdr_v4.guard = 'Q'; |
| 3383 | io_hdr_v4.protocol = BSG_PROTOCOL_SCSI; |
| 3384 | io_hdr_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; |
| 3385 | io_hdr_v4.response = (uintptr_t)sense_buff; |
| 3386 | io_hdr_v4.max_response_len = ADM_SCSI_CDB_SENSE_MAX_LEN; |
| 3387 | io_hdr_v4.request_len = sizeof(struct bsg_ioctl_cmd); |
| 3388 | io_hdr_v4.request = (uintptr_t)(&bsg_param); |
| 3389 | io_hdr_v4.timeout = BSG_APPEND_TIMEOUT_MS + DEFAULT_CONMMAND_TIMEOUT_MS; |
| 3390 | |
| 3391 | if (bufsize >0) { |
| 3392 | io_hdr_v4.din_xferp = (uintptr_t)buf; |
| 3393 | io_hdr_v4.din_xfer_len = bufsize; |
| 3394 | } |
| 3395 | |
| 3396 | bsg_param.msgcode = 0; |
| 3397 | bsg_param.ioctl_r64.opcode = ADM_RAID_READ; |
| 3398 | bsg_param.ioctl_r64.timeout_ms = DEFAULT_CONMMAND_TIMEOUT_MS; |
| 3399 | bsg_param.ioctl_r64.info_0.subopcode = ADM_CMD_SHOW_PDLIST; |
| 3400 | bsg_param.ioctl_r64.addr = (uintptr_t)buf; |
| 3401 | bsg_param.ioctl_r64.info_1.data_len = bufsize; |
| 3402 | bsg_param.ioctl_r64.data_len = bufsize; |
| 3403 | bsg_param.ioctl_r64.info_1.param_len = sizeof(struct cmd_pdlist_idx); |
| 3404 | memset(&cmd_param, 0, 24); |
| 3405 | struct cmd_pdlist_idx *p_cmd_param = (struct cmd_pdlist_idx *)(&cmd_param); |
| 3406 | p_cmd_param->start_idx = start_idx_param; |
| 3407 | p_cmd_param->count = CMD_PDLIST_ONCE_NUM; |
| 3408 | memcpy((u32*)&bsg_param.ioctl_r64.cdw10, cmd_param, sizeof(struct cmd_pdlist_idx)); |
| 3409 | |
| 3410 | int fd; |
| 3411 | char line[128]; |
| 3412 | snprintf(line, sizeof(line) - 1, "/dev/bsg/sssraid%d", bus_no); |
| 3413 | if ((fd = ::open(line, O_RDONLY)) < 0) { |
| 3414 | pout("open %s error %d\n", line, fd); |
| 3415 | return (errno); |
| 3416 | } |
| 3417 | |
| 3418 | int r = ioctl(fd, SG_IO, &io_hdr_v4); |
| 3419 | ::close(fd); |
| 3420 | if (r < 0) { |
| 3421 | return (r); |
| 3422 | } |
| 3423 | |
| 3424 | if (statusp != NULL) { |
| 3425 | *statusp = (io_hdr_v4.transport_status << 0x8) | io_hdr_v4.device_status; |
| 3426 | pout("statusp = 0x%x\n", *statusp); |
| 3427 | if (*statusp) { |
| 3428 | pout("controller returns an error - 0x%x", *statusp); |
| 3429 | return (-1); |
| 3430 | } |
| 3431 | } |
| 3432 | return (0); |
| 3433 | } |
| 3434 | |
| 3435 | int |
| 3436 | linux_smart_interface::sssraid_pd_add_list(int bus_no, smart_device_list & devlist) |
| 3437 | { |
| 3438 | unsigned disk_num = 0; |
| 3439 | struct cmd_pdlist_entry pdlist[CMD_PDS_MAX_NUM]; |
| 3440 | while (disk_num < CMD_PDS_MAX_NUM) { |
| 3441 | struct cmd_show_pdlist list; |
| 3442 | memset(&list, 0, sizeof(list)); |
| 3443 | if (sssraid_pdlist_cmd(bus_no, disk_num, &list, sizeof(struct cmd_show_pdlist), NULL) < 0) |
| 3444 | { |
| 3445 | return (-1); |
| 3446 | } |
| 3447 | if (list.num == 0) |
| 3448 | break; |
| 3449 | memcpy(&pdlist[disk_num], list.disks, list.num * sizeof(struct cmd_pdlist_entry)); |
| 3450 | disk_num += list.num; |
| 3451 | if (list.num < CMD_PDLIST_ONCE_NUM) |
| 3452 | break; |
| 3453 | } |
| 3454 | |
| 3455 | // adding all SCSI devices |
| 3456 | for (unsigned i = 0; i < disk_num; i++) { |
| 3457 | if(!(pdlist[i].interface == ADM_DEVICE_TYPE_SATA || pdlist[i].interface == ADM_DEVICE_TYPE_SAS |
| 3458 | || pdlist[i].interface == ADM_DEVICE_TYPE_NVME)) |
| 3459 | continue; /* non disk device found */ |
| 3460 | char line[128]; |
| 3461 | snprintf(line, sizeof(line) - 1, "/dev/bsg/sssraid%d", bus_no); |
| 3462 | smart_device * dev = new linux_sssraid_device(this, line, (unsigned int)pdlist[i].enc_id, (unsigned int)pdlist[i].slot_id); |
| 3463 | devlist.push_back(dev); |
| 3464 | } |
| 3465 | return (0); |
| 3466 | } |
| 3467 | |