Ticket #1853: smart_7.4_ps3stor2smart.patch
File smart_7.4_ps3stor2smart.patch, 52.5 KB (added by , 4 months ago) |
---|
-
AUTHORS
46 46 Hank Wu <hank@areca.com.tw> 47 47 Shengfeng Zhou <linux@highpoint-tech.com> 48 48 Richard Zybert <richard.zybert@zybert.co.uk> 49 Hong Xu <babyxong@88.com> 49 50 50 51 The first smartmontools code was derived from the smartsuite package, 51 52 written by Michael Cornwell and Andre Hedrick. -
ChangeLog
1 1 $Id$ 2 2 3 2024-07-17 Hong Xu <babyxong@88.com> 4 Add PS3StorRAID (PS3Stor RAID Controller) support on Linux. 5 3 6 2024-05-08 Christian Franke <franke@computer.org> 4 7 5 8 smartctl.cpp, smartd.cpp: Fix segfault on missing option argument (#1830). -
configure.ac
627 627 os_nvme_devicescan_changed=no 628 628 case "${host}" in 629 629 *-*-linux*) 630 os_deps='os_linux.o cciss.o dev_areca.o '630 os_deps='os_linux.o cciss.o dev_areca.o ps3stor.o' 631 631 os_dnsdomainname="'dnsdomainname' 'hostname -d'" 632 632 os_nisdomainname="'nisdomainname' 'hostname -y' 'domainname'" 633 633 os_man_filter=Linux -
Makefile.am
132 132 dev_legacy.cpp \ 133 133 linux_nvme_ioctl.h \ 134 134 megaraid.h \ 135 sssraid.h 135 sssraid.h \ 136 ps3stor.cpp \ 137 ps3stor.h 136 138 137 139 if OS_WIN32_MINGW 138 140 … … 206 208 freebsd_nvme_ioctl.h \ 207 209 netbsd_nvme_ioctl.h \ 208 210 megaraid.h \ 209 sssraid.h 211 sssraid.h \ 212 ps3stor.cpp \ 213 ps3stor.h 210 214 211 215 if OS_POSIX 212 216 -
os_linux.cpp
29 29 * Kernel compatibility By: Andre Hedrick <andre@suse.com> 30 30 * Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> 31 31 * 32 * Original PS3stor code: 33 * Copyright (C) 2021-2024 Hong Xu <babyxong@88.com> 34 * 32 35 * Other ars of this file are derived from code that was 33 36 * 34 37 * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> … … 84 87 // "include/uapi/linux/nvme_ioctl.h" from Linux kernel sources 85 88 #include "linux_nvme_ioctl.h" // nvme_passthru_cmd, NVME_IOCTL_ADMIN_CMD 86 89 90 #include "ps3stor.h" 91 #include <map> 87 92 #ifndef ENOTSUP 88 93 #define ENOTSUP ENOSYS 89 94 #endif … … 1523 1528 } 1524 1529 1525 1530 ///////////////////////////////////////////////////////////////////////////// 1531 /// PS3 STOR support 1532 class linux_smart_interface; 1533 class linux_ps3stor_channel; 1534 class linux_ps3stor_device 1535 : public /* implements */ scsi_device, 1536 public /* extends */ linux_smart_device 1537 { 1538 public: 1539 1540 linux_ps3stor_device(smart_interface *intf, const char *name, 1541 unsigned int tgt); 1542 1543 virtual ~linux_ps3stor_device(); 1544 1545 virtual smart_device * autodetect_open() override; 1546 1547 virtual bool is_open() const override; 1548 virtual bool open() override; 1549 virtual bool close() override; 1550 1551 virtual bool scsi_pass_through(scsi_cmnd_io *iop) override; 1552 1553 private: 1554 unsigned int m_did; 1555 bool m_open_flag; 1556 encl_id_t m_eid; 1557 slot_id_t m_sid; 1558 unsigned int m_host; 1559 bool scsi_cmd(scsi_cmnd_io *iop); 1560 bool get_pd_position(encl_id_t &eid, slot_id_t &sid); 1561 }; 1562 1563 linux_ps3stor_device::linux_ps3stor_device(smart_interface *intf, 1564 const char *dev_name, unsigned int tgt) 1565 : smart_device(intf, dev_name, "ps3stor", "ps3stor"), 1566 linux_smart_device(O_RDWR | O_NONBLOCK), 1567 m_did(tgt), 1568 m_open_flag(false), 1569 m_eid(PS3STOR_INVALID_ENCL_ID), 1570 m_sid(PS3STOR_INVALID_SLOT_ID), 1571 m_host(0) 1572 { 1573 set_info().info_name = strprintf("%s [ps3stor_disk_%02d]", dev_name, m_did); 1574 set_info().dev_type = strprintf("ps3stor,%d", tgt); 1575 } 1576 1577 linux_ps3stor_device::~linux_ps3stor_device() 1578 { 1579 if (m_open_flag) { 1580 m_open_flag = false; 1581 } 1582 set_fd(-1); // for ~linux_smart_device 1583 } 1584 1585 smart_device * linux_ps3stor_device::autodetect_open() 1586 { 1587 int report = scsi_debugmode; 1588 1589 // Open device 1590 if (!open()) 1591 return this; 1592 1593 // The code below is based on smartd.cpp:SCSIFilterKnown() 1594 if (strcmp(get_req_type(), "ps3stor")) 1595 return this; 1596 1597 // Get INQUIRY 1598 unsigned char req_buff[64] = {0, }; 1599 int req_len = 36; 1600 if (scsiStdInquiry(this, req_buff, req_len)) { 1601 close(); 1602 set_err(EIO, "INQUIRY failed"); 1603 return this; 1604 } 1605 1606 int avail_len = req_buff[4] + 5; 1607 int len = (avail_len < req_len ? avail_len : req_len); 1608 if (len < 36) 1609 return this; 1610 1611 if (report) 1612 pout("Got ps3stor inquiry.. %s\n", req_buff+8); 1613 1614 // Use INQUIRY to detect type 1615 { 1616 // SAT? 1617 ata_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); 1618 if (newdev) // NOTE: 'this' is now owned by '*newdev' 1619 return newdev; 1620 } 1621 1622 return this; 1623 } 1624 1625 bool linux_ps3stor_device::is_open() const 1626 { 1627 return m_open_flag; 1628 } 1629 1630 bool linux_ps3stor_device::open() 1631 { 1632 if(!m_open_flag) { 1633 1634 if (sscanf(get_dev_name(), "/dev/bus/%u", &m_host) == 0) { 1635 if (!linux_smart_device::open()) 1636 return false; 1637 /* Get device HBA */ 1638 struct sg_scsi_id sgid; 1639 if (ioctl(get_fd(), SG_GET_SCSI_ID, &sgid) == 0) { 1640 m_host = sgid.host_no; 1641 } 1642 else if (ioctl(get_fd(), SCSI_IOCTL_GET_BUS_NUMBER, &m_host) != 0) { 1643 int err = errno; 1644 linux_smart_device::close(); 1645 return set_err(err, "can't get bus number"); 1646 } // we don't need this device anymore 1647 linux_smart_device::close(); 1648 } 1649 m_open_flag = true; 1650 } 1651 return true; 1652 } 1653 1654 bool linux_ps3stor_device::close() 1655 { 1656 m_open_flag = false; 1657 return true; 1658 } 1659 1660 bool linux_ps3stor_device::scsi_pass_through(scsi_cmnd_io *iop) 1661 { 1662 int report = scsi_debugmode; 1663 1664 if (report > 0) { 1665 int k, j; 1666 const unsigned char * ucp = iop->cmnd; 1667 const char * np; 1668 char buff[256]; 1669 const int sz = (int)sizeof(buff); 1670 1671 np = scsi_get_opcode_name(ucp); 1672 j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); 1673 for (k = 0; k < (int)iop->cmnd_len; ++k) 1674 j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); 1675 if ((report > 1) && 1676 (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { 1677 int trunc = (iop->dxfer_len > 256) ? 1 : 0; 1678 1679 snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " 1680 "data, len=%d%s:\n", (int)iop->dxfer_len, 1681 (trunc ? " [only first 256 bytes shown]" : "")); 1682 dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); 1683 } 1684 else 1685 snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); 1686 pout("%s", buff); 1687 } 1688 1689 if (iop->cmnd[0] == 0x00) 1690 return true; 1691 1692 return scsi_cmd(iop); 1693 } 1694 1695 bool linux_ps3stor_device::scsi_cmd(scsi_cmnd_io *iop) 1696 { 1697 // Controller rejects Test Unit Ready 1698 if (iop->cmnd[0] == 0x00) 1699 return true; 1700 1701 if (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 || iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16) { 1702 // Controller does not return ATA output registers in SAT sense data 1703 if (iop->cmnd[2] & (1 << 5)) // chk_cond 1704 return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware"); 1705 } 1706 // SMART WRITE LOG SECTOR causing media errors 1707 if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 // SAT16 WRITE LOG 1708 && iop->cmnd[14] == ATA_SMART_CMD && iop->cmnd[3]==0 && iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) || 1709 (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 // SAT12 WRITE LOG 1710 && iop->cmnd[9] == ATA_SMART_CMD && iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)) 1711 { 1712 if(!failuretest_permissive) 1713 return set_err(ENOSYS, "SMART WRITE LOG SECTOR may cause problems, try with -T permissive to force"); 1714 } 1715 1716 if(iop->cmnd_len > PS3STOR_SCSI_MAX_CDB_LENGTH) { 1717 return set_err(ENOSYS, "ps3stor cannot support scsi cdb longer than %d", PS3STOR_SCSI_MAX_CDB_LENGTH); 1718 } 1719 1720 //get enclid slotid 1721 encl_id_t eid = 0; 1722 slot_id_t sid = 0; 1723 if(!get_pd_position(eid, sid)) { 1724 pout("linux_ps3stor_device::scsi_cmd: get_pd_position of device %u failed.\n", m_did); 1725 return set_err(EIO, "linux_ps3stor_device::scsi_cmd: get_pd_position of device %u failed.", m_did); 1726 } 1727 1728 // ps3stor_scsi_req 1729 1730 ps3stor_scsi_req_t scsireq = {}; 1731 scsireq.reserved = 1; 1732 switch (iop->dxfer_dir) { 1733 case DXFER_NONE: 1734 scsireq.cmddir = PS3STOR_SCSI_CMD_DIR_NONE; 1735 break; 1736 case DXFER_FROM_DEVICE: 1737 scsireq.cmddir = PS3STOR_SCSI_CMD_DIR_TO_HOST; 1738 break; 1739 case DXFER_TO_DEVICE: 1740 scsireq.cmddir = PS3STOR_SCSI_CMD_DIR_FROM_HOST; 1741 break; 1742 default: 1743 pout("scsi_cmd: bad dxfer_dir\n"); 1744 return set_err(EINVAL, "scsi_cmd: bad dxfer_dir\n"); 1745 } 1746 scsireq.checklen = 0; 1747 memcpy(scsireq.cdb, iop->cmnd, iop->cmnd_len); 1748 1749 1750 // ps3stor_scsi_rsp 1751 struct ps3stor_scsi_rsp scsirsp = {}; 1752 1753 if(PS3STOR_ERRNO_SUCCESS != ps3chn()->pd_scsi_passthrough(m_host, eid, sid, scsireq, scsirsp, iop->dxferp, iop->dxfer_len)) { 1754 return -1; 1755 } 1756 1757 if(scsirsp.entry.status != 0) { 1758 if(scsirsp.entry.status == 12) { 1759 return set_err(EIO, "linux_ps3stor_device::scsi_cmd: Device %u does not exist\n", m_did); 1760 } else { 1761 uint8_t scsi_status = scsirsp.entry.status; 1762 //ignore underrun 1763 if(scsi_status != PS3STOR_SCSI_STATUS_UNDERRUN) { 1764 //free(scsi_passthru); 1765 return set_err((errno ? errno : EIO), "linux_ps3stor_device::scsi_cmd result: %u.%u = %d/%hhu", 1766 m_host, m_did, errno, scsi_status 1767 ); 1768 } 1769 } 1770 } 1771 iop->scsi_status = scsirsp.entry.status; 1772 memcpy(iop->sensep, scsirsp.entry.sensebuf, PS3STOR_MIN(iop->max_sense_len, sizeof(scsirsp.entry.sensebuf))); 1773 return true; 1774 } 1775 1776 bool linux_ps3stor_device::get_pd_position(encl_id_t &eid, slot_id_t &sid) 1777 { 1778 ps3stor_pd_baseinfo_t baseinfo = {}; 1779 //1.get enclId and slotId from ioc for the first time 1780 if(m_eid == PS3STOR_INVALID_ENCL_ID && m_sid == PS3STOR_INVALID_SLOT_ID) { 1781 if(PS3STOR_ERRNO_SUCCESS != ps3chn()->pd_get_baseinfo_by_devid(m_host, m_did, baseinfo)) { 1782 return false; 1783 } 1784 m_eid = baseinfo.enclid; 1785 m_sid = baseinfo.slotid; 1786 } 1787 //2.copy value from member 1788 eid = m_eid; 1789 sid = m_sid; 1790 1791 return true; 1792 } 1793 1794 ///////////////////////////////////////////////////////////////////////////// 1526 1795 /// CCISS RAID support 1527 1796 1528 1797 #ifdef HAVE_LINUX_CCISS_IOCTL_H … … 2863 3132 bool get_dev_sssraid(smart_device_list & devlist); 2864 3133 int sssraid_pd_add_list(int bus_no, smart_device_list & devlist); 2865 3134 int sssraid_pdlist_cmd(int bus_no, uint16_t start_idx, void *buf, size_t bufsize, uint8_t *statusp); 3135 3136 bool get_dev_ps3stor(smart_device_list & devlist); 3137 int ps3stor_pd_add_list(int bus_no, smart_device_list & devlist); 3138 int ps3stor_pdlist_cmd(int bus_no, std::vector<uint16_t> &devidlist); 3139 2866 3140 }; 2867 3141 2868 3142 std::string linux_smart_interface::get_os_version_str() … … 3137 3411 get_dev_megasas(devlist); 3138 3412 // get device list from the sssraid device 3139 3413 get_dev_sssraid(devlist); 3414 3415 // get device list from the ps3stor device 3416 get_dev_ps3stor(devlist); 3140 3417 } 3141 3418 3142 3419 if (type_nvme) { … … 3323 3600 return (0); 3324 3601 } 3325 3602 3603 // getting devices from ps3 and ps3stor, if available 3604 bool linux_smart_interface::get_dev_ps3stor(smart_device_list &devlist) 3605 { 3606 // init ps3stor and get controller list , return false on err or not found 3607 if(!ps3stor_init()) { 3608 return false; 3609 } 3610 // try to add device for each controller 3611 std::vector<unsigned> hostlist; 3612 ps3chn()->get_host_list(hostlist); 3613 for(uint16_t i = 0; i < hostlist.size(); i++) 3614 { 3615 ps3stor_pd_add_list(hostlist.at(i), devlist); 3616 } 3617 return true; 3618 } 3619 3620 int linux_smart_interface::ps3stor_pd_add_list(int bus_no, smart_device_list &devlist) 3621 { 3622 // get pd device id list 3623 std::vector<uint16_t> devid_list; 3624 ps3stor_pdlist_cmd(bus_no, devid_list); 3625 3626 // add all SCSI devices 3627 for (unsigned i = 0; i < devid_list.size(); i++) { 3628 char line[128]; 3629 snprintf(line, sizeof(line) - 1, "/dev/bus/%d", bus_no); 3630 smart_device * dev = new linux_ps3stor_device(this, line, devid_list.at(i)); 3631 devlist.push_back(dev); 3632 } 3633 return (0); 3634 } 3635 3636 int linux_smart_interface::ps3stor_pdlist_cmd(int bus_no, std::vector<uint16_t> &devidlist) 3637 { 3638 // get enclist and get devlsit for each encl 3639 uint8_t enclcount = 0; 3640 struct ps3stor_encl_list *encllist = NULL; 3641 3642 //1.get encl count 3643 if(PS3STOR_ERRNO_SUCCESS != ps3chn()->get_enclcount(bus_no, enclcount)) 3644 { 3645 return -1; 3646 } 3647 3648 //2.get encl list 3649 if(enclcount > 0) 3650 { 3651 size_t listsize = sizeof(struct ps3stor_encl_list) + enclcount * sizeof(uint8_t); 3652 encllist = (struct ps3stor_encl_list*)malloc(listsize) ; 3653 if(PS3STOR_ERRNO_SUCCESS != ps3chn()->get_encllist(bus_no, encllist, listsize)) { 3654 free(encllist); 3655 encllist = NULL; 3656 return -1; 3657 } 3658 } 3659 3660 //3.get pd list for each encl 3661 if(encllist != NULL && encllist->count > 0) { 3662 enclcount = PS3STOR_MIN(enclcount, encllist->count); 3663 for(uint8_t i = 0; i < enclcount; i++){ 3664 uint16_t devcount = 0; 3665 uint8_t eid = encllist->idlist[i]; 3666 if(PS3STOR_ERRNO_SUCCESS != ps3chn()->pd_get_devcount_by_encl(bus_no, eid, devcount)) { 3667 return -1; 3668 } 3669 if(devcount > 0) 3670 { 3671 size_t listsize = sizeof(uint16_t) * devcount; 3672 uint16_t *devlist = (uint16_t*)malloc(listsize); 3673 memset(devlist, 0, listsize); 3674 if(PS3STOR_ERRNO_SUCCESS != ps3chn()->pd_get_devlist_by_encl(bus_no, eid, devlist, listsize)) { 3675 free(devlist); 3676 devlist = NULL; 3677 return -1; 3678 } 3679 for(int j = 0; j < devcount; j++) 3680 { 3681 devidlist.push_back(devlist[j]); 3682 } 3683 free(devlist); 3684 devlist = NULL; 3685 } 3686 3687 } 3688 } 3689 3690 if(encllist != NULL) { 3691 free(encllist); 3692 encllist = NULL; 3693 } 3694 3695 return 0; 3696 } 3697 3326 3698 int 3327 3699 linux_smart_interface::sssraid_pd_add_list(int bus_no, smart_device_list & devlist) 3328 3700 { … … 3613 3985 3614 3986 } 3615 3987 3988 // ps3stor ? 3989 if (sscanf(type, "ps3stor,%d", &disknum) == 1) { 3990 if(ps3stor_init()) { 3991 return new linux_ps3stor_device(this, name, disknum); 3992 } else { 3993 pout("get_custom_smart_device: ps3stor_init failed.\n"); 3994 set_err_np(EINVAL, "get_custom_smart_device: ps3stor_init failed.\n"); 3995 } 3996 3997 } 3998 3616 3999 return nullptr; 3617 4000 } 3618 4001 3619 4002 std::string linux_smart_interface::get_valid_custom_dev_types_str() 3620 4003 { 3621 return "areca,N/E, 3ware,N, hpt,L/M/N, megaraid,N, aacraid,H,L,ID, sssraid,E,S "4004 return "areca,N/E, 3ware,N, hpt,L/M/N, megaraid,N, aacraid,H,L,ID, sssraid,E,S, ps3stor,N" 3622 4005 #ifdef HAVE_LINUX_CCISS_IOCTL_H 3623 4006 ", cciss,N" 3624 4007 #endif … … 3625 4008 ; 3626 4009 } 3627 4010 4011 /// Linux ps3stor channel 4012 class linux_ps3stor_channel 4013 : public /*implements*/ ps3stor_channel 4014 { 4015 public: 4016 linux_ps3stor_channel(); 4017 virtual ~linux_ps3stor_channel(); 4018 enum ps3stor_device_type { 4019 PS3STOR_DEVICE_TYPE_PS3 = 0, 4020 PS3STOR_DEVICE_TYPE_PS3STOR, 4021 PS3STOR_DEVICE_TYPE_NR 4022 }; 4023 4024 public: 4025 virtual ps3stor_errno channel_init() override; 4026 4027 virtual ps3stor_errno get_host_list(std::vector<unsigned> &hostlist) override; 4028 4029 protected: 4030 virtual ps3stor_errno firecmd(unsigned hostid, struct ps3stor_msg_info * info, struct ps3stor_msg_info * ackinfo, unsigned acksize) override; 4031 4032 virtual ps3stor_errno firecmd_scsi(unsigned hostid, struct ps3stor_msg_info * reqinfo, struct ps3stor_msg_info * ackinfo, 4033 unsigned acksize, struct ps3stor_data * scsidata, unsigned scsicount) override; 4034 4035 4036 virtual struct ps3stor_tlv *add_tlv_data(struct ps3stor_tlv *tlv, unsigned type, const void *data, uint16_t size) override; 4037 virtual bool set_err(int no, const char * msg) override; 4038 virtual bool set_err(int no) override; 4039 4040 private: 4041 int m_devfd_ps3; 4042 int m_devfd_ps3stor; 4043 std::map<unsigned, struct ps3stor_pci_info> m_host_map; 4044 4045 int open_node(enum ps3stor_device_type dev_type); 4046 ps3stor_errno get_func_by_host(unsigned hostid, uint8_t &funcid); 4047 ps3stor_errno get_pci_info(unsigned host, struct ps3stor_pci_info &pci_info); 4048 void find_device(enum ps3stor_device_type dev_type); 4049 ps3stor_errno get_devfd(unsigned host, int &devfd); 4050 4051 void print_packet(struct ps3stor_ioctl_sync_cmd &packet); // print packet msg for debug 4052 4053 }; 4054 4055 linux_ps3stor_channel::linux_ps3stor_channel() 4056 { 4057 m_devfd_ps3 = -1; 4058 m_devfd_ps3stor = -1; 4059 } 4060 4061 linux_ps3stor_channel::~linux_ps3stor_channel() 4062 { 4063 if(m_devfd_ps3 >= 0) 4064 ::close(m_devfd_ps3); 4065 4066 if(m_devfd_ps3stor >= 0) 4067 ::close(m_devfd_ps3stor); 4068 } 4069 4070 ps3stor_errno linux_ps3stor_channel::channel_init() 4071 { 4072 ps3stor_errno err = PS3STOR_ERRNO_SUCCESS; 4073 if(m_init) { 4074 return err; 4075 } 4076 4077 m_devfd_ps3 = open_node(PS3STOR_DEVICE_TYPE_PS3); 4078 if(m_devfd_ps3 > 0) { 4079 find_device(PS3STOR_DEVICE_TYPE_PS3); 4080 } 4081 4082 m_devfd_ps3stor = open_node(PS3STOR_DEVICE_TYPE_PS3STOR); 4083 if(m_devfd_ps3stor > 0) { 4084 find_device(PS3STOR_DEVICE_TYPE_PS3STOR); 4085 } 4086 4087 if(m_host_map.size() > 0) { 4088 m_init = true; 4089 } 4090 4091 return err; 4092 } 4093 4094 ps3stor_errno linux_ps3stor_channel::get_host_list(std::vector<unsigned> &hostlist) 4095 { 4096 for(auto it : m_host_map) 4097 { 4098 hostlist.push_back(it.first); 4099 } 4100 return PS3STOR_ERRNO_SUCCESS; 4101 } 4102 4103 ps3stor_errno linux_ps3stor_channel::firecmd(unsigned hostid, struct ps3stor_msg_info * reqinfo, struct ps3stor_msg_info * ackinfo, unsigned acksize) 4104 { 4105 ps3stor_errno err = PS3STOR_ERRNO_SUCCESS; 4106 int devfd = -1; 4107 const size_t insize = (reqinfo == NULL ? 0 : reqinfo->length); 4108 uint8_t funcid = 0; 4109 4110 reqinfo->magic = PS3STOR_MSG_MAGIC_CODE; 4111 reqinfo->error = PS3STOR_ERRNO_SUCCESS; 4112 reqinfo->timeout = 0; 4113 reqinfo->start_time = 0; 4114 reqinfo->runver = PS3STOR_ITR_VER; 4115 reqinfo->uuid = 0; 4116 reqinfo->service = PS3STOR_SMARTCTL_SERVICE; 4117 reqinfo->traceid = 0xffc73a859920e01; 4118 get_func_by_host(hostid, funcid); 4119 reqinfo->funcid = funcid; 4120 4121 const uint16_t inblk = (uint16_t)((insize + PS3STOR_SGL_SIZE -1) / PS3STOR_SGL_SIZE); 4122 const uint16_t outblk = (uint16_t)((acksize + PS3STOR_SGL_SIZE -1) / PS3STOR_SGL_SIZE); 4123 4124 struct ps3stor_ioctl_sync_cmd packet = {}; 4125 packet.hostid = (uint16_t)hostid; 4126 packet.sge_count = inblk + outblk; 4127 packet.sgl_offset = offsetof(struct ps3stor_ioctl_sync_cmd, sgl) / sizeof(uint32_t); // 4 bytes 4128 packet.traceid = reqinfo->traceid; 4129 4130 reqinfo->index.tlv = 0; 4131 reqinfo->index.ack = (uint8_t)(inblk); 4132 reqinfo->ack_length = acksize; 4133 reqinfo->ack_offset = (uint32_t)insize; 4134 4135 for(uint16_t i = 0; i < inblk; i++) { 4136 packet.sgl[i].addr = (uint64_t)(intptr_t) & ((uint8_t*)reqinfo)[PS3STOR_SGL_SIZE * i]; 4137 packet.sgl[i].length = (uint32_t)((i == inblk - 1) ? (insize - (PS3STOR_SGL_SIZE * i)) : PS3STOR_SGL_SIZE); 4138 } 4139 4140 for(uint16_t i = 0; i < outblk; i++) { 4141 packet.sgl[inblk + i].addr = (uint64_t)(intptr_t) & ((uint8_t*)ackinfo)[PS3STOR_SGL_SIZE * i]; 4142 packet.sgl[inblk + i].length = (uint32_t)((i == outblk - 1) ? (acksize - (PS3STOR_SGL_SIZE * i)) : PS3STOR_SGL_SIZE); 4143 } 4144 4145 err = get_devfd(hostid, devfd); 4146 if(err != PS3STOR_ERRNO_SUCCESS) { 4147 return err; 4148 } 4149 int res = ioctl(devfd, PS3STOR_CMD_IOCTL_SYNC_CMD, &packet); 4150 if(res < 0) { 4151 set_err(errno, "ioctl failed.\n"); 4152 return -1; 4153 } 4154 if(ackinfo->magic != PS3STOR_MSG_MAGIC_CODE) { 4155 set_err(EIO, "check magic code failed.\n"); 4156 return -1; 4157 } 4158 if(ackinfo->error != PS3STOR_ERRNO_SUCCESS) { 4159 set_err(EIO, "err form ioc.\n"); 4160 return -1; 4161 } 4162 return err; 4163 } 4164 4165 ps3stor_errno linux_ps3stor_channel::firecmd_scsi(unsigned hostid, struct ps3stor_msg_info * reqinfo, struct ps3stor_msg_info * ackinfo, 4166 unsigned acksize, struct ps3stor_data * scsidata, unsigned scsicount) 4167 { 4168 ps3stor_errno err = PS3STOR_ERRNO_SUCCESS; 4169 int devfd = -1; 4170 const size_t insize = (reqinfo == NULL ? 0 : reqinfo->length); 4171 uint8_t funcid = 0; 4172 4173 reqinfo->magic = PS3STOR_MSG_MAGIC_CODE; 4174 reqinfo->error = PS3STOR_ERRNO_SUCCESS; 4175 reqinfo->timeout = 0; 4176 reqinfo->start_time = 0; 4177 reqinfo->runver = PS3STOR_ITR_VER; 4178 reqinfo->uuid = 0; 4179 reqinfo->service = PS3STOR_SMARTCTL_SERVICE; 4180 reqinfo->traceid = 0xffc73a859920e01; 4181 get_func_by_host(hostid, funcid); 4182 reqinfo->funcid = funcid; 4183 4184 const uint16_t inblk = (uint16_t)((insize + PS3STOR_SGL_SIZE -1) / PS3STOR_SGL_SIZE); 4185 const uint16_t outblk = (uint16_t)((acksize + PS3STOR_SGL_SIZE -1) / PS3STOR_SGL_SIZE); 4186 const uint16_t scsiblk = (uint16_t)scsicount; 4187 4188 struct ps3stor_ioctl_sync_cmd packet = {}; 4189 packet.hostid = (uint16_t)hostid; 4190 packet.sge_count = inblk + outblk + scsiblk; 4191 packet.sgl_offset = offsetof(struct ps3stor_ioctl_sync_cmd, sgl) / sizeof(uint32_t); // 4 bytes 4192 packet.traceid = reqinfo->traceid; 4193 4194 //todo check for sge_count <= 16 4195 4196 reqinfo->index.tlv = 0; 4197 reqinfo->index.ack = (uint8_t)(inblk); 4198 reqinfo->ack_length = acksize; 4199 reqinfo->ack_offset = (uint32_t)insize; 4200 4201 for(uint16_t i = 0; i < inblk; i++) { 4202 packet.sgl[i].addr = (uint64_t)(intptr_t) & ((uint8_t*)reqinfo)[PS3STOR_SGL_SIZE * i]; 4203 packet.sgl[i].length = (uint32_t)((i == inblk - 1) ? (insize - (PS3STOR_SGL_SIZE * i)) : PS3STOR_SGL_SIZE); 4204 } 4205 4206 for(uint16_t i = 0; i < outblk; i++) { 4207 packet.sgl[inblk + i].addr = (uint64_t)(intptr_t) & ((uint8_t*)ackinfo)[PS3STOR_SGL_SIZE * i]; 4208 packet.sgl[inblk + i].length = (uint32_t)((i == outblk - 1) ? (acksize - (PS3STOR_SGL_SIZE * i)) : PS3STOR_SGL_SIZE); 4209 } 4210 4211 for(uint16_t i = 0; i < scsiblk; i++) { 4212 packet.sgl[inblk + outblk + i].addr = (uint64_t)(intptr_t)scsidata[i].pdata; 4213 packet.sgl[inblk + outblk + i].length = scsidata[i].size; 4214 } 4215 err = get_devfd(hostid, devfd); 4216 if(err != PS3STOR_ERRNO_SUCCESS) { 4217 return err; 4218 } 4219 4220 int res = ioctl(devfd, PS3STOR_CMD_IOCTL_SYNC_CMD, &packet); 4221 if(res < 0) { 4222 set_err(errno, "ioctl failed.\n"); 4223 return -1; 4224 } 4225 if(ackinfo->magic != PS3STOR_MSG_MAGIC_CODE) { 4226 set_err(EIO, "check magic code failed.\n"); 4227 return -1; 4228 } 4229 if(ackinfo->error != PS3STOR_ERRNO_SUCCESS) { 4230 set_err(EIO, "err form ioc.\n"); 4231 return -1; 4232 } 4233 return err; 4234 } 4235 4236 struct ps3stor_tlv *linux_ps3stor_channel::add_tlv_data(struct ps3stor_tlv *tlv, unsigned type, const void *data, uint16_t size) 4237 { 4238 if(data == NULL || size == 0) { 4239 return tlv; 4240 } 4241 4242 unsigned tlvcode = type; 4243 4244 // calculate tlvsize 4245 uint16_t tlvsize = (uint16_t)(sizeof(*tlv) ///< tlv 头 4246 + ((tlv == NULL) ? 0 : tlv->size) ///< 已存在tlv的长度 4247 + sizeof(tlvcode) ///< 新 tlv:type 长度 4248 + sizeof(size) ///< 新 tlv:length 长度 4249 + size); 4250 4251 if(tlv == NULL) { 4252 tlv = (struct ps3stor_tlv *)malloc(tlvsize); 4253 memset(tlv, 0, tlvsize); 4254 } else { 4255 struct ps3stor_tlv * tmp = (struct ps3stor_tlv *)realloc(tlv, tlvsize); 4256 if(tmp == NULL) { 4257 free(tlv); 4258 } 4259 tlv = tmp; 4260 } 4261 4262 // add data 4263 if (tlv != NULL) 4264 { 4265 memcpy(tlv->buff + tlv->size, &tlvcode, sizeof(tlvcode)); 4266 tlv->size += sizeof(tlvcode); 4267 memcpy(tlv->buff + tlv->size, &size, sizeof(size)); 4268 tlv->size += sizeof(size); 4269 memcpy(tlv->buff + tlv->size, data, size); 4270 tlv->size += size; 4271 } 4272 4273 return tlv; 4274 } 4275 4276 bool linux_ps3stor_channel::set_err(int no, const char * msg) 4277 { 4278 return smi()->set_err(no, "%s", msg); 4279 } 4280 4281 bool linux_ps3stor_channel::set_err(int no) 4282 { 4283 return smi()->set_err(no); 4284 } 4285 4286 int linux_ps3stor_channel::open_node(enum ps3stor_device_type dev_type) 4287 { 4288 /* Scanning of disks on ps3stor device */ 4289 /* Perform mknod of device ioctl node */ 4290 char line[128]; 4291 int mjr = -1; //major device number 4292 int n1 = -1; 4293 int devnode_fd = -1; 4294 // scan ps3stor 4295 FILE * fp = fopen(PS3STOR_DRIVE_DEVICE_ID, "r"); 4296 if (!fp) 4297 return devnode_fd; 4298 4299 switch (dev_type) 4300 { 4301 case PS3STOR_DEVICE_TYPE_PS3: 4302 while (fgets(line, sizeof(line), fp) != NULL) { 4303 n1=0; 4304 int tmp = sscanf(line, "%d ps3-ioctl%n", &mjr, &n1); 4305 //if (sscanf(line, "%d ps3-ioctl%n", &mjr, &n1) == 1 && n1 == 13) { 4306 if (tmp == 1 && n1 == 13) { 4307 n1=mknod("/dev/ps3-ioctl", S_IFCHR|0600, makedev(mjr, 0)); 4308 if(scsi_debugmode > 0) 4309 pout("Creating /dev/ps3-ioctl = %d\n", n1 >= 0 ? 0 : errno); 4310 if (n1 >= 0 || errno == EEXIST) { 4311 devnode_fd = ::open("/dev/ps3-ioctl", O_RDWR); 4312 break; 4313 } else { 4314 break; 4315 } 4316 } 4317 } 4318 break; 4319 case PS3STOR_DEVICE_TYPE_PS3STOR: 4320 while (fgets(line, sizeof(line), fp) != NULL) { 4321 n1=0; 4322 int tmp = sscanf(line, "%d ps3stor-ioctl%n", &mjr, &n1); 4323 //if (sscanf(line, "%d ps3stor-ioctl%n", &mjr, &n1) == 1 && n1 == 17) { 4324 if (tmp == 1 && n1 == 17) { 4325 n1=mknod("/dev/ps3stor-ioctl", S_IFCHR|0600, makedev(mjr, 0)); 4326 if(scsi_debugmode > 0) 4327 pout("Creating /dev/ps3stor-ioctl = %d\n", n1 >= 0 ? 0 : errno); 4328 if (n1 >= 0 || errno == EEXIST) { 4329 devnode_fd = ::open("/dev/ps3stor-ioctl", O_RDWR); 4330 break; 4331 } else { 4332 break; 4333 } 4334 } 4335 } 4336 break; 4337 default: 4338 break; 4339 } 4340 fclose(fp); 4341 return devnode_fd; 4342 } 4343 4344 ps3stor_errno linux_ps3stor_channel::get_func_by_host(unsigned hostid, uint8_t &funcid) 4345 { 4346 for(auto it : m_host_map) 4347 { 4348 if(it.first == hostid) { 4349 funcid = it.second.function; 4350 return PS3STOR_ERRNO_SUCCESS; 4351 } 4352 } 4353 return -1; 4354 } 4355 4356 ps3stor_errno linux_ps3stor_channel::get_pci_info(unsigned host, ps3stor_pci_info &pci_info) 4357 { 4358 ps3stor_errno err = PS3STOR_ERRNO_SUCCESS; 4359 char path[128] = {}; 4360 char filelink[128] = {}; 4361 4362 snprintf(path, sizeof(path) - 1, "/sys/class/scsi_host/host%u", host); 4363 err = readlink(path, filelink, sizeof(filelink)); 4364 if(err < 0) { 4365 return errno; 4366 } 4367 err = -1; 4368 const char templatestr[] = "0000:00:00.0"; // look up pci addr by file link 4369 unsigned templen = strlen(templatestr); 4370 if(strlen(path) < templen) { 4371 return -1; 4372 } 4373 4374 for(unsigned i = 0; *(filelink + i + templen) != '\0'; i++){ 4375 char *begin = filelink + i; 4376 bool match = true; 4377 for(unsigned j = 0; j < templen; j++) { 4378 if(begin[j] == templatestr[j]) { 4379 continue; 4380 } else if (isxdigit(begin[j]) && templatestr[j] == '0'){ 4381 continue; 4382 } else { 4383 match = false; 4384 break; 4385 } 4386 } 4387 if(match) { 4388 err = PS3STOR_ERRNO_SUCCESS; 4389 memcpy(pci_info.pci_addr, begin, templen + 1); 4390 sscanf(pci_info.pci_addr, "%x:%hhx:%hhx.%hhx", 4391 &pci_info.domainid, &pci_info.busid, &pci_info.deviceid, &pci_info.function); 4392 } 4393 } 4394 return err; 4395 } 4396 4397 void linux_ps3stor_channel::find_device(enum ps3stor_device_type dev_type) 4398 { 4399 // getting bus numbers with ps3stor controllers 4400 // we are using sysfs to get list of all scsi hosts 4401 char procctx[16] = {}; 4402 size_t proclen = 0; 4403 switch (dev_type) 4404 { 4405 case PS3STOR_DEVICE_TYPE_PS3: 4406 snprintf(procctx, sizeof(procctx) - 1, "%s", "ps3\n"); 4407 proclen = 4; 4408 break; 4409 case PS3STOR_DEVICE_TYPE_PS3STOR: 4410 snprintf(procctx, sizeof(procctx) - 1, "%s", "ps3stor\n"); 4411 proclen = 7; 4412 break; 4413 default: 4414 return; 4415 break; 4416 } 4417 4418 DIR * dp = opendir(PS3STOR_SYS_CLASS_SCSI_HOST_PATH); 4419 if (dp != NULL) 4420 { 4421 struct dirent *ep; 4422 FILE* fp = NULL; 4423 char line[128] = {}; 4424 while ((ep = readdir (dp)) != NULL) { 4425 unsigned int host_no = 0; 4426 if (!sscanf(ep->d_name, "host%u", &host_no)) 4427 continue; 4428 /* proc_name should be procctx */ 4429 char sysfsdir[256] = {}; 4430 snprintf(sysfsdir, sizeof(sysfsdir) - 1, 4431 "/sys/class/scsi_host/host%u/proc_name", host_no); 4432 if((fp = fopen(sysfsdir, "r")) == NULL) 4433 continue; 4434 if(fgets(line, sizeof(line), fp) != NULL && !strncmp(line, procctx, proclen)) { 4435 struct ps3stor_pci_info pci = {}; 4436 if(get_pci_info(host_no, pci) == PS3STOR_ERRNO_SUCCESS) { 4437 pci.devtype = dev_type; 4438 m_host_map[host_no] = pci; 4439 } 4440 } 4441 fclose(fp); 4442 } 4443 (void) closedir(dp); 4444 } 4445 return; 4446 } 4447 4448 ps3stor_errno linux_ps3stor_channel::get_devfd(unsigned host, int &devfd) 4449 { 4450 ps3stor_errno err = -1; 4451 for(auto it : m_host_map) 4452 { 4453 if(it.first == host) { 4454 switch (it.second.devtype) 4455 { 4456 case PS3STOR_DEVICE_TYPE_PS3: 4457 devfd = m_devfd_ps3; 4458 err = PS3STOR_ERRNO_SUCCESS; 4459 return err; 4460 case PS3STOR_DEVICE_TYPE_PS3STOR: 4461 devfd = m_devfd_ps3stor; 4462 err = PS3STOR_ERRNO_SUCCESS; 4463 return err; 4464 default: 4465 break; 4466 }; 4467 break; 4468 } 4469 } 4470 return err; 4471 } 4472 4473 void linux_ps3stor_channel::print_packet(ps3stor_ioctl_sync_cmd &packet) 4474 { 4475 for(uint16_t i = 0; i < packet.sge_count; i++) { 4476 char tmp_buf[1024 * 4] = {}; 4477 uint32_t sz = 1024 * 4; 4478 uint32_t len = 0; 4479 len = snprintf(tmp_buf, sz, "=============sgl[%hu]:length = %u =============:\n", i, packet.sgl[i].length); 4480 for(uint32_t j = 0; j < packet.sgl[i].length && len < sz ; j++) { 4481 if(j % 32 == 0){ 4482 len += snprintf(&tmp_buf[len], (sz > len ? (sz - len) : 0), "0x%04x: ", j); 4483 } 4484 uint8_t* buff = (uint8_t*)(intptr_t)packet.sgl[i].addr; 4485 len += snprintf(&tmp_buf[len], (sz > len ? (sz - len) : 0), "%02x ", buff[j]); 4486 if((j + 1) % 4 == 0) { 4487 len += snprintf(&tmp_buf[len], (sz > len ? (sz - len) : 0), " "); 4488 } 4489 if((j + 1) % 32 == 0) { 4490 len += snprintf(&tmp_buf[len], (sz > len ? (sz - len) : 0), "\n"); 4491 } 4492 } 4493 pout("%s\n=================================\n", tmp_buf); 4494 } 4495 4496 } 4497 3628 4498 } // namespace 3629 4499 3630 4500 ///////////////////////////////////////////////////////////////////////////// … … 3635 4505 static os_linux::linux_smart_interface the_interface; 3636 4506 smart_interface::set(&the_interface); 3637 4507 } 4508 4509 void ps3stor_channel::init() 4510 { 4511 static os_linux::linux_ps3stor_channel the_ps3stor_instance; 4512 ps3stor_channel::set(&the_ps3stor_instance); 4513 } 4514 4515 bool ps3stor_init() 4516 { 4517 if(!ps3chn()) { 4518 ps3stor_channel::init(); 4519 if (!ps3chn()) 4520 return false; 4521 } 4522 if(PS3STOR_ERRNO_SUCCESS != ps3chn()->channel_init()) { 4523 return false; 4524 } 4525 return true; 4526 } 4527 No newline at end of file -
ps3stor.cpp
1 /* 2 * ps3stor.cpp 3 * 4 * Home page of code is: http://www.smartmontools.org 5 * 6 * Copyright (C) 2024 Hong Xu 7 * 8 * SPDX-License-Identifier: GPL-2.0-or-later 9 */ 10 11 #include "ps3stor.h" 12 ps3stor_channel * ps3stor_channel::s_channel; 13 14 ps3stor_errno ps3stor_channel::get_enclcount(unsigned hostid, uint8_t &enclcount) 15 { 16 struct ps3stor_msg_info* reqinfo = NULL; 17 size_t insize = sizeof(struct ps3stor_msg_info); 18 reqinfo = (struct ps3stor_msg_info*)malloc(insize); 19 memset(reqinfo, 0, insize); 20 reqinfo->length = insize; 21 reqinfo->opcode = PS3STOR_CMD_ENCL_GET_COUNT; 22 23 struct ps3stor_msg_info* rspinfo = NULL; 24 size_t outsize = sizeof(struct ps3stor_msg_info) + sizeof(enclcount); 25 rspinfo = (struct ps3stor_msg_info*)malloc(outsize); 26 memset(rspinfo, 0, outsize); 27 28 if(PS3STOR_ERRNO_SUCCESS != firecmd(hostid, reqinfo, rspinfo, outsize)) { 29 free(reqinfo); 30 free(rspinfo); 31 return -1; 32 } 33 memcpy(&enclcount, rspinfo->body, sizeof(enclcount)); 34 free(reqinfo); 35 free(rspinfo); 36 return 0; 37 } 38 39 ps3stor_errno ps3stor_channel::get_encllist(unsigned hostid, ps3stor_encl_list *&encllist, size_t listsize) 40 { 41 struct ps3stor_msg_info* reqinfo = NULL; 42 size_t insize = sizeof(struct ps3stor_msg_info); 43 reqinfo = (struct ps3stor_msg_info*)malloc(insize); 44 memset(reqinfo, 0, insize); 45 reqinfo->length = insize; 46 reqinfo->opcode = PS3STOR_CMD_ENCL_GET_LIST; 47 48 struct ps3stor_msg_info* rspinfo = NULL; 49 size_t outsize = sizeof(struct ps3stor_msg_info) + listsize; 50 rspinfo = (struct ps3stor_msg_info*)malloc(outsize); 51 memset(rspinfo, 0, outsize); 52 53 if(PS3STOR_ERRNO_SUCCESS != firecmd(hostid, reqinfo, rspinfo, outsize)) { 54 free(reqinfo); 55 free(rspinfo); 56 return -1; 57 } 58 memcpy(encllist, rspinfo->body, listsize); 59 free(reqinfo); 60 free(rspinfo); 61 return 0; 62 } 63 64 ps3stor_errno ps3stor_channel::pd_get_devcount_by_encl(unsigned hostid, uint8_t enclid, uint16_t &devcount) 65 { 66 struct ps3stor_msg_info* reqinfo = NULL; 67 size_t insize = sizeof(struct ps3stor_msg_info); 68 reqinfo = (struct ps3stor_msg_info*)malloc(insize); 69 memset(reqinfo, 0, insize); 70 reqinfo->length = insize; 71 reqinfo->opcode = PS3STOR_CMD_PD_GET_COUNT_IN_ENCL; 72 reqinfo->id.type = PS3STOR_ID_GROUP_TYPE_PD_POSITION; 73 reqinfo->id.pd_position.enclid = enclid; 74 75 struct ps3stor_msg_info* rspinfo = NULL; 76 size_t outsize = sizeof(struct ps3stor_msg_info) + sizeof(devcount); 77 rspinfo = (struct ps3stor_msg_info*)malloc(outsize); 78 memset(rspinfo, 0, outsize); 79 80 if(PS3STOR_ERRNO_SUCCESS != firecmd(hostid, reqinfo, rspinfo, outsize)) { 81 free(reqinfo); 82 free(rspinfo); 83 return -1; 84 } 85 memcpy(&devcount, rspinfo->body, sizeof(devcount)); 86 free(reqinfo); 87 free(rspinfo); 88 return 0; 89 } 90 91 ps3stor_errno ps3stor_channel::pd_get_devlist_by_encl(unsigned hostid, uint8_t enclid, uint16_t *&devlist, size_t listsize) 92 { 93 ps3stor_errno err = PS3STOR_ERRNO_SUCCESS; 94 95 struct ps3stor_msg_info* reqinfo = NULL; 96 size_t insize = sizeof(struct ps3stor_msg_info); 97 reqinfo = (struct ps3stor_msg_info*)malloc(insize); 98 memset(reqinfo, 0, insize); 99 reqinfo->length = insize; 100 reqinfo->opcode = PS3STOR_CMD_PD_GET_DEV_LIST_IN_ENCL; 101 102 struct ps3stor_msg_info* rspinfo = NULL; 103 size_t outsize = sizeof(struct ps3stor_msg_info) + listsize; 104 rspinfo = (struct ps3stor_msg_info*)malloc(outsize); 105 memset(rspinfo, 0, outsize); 106 reqinfo->id.type = PS3STOR_ID_GROUP_TYPE_PD_POSITION; 107 reqinfo->id.pd_position.enclid = enclid; 108 109 if(PS3STOR_ERRNO_SUCCESS != firecmd(hostid, reqinfo, rspinfo, outsize)) { 110 free(reqinfo); 111 free(rspinfo); 112 return -1; 113 } 114 memcpy(devlist, rspinfo->body, listsize); 115 free(reqinfo); 116 free(rspinfo); 117 return err; 118 } 119 120 ps3stor_errno ps3stor_channel::pd_get_baseinfo_by_devid(unsigned hostid, unsigned devid, ps3stor_pd_baseinfo_t &baseinfo) 121 { 122 baseinfo.enclid = 0; 123 baseinfo.slotid = 0; 124 ps3stor_batch_req_t *batchreq = NULL; 125 struct ps3stor_tlv *req_tlv = NULL; 126 uint32_t id_count = 1; 127 uint32_t data_size = sizeof(ps3stor_pd_baseinfo_t); 128 129 unsigned reqsize = sizeof(ps3stor_batch_req_t) + id_count * sizeof(struct ps3stor_id_group); 130 batchreq = (ps3stor_batch_req_t*)malloc(reqsize); 131 memset(batchreq, 0, reqsize); 132 batchreq->idcount = id_count; 133 batchreq->datasize = data_size; 134 batchreq->idgroup[0].type = PS3STOR_ID_GROUP_TYPE_DEVICE_ID; 135 batchreq->idgroup[0].deviceid = (uint16_t)devid; 136 137 //packet batchreq 138 139 req_tlv = add_tlv_data(req_tlv, PS3STOR_MK_TLV_CODE(PS3STOR_BATCH_TLV_CODE_MASK, ps3stor_batch_req_t, idcount), 140 &batchreq->idcount, (uint16_t)sizeof(batchreq->idcount)); 141 req_tlv = add_tlv_data(req_tlv, PS3STOR_MK_TLV_CODE(PS3STOR_BATCH_TLV_CODE_MASK, ps3stor_batch_req_t, datasize), 142 &batchreq->datasize, (uint16_t)sizeof(batchreq->datasize)); 143 req_tlv = add_tlv_data(req_tlv, PS3STOR_MK_TLV_CODE(PS3STOR_BATCH_TLV_CODE_MASK, ps3stor_batch_req_t, idgroup), 144 &batchreq->idgroup, (uint16_t)(id_count * sizeof(struct ps3stor_id_group))); 145 if(req_tlv == NULL) { 146 free(batchreq); 147 return -1; 148 } 149 150 ps3stor_batch_rsp_t *batchrsp = NULL; 151 unsigned rspsize = sizeof(ps3stor_batch_rsp_t) + id_count * (sizeof(ps3stor_rsp_entry_t) + sizeof(ps3stor_pd_baseinfo_t)); 152 batchrsp = (ps3stor_batch_rsp_t*)malloc(rspsize); 153 memset(batchrsp, 0, rspsize); 154 155 // call ioc 156 struct ps3stor_msg_info* reqinfo = NULL; 157 size_t insize = sizeof(struct ps3stor_msg_info) + req_tlv->size; 158 reqinfo = (struct ps3stor_msg_info*)malloc(insize); 159 memset(reqinfo, 0, insize); 160 reqinfo->length = insize; 161 reqinfo->opcode = PS3STOR_CMD_PD_BASE_INFO; 162 memcpy(reqinfo->body, req_tlv->buff, req_tlv->size); 163 164 struct ps3stor_msg_info* rspinfo = NULL; 165 size_t outsize = sizeof(struct ps3stor_msg_info) + rspsize; 166 rspinfo = (struct ps3stor_msg_info*)malloc(outsize); 167 memset(rspinfo, 0, outsize); 168 169 if(PS3STOR_ERRNO_SUCCESS != firecmd(hostid, reqinfo, rspinfo, outsize)) { 170 free(batchreq); 171 free(req_tlv); 172 free(batchrsp); 173 free(reqinfo); 174 free(rspinfo); 175 return -1; 176 } 177 memcpy(batchrsp, rspinfo->body, rspsize); 178 ps3stor_rsp_entry_t* entry = (ps3stor_rsp_entry_t*)batchrsp->rsp_entry; 179 if(entry != NULL && entry->result == PS3STOR_ERRNO_SUCCESS) { 180 memcpy(&baseinfo, entry->data, PS3STOR_MIN(entry->size, sizeof(ps3stor_pd_baseinfo_t))); 181 } else { 182 free(batchreq); 183 free(req_tlv); 184 free(batchrsp); 185 free(reqinfo); 186 free(rspinfo); 187 return -1; 188 } 189 190 free(batchreq); 191 free(req_tlv); 192 free(batchrsp); 193 free(reqinfo); 194 free(rspinfo); 195 return 0; 196 } 197 198 199 ps3stor_errno ps3stor_channel::pd_scsi_passthrough(unsigned hostid, uint8_t eid, uint16_t sid, 200 ps3stor_scsi_req_t &scsireq, ps3stor_scsi_rsp &scsirsp, 201 uint8_t *&scsidata, const size_t scsilen) 202 { 203 // 1. scsi data align 204 unsigned scsicount = scsilen / PS3STOR_SGL_SIZE; 205 scsicount = (scsilen % PS3STOR_SGL_SIZE == 0) ? (scsicount) : ((scsicount + 1)); 206 struct ps3stor_data scsiblks[PS3STOR_SCSI_MAX_BLK_CNT] = {}; 207 if (scsicount > PS3STOR_SCSI_MAX_BLK_CNT) 208 { 209 set_err(EIO, "linux_ps3stor_device::scsi_cmd: request for scsi data is too large."); 210 return -1; 211 } 212 213 for(unsigned i = 0; i < scsicount; i++) { 214 unsigned size = PS3STOR_SGL_SIZE; 215 if(i == scsicount - 1) { 216 size = scsilen - i * PS3STOR_SGL_SIZE; 217 } 218 size = (size % PS3STOR_SCSI_ALIGN_SIZE == 0) ? (size) : ((size / PS3STOR_SCSI_ALIGN_SIZE + 1) * PS3STOR_SCSI_ALIGN_SIZE); 219 scsiblks[i].pdata = malloc(size); 220 memset(scsiblks[i].pdata, 0, size); 221 scsiblks[i].size = size; 222 scsireq.req.datalen += size; 223 } 224 225 scsireq.req.sgecount = (scsireq.req.datalen + PS3STOR_SCSI_BYTE_PER_CMD - 1) / PS3STOR_SCSI_BYTE_PER_CMD; 226 scsireq.req.sgeindex = PS3STOR_SCSI_SGE_INDEX_BASE; 227 228 scsireq.req.id.type = PS3STOR_ID_GROUP_TYPE_PD_POSITION; 229 scsireq.req.id.pd_position.enclid = eid; 230 scsireq.req.id.pd_position.slotid = sid; 231 232 // 2. packet scsireq 233 struct ps3stor_tlv *scsireq_tlv = NULL; 234 scsireq_tlv = add_tlv_data(scsireq_tlv, PS3STOR_MK_TLV_CODE(PS3STOR_SCSI_TLV_CODE_MASK, ps3stor_scsi_req_t, reserved), 235 &scsireq.reserved, (uint16_t)sizeof(scsireq.reserved)); 236 scsireq_tlv = add_tlv_data(scsireq_tlv, PS3STOR_MK_TLV_CODE(PS3STOR_SCSI_TLV_CODE_MASK, ps3stor_scsi_req_t, cmddir), 237 &scsireq.cmddir, (uint16_t)sizeof(scsireq.cmddir)); 238 scsireq_tlv = add_tlv_data(scsireq_tlv, PS3STOR_MK_TLV_CODE(PS3STOR_SCSI_TLV_CODE_MASK, ps3stor_scsi_req_t, checklen), 239 &scsireq.checklen, (uint16_t)sizeof(scsireq.checklen)); 240 scsireq_tlv = add_tlv_data(scsireq_tlv, PS3STOR_MK_TLV_CODE(PS3STOR_SCSI_TLV_CODE_MASK, ps3stor_scsi_req_t, cdb), 241 &scsireq.cdb, (uint16_t)PS3STOR_SCSI_CDB_LEN); 242 scsireq_tlv = add_tlv_data(scsireq_tlv, PS3STOR_MK_TLV_CODE(PS3STOR_SCSI_TLV_CODE_MASK, ps3stor_scsi_req_t, req), 243 &scsireq.req, (uint16_t)sizeof(scsireq.req)); 244 if(scsireq_tlv == NULL) { 245 for(unsigned i = 0; i < scsicount; i++) { 246 free(scsiblks[i].pdata); 247 } 248 return -1; 249 } 250 251 // 3. call scsi passthrough 252 struct ps3stor_msg_info* reqinfo = NULL; 253 size_t insize = sizeof(struct ps3stor_msg_info) + scsireq_tlv->size; 254 reqinfo = (struct ps3stor_msg_info*)malloc(insize); 255 memset(reqinfo, 0, insize); 256 reqinfo->length = insize; 257 reqinfo->opcode = PS3STOR_CMD_PD_SCSI_PASSTHROUGH; 258 memcpy(&reqinfo->id, &scsireq.req.id, sizeof(struct ps3stor_id_group)); 259 memcpy(reqinfo->body, scsireq_tlv->buff, scsireq_tlv->size); 260 261 struct ps3stor_msg_info* rspinfo = NULL; 262 size_t outsize = sizeof(struct ps3stor_msg_info) + sizeof( struct ps3stor_scsi_rsp); 263 rspinfo = (struct ps3stor_msg_info*)malloc(outsize); 264 memset(rspinfo, 0, outsize); 265 266 if(PS3STOR_ERRNO_SUCCESS != firecmd_scsi(hostid, reqinfo, rspinfo, outsize, scsiblks, scsicount)) { 267 for(unsigned i = 0; i < scsicount; i++) { 268 free(scsiblks[i].pdata); 269 } 270 free(reqinfo); 271 free(rspinfo); 272 free(scsireq_tlv); 273 return -1; 274 } 275 276 // 4. copy and free memory 277 memcpy(&scsirsp, rspinfo->body, sizeof(scsirsp)); 278 for(unsigned i = 0; i < scsicount; i++) { 279 unsigned size = PS3STOR_SGL_SIZE; 280 if(i == scsicount - 1) { 281 size = scsilen - i * PS3STOR_SGL_SIZE; 282 } 283 memcpy(scsidata + i * PS3STOR_SGL_SIZE, scsiblks[i].pdata, size); 284 free(scsiblks[i].pdata); 285 } 286 free(scsireq_tlv); 287 free(reqinfo); 288 free(rspinfo); 289 return 0; 290 } -
ps3stor.h
1 /* 2 * ps3stor.h 3 * 4 * Home page of code is: http://www.smartmontools.org 5 * 6 * Copyright (C) 2024 Hong Xu 7 * 8 * SPDX-License-Identifier: GPL-2.0-or-later 9 */ 10 11 #ifndef __PS3STOR_H__ 12 #define __PS3STOR_H__ 13 14 #include "utility.h" 15 16 #include <stdint.h> 17 #include <string> 18 #include <vector> 19 #include <stddef.h> 20 21 typedef uint8_t encl_id_t; 22 typedef uint16_t slot_id_t; 23 typedef int32_t ps3stor_errno; 24 25 #define PS3STOR_ERRNO_SUCCESS (0) 26 27 #define PS3STOR_ID_LIST_MAX_COUNT (128) 28 #define PS3STOR_SCSI_STATUS_UNDERRUN (140) 29 #define PS3STOR_MSG_MAGIC_CODE (0x12345678) 30 #define PS3STOR_SGL_SIZE (4 * 1024) 31 #define PS3STOR_ITR_VER (0x2000000) 32 #define PS3STOR_SMARTCTL_SERVICE (0) 33 #define PS3STOR_SCSI_CDB_LEN (32) 34 #define PS3STOR_SCSI_MAX_CDB_LENGTH (32) 35 #define PS3STOR_SCSI_SENSE_BUFFER_LEN (96) 36 #define PS3STOR_SCSI_MAX_BLK_CNT (14) 37 #define PS3STOR_SCSI_ALIGN_SIZE (512) 38 #define PS3STOR_SCSI_BYTE_PER_CMD (4 * 1024) 39 #define PS3STOR_SCSI_SGE_INDEX_BASE (2) 40 41 #define PS3STOR_DRIVE_DEVICE_ID "/proc/devices" 42 #define PS3STOR_SYS_CLASS_SCSI_HOST_PATH "/sys/class/scsi_host/" 43 #define PS3STOR_SYS_BUS_PCI_DEVICE "/sys/bus/pci/devices" 44 45 #define PS3STOR_CMD_ENCL_GET_COUNT (0x3040101) 46 #define PS3STOR_CMD_ENCL_GET_LIST (0x3040102) 47 #define PS3STOR_CMD_PD_GET_COUNT_IN_ENCL (0x3050101) 48 #define PS3STOR_CMD_PD_GET_DEV_LIST_IN_ENCL (0x3050115) 49 #define PS3STOR_CMD_PD_SCSI_PASSTHROUGH (0x23051c01) 50 #define PS3STOR_CMD_PD_BASE_INFO (0x3050104) 51 52 #define PS3STOR_SCSI_TLV_CODE_MASK (0x41c01000) 53 #define PS3STOR_BATCH_TLV_CODE_MASK (0x6000) 54 55 #define PS3STOR_MIN(x,y) ((x) < (y) ? (x) : (y)) 56 #define PS3STOR_MK_TLV_CODE(code, struct_name, struct_member) \ 57 ((uint32_t) (code | offsetof(struct_name, struct_member))) 58 59 #define PS3STOR_ID_GROUP_TYPE_UNKNOWN (0) 60 #define PS3STOR_ID_GROUP_TYPE_DEVICE_ID (1) 61 #define PS3STOR_ID_GROUP_TYPE_PD_POSITION (2) 62 #define PS3STOR_SCSI_CMD_DIR_FROM_HOST (1) 63 #define PS3STOR_SCSI_CMD_DIR_TO_HOST (2) 64 #define PS3STOR_SCSI_CMD_DIR_NONE (0) 65 66 #define PS3STOR_INVALID_U64 (0xFFFFFFFFFFFFFFFF) 67 #define PS3STOR_INVALID_U32 (0xFFFFFFFF) 68 #define PS3STOR_INVALID_U16 (0xFFFF) 69 #define PS3STOR_INVALID_U8 (0xFF) 70 71 #define PS3STOR_INVALID_ENCL_ID (PS3STOR_INVALID_U8) 72 #define PS3STOR_INVALID_SLOT_ID (PS3STOR_INVALID_U16) 73 74 75 struct ps3stor_pd_position { 76 uint8_t enclid; 77 uint8_t pad; 78 uint16_t slotid; 79 }; 80 81 struct ps3stor_id_group { 82 uint8_t type; 83 uint8_t pad[7]; 84 union{ 85 uint16_t deviceid; 86 struct ps3stor_pd_position pd_position; 87 uint64_t reserved; // align as 8 bytes 88 uint8_t value[24]; // max for 24 bytes 89 }; 90 }; 91 92 struct ps3stor_tlv { 93 int32_t size; 94 uint8_t buff[0]; 95 }; 96 97 struct ps3stor_encl_list 98 { 99 uint8_t count; 100 uint8_t idlist[0]; 101 }; 102 103 struct ps3stor_msg_info { 104 uint32_t magic; 105 uint32_t opcode; 106 uint32_t error; 107 uint32_t timeout; 108 uint32_t start_time; 109 uint32_t runver; 110 uint32_t length; 111 uint32_t ack_offset; 112 uint32_t ack_length; 113 uint32_t leftmsg_count; 114 uint32_t msg_index; 115 uint8_t reserved[4]; 116 uint64_t uuid; 117 uint8_t service; 118 struct { 119 uint8_t ack : 4; 120 uint8_t tlv : 4; 121 } index; 122 uint8_t funcid : 1; 123 uint8_t pad : 7; 124 uint8_t reserved2[5]; 125 struct ps3stor_id_group id; 126 uint64_t traceid; 127 uint8_t body[0]; 128 }; 129 130 #define PS3STOR_MSG_INFO_SIZE (sizeof(struct ps3stor_msg_info)) 131 132 struct ps3stor_sge { 133 uint64_t addr; 134 uint32_t length; 135 uint32_t reserved1 : 30; 136 uint32_t last_sge : 1; 137 uint32_t ext : 1; 138 }; 139 140 struct ps3stor_ioctl_sync_cmd { 141 uint16_t hostid; 142 uint16_t sgl_offset; 143 uint16_t sge_count; 144 uint16_t reserved1; 145 uint32_t result_code; 146 uint8_t reserved2[100]; 147 uint64_t traceid; 148 uint8_t reserved3[120]; 149 uint8_t reserved4[128]; 150 struct ps3stor_sge sgl[16]; 151 }; 152 153 #define PS3STOR_CMD_IOCTL_SYNC_CMD _IOWR('M', 1, struct ps3stor_ioctl_sync_cmd) 154 155 typedef struct { 156 uint32_t count; 157 uint8_t pad[4]; 158 int64_t values[PS3STOR_ID_LIST_MAX_COUNT]; 159 } ps3stor_id_list; 160 161 struct ps3stor_pci_info { 162 uint32_t domainid; 163 uint8_t busid; 164 uint8_t deviceid; 165 uint8_t function; 166 uint8_t devtype; 167 char pci_addr[32]; 168 }; 169 170 struct ps3stor_data { 171 void* pdata; 172 uint32_t size; 173 }; 174 175 struct ps3stor_scsi_info 176 { 177 uint32_t datalen; 178 uint32_t sgecount; 179 uint32_t sgeindex; 180 uint8_t pad[4]; 181 struct ps3stor_id_group id; 182 }; 183 184 typedef struct ps3stor_scsi_req { 185 uint32_t reserved; 186 uint8_t cmddir; 187 uint8_t checklen; 188 uint8_t pad[2]; 189 uint8_t cdb[PS3STOR_SCSI_CDB_LEN]; 190 struct ps3stor_scsi_info req; 191 } ps3stor_scsi_req_t; 192 193 struct ps3stor_scsi_rsp_entry { 194 uint8_t sensebuf[PS3STOR_SCSI_SENSE_BUFFER_LEN]; 195 uint8_t status; 196 uint8_t pad1[3]; 197 uint32_t xfercnt; 198 uint8_t pad2[4]; 199 uint32_t result; 200 }; 201 202 struct ps3stor_scsi_rsp { 203 uint32_t reserved; 204 struct ps3stor_scsi_rsp_entry entry; 205 }; 206 207 typedef struct ps3stor_pd_baseinfo{ 208 uint16_t deviceid; 209 uint8_t reserved1[2]; 210 uint8_t enclid; 211 uint8_t reserved2; 212 uint16_t slotid; 213 uint64_t reserved[22]; 214 } ps3stor_pd_baseinfo_t; 215 216 typedef struct ps3stor_batch_req{ 217 uint32_t idcount; 218 uint32_t datasize; 219 struct ps3stor_id_group idgroup[0]; 220 } ps3stor_batch_req_t; 221 222 typedef struct ps3stor_rsp_entry { 223 int32_t result; 224 uint32_t size; 225 uint8_t data[0]; 226 } ps3stor_rsp_entry_t; 227 228 typedef struct ps3stor_batch_rsp { 229 uint32_t count; 230 uint8_t rsp_entry[0]; // ps3stor_rsp_entry_t 231 } ps3stor_batch_rsp_t; 232 233 234 bool ps3stor_init(); 235 ///////////////////////////////////////////////////////////////////////////// 236 // ps3stor_channel 237 238 /// The platform ps3stor channel abstraction 239 class ps3stor_channel 240 { 241 public: 242 /// Initialize platform channel and register with ps3chn(). 243 /// Must be implemented by platform module and register channel with set() 244 static void init(); 245 246 ps3stor_channel() 247 { m_init = false; } 248 249 virtual ~ps3stor_channel() 250 { } 251 252 /// Error (number,message) pair 253 struct error_info { 254 explicit error_info(int n = 0) 255 : no(n) { } 256 error_info(int n, const char * m) 257 : no(n), msg(m) { } 258 void clear() 259 { no = 0; msg.erase(); } 260 261 int no; ///< Error number 262 std::string msg; ///< Error message 263 }; 264 protected: 265 /// Set channel to use, must be called from init(). 266 static void set(ps3stor_channel * channel) 267 { s_channel = channel; } 268 269 public: 270 virtual ps3stor_errno channel_init() = 0; 271 272 virtual ps3stor_errno get_host_list(std::vector<unsigned> &hostlist) = 0; 273 274 ps3stor_errno get_enclcount(unsigned hostid, uint8_t &enclcount); 275 276 ps3stor_errno get_encllist(unsigned hostid, struct ps3stor_encl_list* &encllist, size_t listsize); 277 278 ps3stor_errno pd_get_devcount_by_encl(unsigned hostid, uint8_t enclid, uint16_t &devcount); 279 280 ps3stor_errno pd_get_devlist_by_encl(unsigned hostid, uint8_t enclid, uint16_t* &devlist, size_t listsize); 281 282 ps3stor_errno pd_get_baseinfo_by_devid(unsigned hostid, unsigned devid, ps3stor_pd_baseinfo_t &basinfo); 283 284 ps3stor_errno pd_scsi_passthrough(unsigned hostid, uint8_t eid, uint16_t sid, 285 ps3stor_scsi_req_t &scsireq, ps3stor_scsi_rsp &scsirsp, 286 uint8_t * &scsidata, const size_t scsilen); 287 288 protected: 289 virtual ps3stor_errno firecmd(unsigned hostid, struct ps3stor_msg_info *info, struct ps3stor_msg_info * ackinfo, unsigned acksize) = 0; 290 291 virtual ps3stor_errno firecmd_scsi(unsigned hostid, struct ps3stor_msg_info * reqinfo, struct ps3stor_msg_info * ackinfo, 292 unsigned acksize, struct ps3stor_data * scsidata, unsigned scsicount) = 0; 293 294 virtual struct ps3stor_tlv *add_tlv_data(struct ps3stor_tlv *tlv, unsigned type, const void *data, uint16_t size) = 0; 295 /////////////////////////////////////////////// 296 // Last error information 297 /// Set last error number and message. 298 /// Returns false always to allow use as a return expression. 299 virtual bool set_err(int no, const char * msg) = 0; 300 301 /// Set last error number and default message. 302 /// Message is retrieved from interface's get_msg_for_errno(no). 303 virtual bool set_err(int no) = 0; 304 305 bool m_init; 306 307 private: 308 309 friend ps3stor_channel * ps3chn(); // below 310 static ps3stor_channel * s_channel; ///< Pointer to the channel object. 311 312 // Prevent copy/assignment 313 ps3stor_channel(const ps3stor_channel &); 314 void operator=(const ps3stor_channel &); 315 316 }; 317 318 /// Global access to the (usually singleton) ps3stor_channel 319 inline ps3stor_channel * ps3chn() 320 { return ps3stor_channel::s_channel; } 321 322 #endif 323 No newline at end of file -
smartctl.8.in
778 778 \- the device consists of multiple SATA disks connected to a JMicron JMS56x 779 779 USB to SATA RAID bridge. 780 780 See \*(Aqjmb39x...\*(Aq above for valid arguments. 781 .Sp 782 .I ps3stor,n 783 \- [Linux only] 784 the device consists of one or more SCSI/SAS or SATA disks connected to a 785 PS3StorRAID controller. 786 The non-negative integer N (in the range of 0 to 127 inclusive) denotes the enclosure 787 and S (range 0 to 128) denotes the slot. 788 Use syntax such as: 789 .br 790 \fBsmartctl \-a \-d ps3stor,1 /dev/bus/0 791 .br 792 It is possible to set RAID device name as /dev/bus/N, where N is a 793 SCSI bus number. 794 .Sp 795 .\" %ENDIF OS Linux 781 796 .TP 782 797 .B \-T TYPE, \-\-tolerance=TYPE 783 798 [ATA only] Specifies how tolerant \fBsmartctl\fP should be of ATA and SMART