diff --git a/smartmontools/ChangeLog b/smartmontools/ChangeLog
index 1f457d63a70c7b189f8c5bb41b2abbfc1d5c5a85..dca8fab47c993c2d6e2aab8f5cc99c46e9101445 100644
--- a/smartmontools/ChangeLog
+++ b/smartmontools/ChangeLog
@@ -1,5 +1,15 @@
 $Id$
 
+2022-03-28  Douglas Gilbert  <dgilbert@interlog.com>
+
+	os_linux.cpp [Linux only]: remove support from generic part
+	for the SCSI_IOCTL_SEND_COMMAND ioctl. Default to the SG_IO_V3
+	interface which is now (lk 5.17, 2022) much more widely
+	supported. The SCSI_IOCTL_SEND_COMMAND ioctl is still in
+	the Linux kernel but has been deprecated for a long time.
+	Some old vendor specific code still uses that ioctl, two
+	instances: m_escalade_type==AMCC_3WARE_678K and -d marvell
+
 2022-03-04  Christian Franke  <franke@computer.org>
 
 	configure.ac: Add "pre-" also on man pages.
diff --git a/smartmontools/os_linux.cpp b/smartmontools/os_linux.cpp
index 7740ef5b4f5642a335d582059935ba9d3d9fb57a..4797a5de6086609eeee912bae9994744f06265d2 100644
--- a/smartmontools/os_linux.cpp
+++ b/smartmontools/os_linux.cpp
@@ -477,10 +477,13 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
  * mapping disk devices (e.g. /dev/sda) to the corresponding sg device
  * (e.g. /dev/sg2). In the linux kernel 2.6 series most of the facilities of
  * the sg driver have become available via the SG_IO ioctl which is available
- * on all SCSI devices (on SCSI tape devices from lk 2.6.6).
- * So the strategy below is to find out if the SG_IO ioctl is available and
- * if so use it; failing that use the older SCSI_IOCTL_SEND_COMMAND ioctl.
- * Should work in 2.0, 2.2, 2.4 and 2.6 series linux kernels. */
+ * on all SCSI devices (on SCSI tape devices from lk 2.6.6). Now in lk 5.17
+ * the SCSI_IOCTL_SEND_COMMAND ioctl is still present but deprecated sending
+ * a warning to the log the first time (after power up) it is used. The SG_IO
+ * Version 3 interface is the most widely used (circa lk 5.17 in 2022) and is
+ * available on the primary block devive name (e.g. /dev/sdc) for all SCSI
+ * disks (and tapes) including all USB attached storage and all ATA/SATA
+ * storage. */
 
 #define MAX_DXFER_LEN 1024      /* can be increased if necessary */
 #define SEND_IOCTL_RESP_SENSE_LEN 16    /* ioctl limitation */
@@ -493,33 +496,24 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
 #define LSCSI_DID_BUS_BUSY  0x2
 #define LSCSI_DID_NO_CONNECT  0x1
 
-#ifndef SCSI_IOCTL_SEND_COMMAND
-#define SCSI_IOCTL_SEND_COMMAND 1
-#endif
 
-#define SG_IO_USE_DETECT 0
-#define SG_IO_UNSUPP 1
-#define SG_IO_USE_V3 3
-#define SG_IO_USE_V4 4
+enum lk_sg_io_ifc_t {
+    SG_IO_USE_DETECT = 0,
+    SG_IO_UNSUPP = 1,
+    SG_IO_USE_V3 = 3,
+    SG_IO_USE_V4 = 4,
+};
 
-static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
-                         int sgio_ver);
-static int sisc_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report);
+static enum lk_sg_io_ifc_t sg_io_interface = SG_IO_USE_DETECT;
 
-static int sg_io_state = SG_IO_USE_DETECT;
 
 /* Preferred implementation for issuing SCSI commands in linux. This
  * function uses the SG_IO ioctl. Return 0 if command issued successfully
  * (various status values should still be checked). If the SCSI command
  * cannot be issued then a negative errno value is returned. */
 static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
