| | 1379 | /// 3SNIC RAID support |
| | 1380 | |
| | 1381 | class linux_sssraid_device |
| | 1382 | : public /* implements */ scsi_device, |
| | 1383 | public /* extends */ linux_smart_device |
| | 1384 | { |
| | 1385 | public: |
| | 1386 | linux_sssraid_device(smart_interface *intf, const char *name, |
| | 1387 | unsigned int eid, unsigned int sid); |
| | 1388 | |
| | 1389 | virtual bool scsi_pass_through(scsi_cmnd_io *iop) override; |
| | 1390 | |
| | 1391 | private: |
| | 1392 | unsigned int m_eid; |
| | 1393 | unsigned int m_sid; |
| | 1394 | |
| | 1395 | bool scsi_cmd(int cdbLen, void *cdb, int dataLen, void *data, int direction); |
| | 1396 | }; |
| | 1397 | |
| | 1398 | linux_sssraid_device::linux_sssraid_device(smart_interface *intf, |
| | 1399 | const char *dev_name, unsigned int eid, unsigned int sid) |
| | 1400 | : smart_device(intf, dev_name, "sssraid", "sssraid"), |
| | 1401 | linux_smart_device(O_RDWR | O_NONBLOCK), |
| | 1402 | m_eid(eid), m_sid(sid) |
| | 1403 | { |
| | 1404 | set_info().info_name = strprintf("%s [sssraid_disk_%02d_%02d]", dev_name, eid, sid); |
| | 1405 | set_info().dev_type = strprintf("sssraid,%d,%d", eid, sid); |
| | 1406 | } |
| | 1407 | |
| | 1408 | bool linux_sssraid_device::scsi_pass_through(scsi_cmnd_io *iop) |
| | 1409 | { |
| | 1410 | int report = scsi_debugmode; |
| | 1411 | if (report > 0) { |
| | 1412 | int k, j; |
| | 1413 | const unsigned char * ucp = iop->cmnd; |
| | 1414 | const char * np; |
| | 1415 | char buff[256]; |
| | 1416 | const int sz = (int)sizeof(buff); |
| | 1417 | |
| | 1418 | np = scsi_get_opcode_name(ucp[0]); |
| | 1419 | j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); |
| | 1420 | for (k = 0; k < (int)iop->cmnd_len; ++k) |
| | 1421 | j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); |
| | 1422 | if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { |
| | 1423 | int trunc = (iop->dxfer_len > 256) ? 1 : 0; |
| | 1424 | |
| | 1425 | snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " |
| | 1426 | "data, len=%d%s:\n", (int)iop->dxfer_len, |
| | 1427 | (trunc ? " [only first 256 bytes shown]" : "")); |
| | 1428 | dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); |
| | 1429 | } |
| | 1430 | else |
| | 1431 | snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); |
| | 1432 | pout("%s", buff); |
| | 1433 | } |
| | 1434 | |
| | 1435 | bool r = scsi_cmd(iop->cmnd_len, iop->cmnd, |
| | 1436 | iop->dxfer_len, iop->dxferp, iop->dxfer_dir); |
| | 1437 | return r; |
| | 1438 | } |
| | 1439 | |
| | 1440 | /* Issue passthrough scsi commands to sssraid controllers */ |
| | 1441 | bool linux_sssraid_device::scsi_cmd(int cdbLen, void *cdb, |
| | 1442 | int dataLen, void *data, int dxfer_dir) |
| | 1443 | { |
| | 1444 | struct sg_io_v4 io_hdr_v4; |
| | 1445 | struct cmd_scsi_passthrough scsi_param; |
| | 1446 | unsigned char sense_buff[96] = { 0 }; |
| | 1447 | struct bsg_ioctl_cmd bsg_param; |
| | 1448 | memset(&io_hdr_v4, 0, sizeof(io_hdr_v4)); |
| | 1449 | memset(&scsi_param, 0, sizeof(scsi_param)); |
| | 1450 | memset(&bsg_param, 0, sizeof(bsg_param)); |
| | 1451 | scsi_param.sense_buffer = sense_buff; |
| | 1452 | scsi_param.sense_buffer_len = 96; |
| | 1453 | scsi_param.cdb_len = cdbLen; |
| | 1454 | memcpy(scsi_param.cdb, cdb, cdbLen); |
| | 1455 | scsi_param.loc.enc_id = m_eid; |
| | 1456 | scsi_param.loc.slot_id = m_sid; |
| | 1457 | |
| | 1458 | io_hdr_v4.guard = 'Q'; |
| | 1459 | io_hdr_v4.protocol = BSG_PROTOCOL_SCSI; |
| | 1460 | io_hdr_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; |
| | 1461 | io_hdr_v4.response = (uintptr_t)sense_buff; |
| | 1462 | io_hdr_v4.max_response_len = ADM_SCSI_CDB_SENSE_MAX_LEN; |
| | 1463 | io_hdr_v4.request_len = sizeof(struct bsg_ioctl_cmd); |
| | 1464 | io_hdr_v4.request = (uintptr_t)(&bsg_param); |
| | 1465 | io_hdr_v4.timeout = BSG_APPEND_TIMEOUT_MS + DEFAULT_CONMMAND_TIMEOUT_MS; |
| | 1466 | |
| | 1467 | switch (dxfer_dir) { |
| | 1468 | case DXFER_NONE: |
| | 1469 | case DXFER_FROM_DEVICE: |
| | 1470 | io_hdr_v4.din_xferp = (uintptr_t)data; |
| | 1471 | io_hdr_v4.din_xfer_len = dataLen; |
| | 1472 | bsg_param.ioctl_pthru.opcode = ADM_RAID_READ; |
| | 1473 | break; |
| | 1474 | case DXFER_TO_DEVICE: |
| | 1475 | io_hdr_v4.dout_xferp = (uintptr_t)data; |
| | 1476 | io_hdr_v4.dout_xfer_len = dataLen; |
| | 1477 | bsg_param.ioctl_pthru.opcode = ADM_RAID_WRITE; |
| | 1478 | break; |
| | 1479 | default: |
| | 1480 | pout("scsi_cmd: bad dxfer_dir\n"); |
| | 1481 | return set_err(EINVAL, "scsi_cmd: bad dxfer_dir\n"); |
| | 1482 | } |
| | 1483 | |
| | 1484 | bsg_param.msgcode = ADM_BSG_MSGCODE_SCSI_PTHRU; |
| | 1485 | bsg_param.ioctl_pthru.timeout_ms = DEFAULT_CONMMAND_TIMEOUT_MS; |
| | 1486 | bsg_param.ioctl_pthru.info_1.subopcode = ADM_CMD_SCSI_PASSTHROUGH; |
| | 1487 | bsg_param.ioctl_pthru.addr = (uintptr_t)data; |
| | 1488 | bsg_param.ioctl_pthru.data_len = dataLen; |
| | 1489 | |
| | 1490 | bsg_param.ioctl_pthru.info_0.cdb_len = scsi_param.cdb_len; |
| | 1491 | bsg_param.ioctl_pthru.sense_addr = (uintptr_t)scsi_param.sense_buffer; |
| | 1492 | bsg_param.ioctl_pthru.info_0.res_sense_len = scsi_param.sense_buffer_len; |
| | 1493 | io_hdr_v4.response = (uintptr_t)scsi_param.sense_buffer; |
| | 1494 | io_hdr_v4.response_len = scsi_param.sense_buffer_len; |
| | 1495 | bsg_param.ioctl_pthru.info_3.eid = scsi_param.loc.enc_id; |
| | 1496 | bsg_param.ioctl_pthru.info_3.sid = scsi_param.loc.slot_id; |
| | 1497 | bsg_param.ioctl_pthru.info_4.did = scsi_param.loc.did; |
| | 1498 | bsg_param.ioctl_pthru.info_4.did_flag = scsi_param.loc.flag; |
| | 1499 | |
| | 1500 | memcpy(&bsg_param.ioctl_pthru.cdw16, scsi_param.cdb, scsi_param.cdb_len); |
| | 1501 | |
| | 1502 | int r = ioctl(get_fd(), SG_IO, &io_hdr_v4); |
| | 1503 | if (r < 0) { |
| | 1504 | return (r); |
| | 1505 | } |
| | 1506 | |
| | 1507 | return true; |
| | 1508 | } |
| | 1509 | |
| | 1510 | ///////////////////////////////////////////////////////////////////////////// |
| | 3031 | // getting devices from 3SNIC Raid, if available |
| | 3032 | bool linux_smart_interface::get_dev_sssraid(smart_device_list & devlist) |
| | 3033 | { |
| | 3034 | /* Scanning of disks on sssraid device */ |
| | 3035 | char line[128]; |
| | 3036 | FILE * fp = NULL; |
| | 3037 | |
| | 3038 | // getting bus numbers with 3snic sas devices |
| | 3039 | // we are using sysfs to get list of all scsi hosts |
| | 3040 | DIR * dp = opendir ("/sys/class/scsi_host/"); |
| | 3041 | if (dp != NULL) |
| | 3042 | { |
| | 3043 | struct dirent *ep; |
| | 3044 | while ((ep = readdir (dp)) != NULL) { |
| | 3045 | unsigned int host_no = 0; |
| | 3046 | if (!sscanf(ep->d_name, "host%u", &host_no)) |
| | 3047 | continue; |
| | 3048 | /* proc_name should be sssraid */ |
| | 3049 | char sysfsdir[256]; |
| | 3050 | snprintf(sysfsdir, sizeof(sysfsdir) - 1, |
| | 3051 | "/sys/class/scsi_host/host%u/proc_name", host_no); |
| | 3052 | if((fp = fopen(sysfsdir, "r")) == NULL) |
| | 3053 | continue; |
| | 3054 | if(fgets(line, sizeof(line), fp) != NULL && !strncmp(line,"sssraid",7)) { |
| | 3055 | sssraid_pd_add_list(host_no, devlist); |
| | 3056 | } |
| | 3057 | fclose(fp); |
| | 3058 | } |
| | 3059 | (void) closedir (dp); |
| | 3060 | } else { /* sysfs not mounted ? */ |
| | 3061 | for(unsigned i = 0; i <=16; i++) // trying to add devices on first 16 buses |
| | 3062 | sssraid_pd_add_list(i, devlist); |
| | 3063 | } |
| | 3064 | return true; |
| | 3065 | } |
| | 3066 | |
| | 3251 | int |
| | 3252 | linux_smart_interface::sssraid_pdlist_cmd(int bus_no, uint16_t start_idx_param, void *buf, size_t bufsize, uint8_t *statusp) |
| | 3253 | { |
| | 3254 | struct sg_io_v4 io_hdr_v4; |
| | 3255 | unsigned char sense_buff[ADM_SCSI_CDB_SENSE_MAX_LEN] = { 0 }; |
| | 3256 | struct bsg_ioctl_cmd bsg_param; |
| | 3257 | u8 cmd_param[24] = { 0 }; |
| | 3258 | |
| | 3259 | memset(&io_hdr_v4, 0, sizeof(io_hdr_v4)); |
| | 3260 | memset(&bsg_param, 0, sizeof(bsg_param)); |
| | 3261 | io_hdr_v4.guard = 'Q'; |
| | 3262 | io_hdr_v4.protocol = BSG_PROTOCOL_SCSI; |
| | 3263 | io_hdr_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT; |
| | 3264 | io_hdr_v4.response = (uintptr_t)sense_buff; |
| | 3265 | io_hdr_v4.max_response_len = ADM_SCSI_CDB_SENSE_MAX_LEN; |
| | 3266 | io_hdr_v4.request_len = sizeof(struct bsg_ioctl_cmd); |
| | 3267 | io_hdr_v4.request = (uintptr_t)(&bsg_param); |
| | 3268 | io_hdr_v4.timeout = BSG_APPEND_TIMEOUT_MS + DEFAULT_CONMMAND_TIMEOUT_MS; |
| | 3269 | |
| | 3270 | if (bufsize >0) { |
| | 3271 | io_hdr_v4.din_xferp = (uintptr_t)buf; |
| | 3272 | io_hdr_v4.din_xfer_len = bufsize; |
| | 3273 | } |
| | 3274 | |
| | 3275 | bsg_param.msgcode = 0; |
| | 3276 | bsg_param.ioctl_r64.opcode = ADM_RAID_READ; |
| | 3277 | bsg_param.ioctl_r64.timeout_ms = DEFAULT_CONMMAND_TIMEOUT_MS; |
| | 3278 | bsg_param.ioctl_r64.info_0.subopcode = ADM_CMD_SHOW_PDLIST; |
| | 3279 | bsg_param.ioctl_r64.addr = (uintptr_t)buf; |
| | 3280 | bsg_param.ioctl_r64.info_1.data_len = bufsize; |
| | 3281 | bsg_param.ioctl_r64.data_len = bufsize; |
| | 3282 | bsg_param.ioctl_r64.info_1.param_len = sizeof(struct cmd_pdlist_idx); |
| | 3283 | memset(&cmd_param, 0, 24); |
| | 3284 | struct cmd_pdlist_idx *p_cmd_param = (struct cmd_pdlist_idx *)(&cmd_param); |
| | 3285 | p_cmd_param->start_idx = start_idx_param; |
| | 3286 | p_cmd_param->count = CMD_PDLIST_ONCE_NUM; |
| | 3287 | memcpy((u32*)&bsg_param.ioctl_r64.cdw10, cmd_param, sizeof(struct cmd_pdlist_idx)); |
| | 3288 | |
| | 3289 | int fd; |
| | 3290 | char line[128]; |
| | 3291 | snprintf(line, sizeof(line) - 1, "/dev/bsg/sssraid%d", bus_no); |
| | 3292 | if ((fd = ::open(line, O_RDONLY)) < 0) { |
| | 3293 | pout("open %s error %d\n", line, fd); |
| | 3294 | return (errno); |
| | 3295 | } |
| | 3296 | |
| | 3297 | int r = ioctl(fd, SG_IO, &io_hdr_v4); |
| | 3298 | ::close(fd); |
| | 3299 | if (r < 0) { |
| | 3300 | return (r); |
| | 3301 | } |
| | 3302 | |
| | 3303 | if (statusp != NULL) { |
| | 3304 | *statusp = (io_hdr_v4.transport_status << 0x8) | io_hdr_v4.device_status; |
| | 3305 | pout("statusp = 0x%x\n", *statusp); |
| | 3306 | if (*statusp) { |
| | 3307 | pout("controller returns an error - 0x%x", *statusp); |
| | 3308 | return (-1); |
| | 3309 | } |
| | 3310 | } |
| | 3311 | return (0); |
| | 3312 | } |
| | 3313 | |
| | 3314 | int |
| | 3315 | linux_smart_interface::sssraid_pd_add_list(int bus_no, smart_device_list & devlist) |
| | 3316 | { |
| | 3317 | unsigned disk_num = 0; |
| | 3318 | struct cmd_pdlist_entry pdlist[CMD_PDS_MAX_NUM]; |
| | 3319 | while (disk_num < CMD_PDS_MAX_NUM) { |
| | 3320 | struct cmd_show_pdlist list; |
| | 3321 | memset(&list, 0, sizeof(list)); |
| | 3322 | if (sssraid_pdlist_cmd(bus_no, disk_num, &list, sizeof(struct cmd_show_pdlist), NULL) < 0) |
| | 3323 | { |
| | 3324 | return (-1); |
| | 3325 | } |
| | 3326 | if (list.num == 0) |
| | 3327 | break; |
| | 3328 | memcpy(&pdlist[disk_num], list.disks, list.num * sizeof(struct cmd_pdlist_entry)); |
| | 3329 | disk_num += list.num; |
| | 3330 | if (list.num < CMD_PDLIST_ONCE_NUM) |
| | 3331 | break; |
| | 3332 | } |
| | 3333 | |
| | 3334 | // adding all SCSI devices |
| | 3335 | for (unsigned i = 0; i < disk_num; i++) { |
| | 3336 | if(!(pdlist[i].interface == ADM_DEVICE_TYPE_SATA || pdlist[i].interface == ADM_DEVICE_TYPE_SAS |
| | 3337 | || pdlist[i].interface == ADM_DEVICE_TYPE_NVME)) |
| | 3338 | continue; /* non disk device found */ |
| | 3339 | char line[128]; |
| | 3340 | snprintf(line, sizeof(line) - 1, "/dev/bsg/sssraid%d", bus_no); |
| | 3341 | smart_device * dev = new linux_sssraid_device(this, line, (unsigned int)pdlist[i].enc_id, (unsigned int)pdlist[i].slot_id); |
| | 3342 | devlist.push_back(dev); |
| | 3343 | } |
| | 3344 | return (0); |
| | 3345 | } |
| | 3346 | |