-                         int sg_io_ver)
+                         enum lk_sg_io_ifc_t sg_io_ifc)
 {
-#ifndef SG_IO
-    ARGUSED(dev_fd); ARGUSED(iop); ARGUSED(report);
-    return -ENOTTY;
-#else
-
     /* we are filling structures for both versions, but using only one requested */
     struct sg_io_hdr io_hdr_v3;
     struct sg_io_v4  io_hdr_v4;
@@ -547,7 +541,7 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
         char buff[256];
         const int sz = (int)sizeof(buff);
 
-        pout(">>>> do_scsi_cmnd_io: sg_io_ver=%d\n", sg_io_ver);
+        pout(">>>> do_scsi_cmnd_io: sg_io_ifc=%d\n", (int)sg_io_ifc);
         np = scsi_get_opcode_name(ucp[0]);
         j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
         for (k = 0; k < (int)iop->cmnd_len; ++k)
@@ -611,7 +605,7 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
 
     void * io_hdr = NULL;
 
-    switch (sg_io_ver) {
+    switch (sg_io_ifc) {
       case SG_IO_USE_V3:
           io_hdr = &io_hdr_v3;
           break;
@@ -627,14 +621,14 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
     if (ioctl(dev_fd, SG_IO, io_hdr) < 0) {
         if (report)
             pout("  SG_IO ioctl failed, errno=%d [%s], SG_IO_V%d\n", errno,
-                 strerror(errno), sg_io_ver);
+                 strerror(errno), (int)sg_io_ifc);
         return -errno;
     }
 
     unsigned int sg_driver_status = 0,  sg_transport_status = 0, sg_info = 0,
         sg_duration = 0;
 
-    if (sg_io_ver == SG_IO_USE_V3) {
+    if (sg_io_ifc == SG_IO_USE_V3) {
         iop->resid =            io_hdr_v3.resid;
         iop->scsi_status =      io_hdr_v3.status;
         sg_driver_status =      io_hdr_v3.driver_status;
@@ -644,7 +638,7 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
         sg_duration =           io_hdr_v3.duration;
     }
 
-    if (sg_io_ver == SG_IO_USE_V4) {
+    if (sg_io_ifc == SG_IO_USE_V4) {
        switch (iop->dxfer_dir) {
            case DXFER_NONE:
                iop->resid = 0;
@@ -732,128 +726,6 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
         }
     }
     return 0;
-#endif
-}
-
-struct linux_ioctl_send_command
-{
-    int inbufsize;
-    int outbufsize;
-    uint8_t buff[MAX_DXFER_LEN + 16];
-};
-
-/* The Linux SCSI_IOCTL_SEND_COMMAND ioctl is primitive and it doesn't
- * support: CDB length (guesses it from opcode), resid and timeout.
- * Patches in Linux 2.4.21 and 2.5.70 to extend SEND DIAGNOSTIC timeout
- * to 2 hours in order to allow long foreground extended self tests. */
-static int sisc_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report)
-{
-    struct linux_ioctl_send_command wrk;
-    int status, buff_offset;
-    size_t len;
-
-    memcpy(wrk.buff, iop->cmnd, iop->cmnd_len);
-    buff_offset = iop->cmnd_len;
-    if (report > 0) {
-        int k, j;
-        const unsigned char * ucp = iop->cmnd;
-        const char * np;
-        char buff[256];
-        const int sz = (int)sizeof(buff);
-
-        np = scsi_get_opcode_name(ucp[0]);
-        j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>");
-        for (k = 0; k < (int)iop->cmnd_len; ++k)
-            j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]);
-        if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir)) {
-            int trunc = (iop->dxfer_len > 256) ? 1 : 0;
-
-            snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n  Outgoing "
-                     "data, len=%d%s:\n", (int)iop->dxfer_len,
-                     (trunc ? " [only first 256 bytes shown]" : ""));
-            dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
-        }
-        else
-            snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n");
-        pout("%s", buff);
-    }
-    switch (iop->dxfer_dir) {
-        case DXFER_NONE:
-            wrk.inbufsize = 0;
-            wrk.outbufsize = 0;
-            break;
-        case DXFER_FROM_DEVICE:
-            wrk.inbufsize = 0;
-            if (iop->dxfer_len > MAX_DXFER_LEN)
-                return -EINVAL;
-            wrk.outbufsize = iop->dxfer_len;
-            break;
-        case DXFER_TO_DEVICE:
-            if (iop->dxfer_len > MAX_DXFER_LEN)
-                return -EINVAL;
-            memcpy(wrk.buff + buff_offset, iop->dxferp, iop->dxfer_len);
-            wrk.inbufsize = iop->dxfer_len;
-            wrk.outbufsize = 0;
-            break;
-        default:
-            pout("do_scsi_cmnd_io: bad dxfer_dir\n");
-            return -EINVAL;
-    }
-    iop->resp_sense_len = 0;
-    iop->scsi_status = 0;
-    iop->resid = 0;
-    status = ioctl(dev_fd, SCSI_IOCTL_SEND_COMMAND, &wrk);
-    if (-1 == status) {
-        if (report)
-            pout("  SCSI_IOCTL_SEND_COMMAND ioctl failed, errno=%d [%s]\n",
-                 errno, strerror(errno));
-        return -errno;
-    }
-    if (0 == status) {
-        if (report > 0)
-            pout("  status=0\n");
-        if (DXFER_FROM_DEVICE == iop->dxfer_dir) {
-            memcpy(iop->dxferp, wrk.buff, iop->dxfer_len);
-            if (report > 1) {
-                int trunc = (iop->dxfer_len > 256) ? 1 : 0;
-
-                pout("  Incoming data, len=%d%s:\n", (int)iop->dxfer_len,
-                     (trunc ? " [only first 256 bytes shown]" : ""));
-                dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1);
-            }
-        }
-        return 0;
-    }
-    iop->scsi_status = status & 0x7e; /* bits 0 and 7 used to be for vendors */
-    if (LSCSI_DRIVER_SENSE == ((status >> 24) & 0xf))
-        iop->scsi_status = SCSI_STATUS_CHECK_CONDITION;
-    len = (SEND_IOCTL_RESP_SENSE_LEN < iop->max_sense_len) ?
-                SEND_IOCTL_RESP_SENSE_LEN : iop->max_sense_len;
-    if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) &&
-        iop->sensep && (len > 0)) {
-        memcpy(iop->sensep, wrk.buff, len);
-        iop->resp_sense_len = len;
-        if (report > 1) {
-            pout("  >>> Sense buffer, len=%d:\n", (int)len);
-            dStrHex(wrk.buff, len , 1);
-        }
-    }
-    if (report) {
-        if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) {
-            pout("  status=%x: sense_key=%x asc=%x ascq=%x\n", status & 0xff,
-                 wrk.buff[2] & 0xf, wrk.buff[12], wrk.buff[13]);
-        }
-        else
-            pout("  status=0x%x\n", status);
-    }
-    if (iop->scsi_status > 0)
-        return 0;
-    else {
-        if (report > 0)
-            pout("  ioctl status=0x%x but scsi status=0, fail with EIO\n",
-                 status);
-        return -EIO;      /* give up, assume no device there */
-    }
 }
 
 /* SCSI command transmission interface function, linux version.
@@ -868,39 +740,42 @@ static int do_normal_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop,
 {
     int res;
 
-    /* implementation relies on static sg_io_state variable. If not
+    /* implementation relies on static sg_io_interface variable. If not
      * previously set tries the SG_IO ioctl. If that succeeds assume
      * that SG_IO ioctl functional. If it fails with an errno value
-     * other than ENODEV (no device) or permission then assume
-     * SCSI_IOCTL_SEND_COMMAND is the only option. */
-    switch (sg_io_state) {
+     * other than ENODEV (no device) or a permissions problem then
+     * assume the SG_IO_USE_V3 interface. */
+    switch (sg_io_interface) {
     case SG_IO_USE_DETECT:
         /* ignore report argument */
         /* Try SG_IO V3 first */
         if (0 == (res = sg_io_cmnd_io(dev_fd, iop, report, SG_IO_USE_V3))) {
-            sg_io_state = SG_IO_USE_V3;
+            sg_io_interface = SG_IO_USE_V3;
             return 0;
         } else if ((-ENODEV == res) || (-EACCES == res) || (-EPERM == res))
             return res;         /* wait until we see a device */
         /* See if we can use SG_IO V4 * */
         if (0 == (res = sg_io_cmnd_io(dev_fd, iop, report, SG_IO_USE_V4))) {
-            sg_io_state = SG_IO_USE_V4;
+            sg_io_interface = SG_IO_USE_V4;
             return 0;
         } else if ((-ENODEV == res) || (-EACCES == res) || (-EPERM == res))
             return res;         /* wait until we see a device */
-        /* fallback to the SCSI_IOCTL_SEND_COMMAND */
-        sg_io_state = SG_IO_UNSUPP;
+        sg_io_interface = SG_IO_UNSUPP;
         /* FALLTHRU */
     case SG_IO_UNSUPP:
-        /* deprecated SCSI_IOCTL_SEND_COMMAND ioctl */
-        return sisc_cmnd_io(dev_fd, iop, report);
+        /* previously called SCSI_IOCTL_SEND_COMMAND ioctl which has now
+	 * been removed. The SG_IO_USE_V3 is most widely used now in Linux
+	 * (circa 2022), try it again. */
+        sg_io_interface = SG_IO_USE_V3;
+        /* FALLTHRU */
     case SG_IO_USE_V3:
     case SG_IO_USE_V4:
         /* use SG_IO V3 or V4 ioctl, depending on availabiliy */
-        return sg_io_cmnd_io(dev_fd, iop, report, sg_io_state);
+        return sg_io_cmnd_io(dev_fd, iop, report, sg_io_interface);
     default:
-        pout(">>>> do_scsi_cmnd_io: bad sg_io_state=%d\n", sg_io_state);
-        sg_io_state = SG_IO_USE_DETECT;
+        pout(">>>> do_scsi_cmnd_io: bad sg_io_interface=%d\n",
+	     (int)sg_io_interface);
+        sg_io_interface = SG_IO_USE_DETECT;
         return -EIO;    /* report error and reset state */
     }
 }
@@ -1743,6 +1618,10 @@ bool linux_escalade_device::open()
 // TODO: Function no longer useful
 //void printwarning(smart_command_set command);
 
+#ifndef SCSI_IOCTL_SEND_COMMAND
+#define SCSI_IOCTL_SEND_COMMAND 1
+#endif
+
 // PURPOSE
 //   This is an interface routine meant to isolate the OS dependent
 //   parts of the code, and to provide a debugging interface.  Each