Project

General

Profile

Actions

Bug #16084

open

USB devices without ID strings are invisible to cfgadm

Added by Joshua M. Clulow 3 months ago. Updated 3 months ago.

Status:
New
Priority:
Normal
Category:
cmd - userland programs
Start date:
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
Gerrit CR:
External Bug:

Description

Adafruit manufacture an FTDI FT232H breakout board that is customisable and allows for various serial, I2C, and GPIO devices to be attached to a machine. For whatever reason, the devices generally ship with somewhat invalid contents in the configuration flash on the device. Of particular note to us here: the device will come up with no Manufacturer, Product, or Serial string. To fix this, one can use the ftdi_eeprom tool to write new flash contents, including a unique serial number and correct ID strings. Once written, the device needs to be reset; e.g., via:

# cfgadm -y -v -x usb_reset usb2/1.2.7.2

This causes the USB stack to act as if the device was hot plugged. The new flash contents takes effect and the updated serial, etc, takes effect.

I was trying to perform this sequence, but after writing the new flash contents I realised that the attachment point for the USB device in question was curiously absent from cfgadm output. You can see that a driver is attached to it:

$ ls -la /dev/term/8
lrwxrwxrwx   1 root     root          74 Nov 27 19:28 /dev/term/8 -> ../../devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7/device@2/serdev@0:0

Based on the devices path we would expect .../hub@1/hub@2/hub@7/device@2/... to become an attachment point like usbN/1.2.7.2, but we don't see it:

$ pcfgadm usb
Ap_Id              Type         Receptacle   Occupant     Condition
usb1/1             unknown      empty        unconfigured ok
usb1/2             unknown      empty        unconfigured ok
usb1/3             unknown      empty        unconfigured ok
usb1/4             unknown      empty        unconfigured ok
usb1/5             unknown      empty        unconfigured ok
usb1/6             unknown      empty        unconfigured ok
usb1/7             unknown      empty        unconfigured ok
usb1/8             unknown      empty        unconfigured ok
usb2/1             usb-hub      connected    configured   ok
usb2/1.1           usb-device   connected    configured   ok
usb2/1.2           usb-hub      connected    configured   ok
usb2/1.2.1         usb-device   connected    configured   ok
usb2/1.2.2         usb-device   connected    configured   ok
usb2/1.2.3         usb-miscell  connected    configured   ok
usb2/1.2.4         usb-device   connected    configured   ok
usb2/1.2.5         usb-miscell  connected    configured   ok
usb2/1.2.6         usb-miscell  connected    configured   ok
usb2/1.2.7         usb-hub      connected    configured   ok
usb2/1.2.7.1       unknown      empty        unconfigured ok
      <---------------------------------- it should be here!
usb2/1.2.7.3       unknown      empty        unconfigured ok
usb2/1.2.7.4       unknown      empty        unconfigured ok
usb2/1.2.7.5       usb-miscell  connected    configured   ok
usb2/1.2.7.6       unknown      empty        unconfigured ok
usb2/1.2.7.7       unknown      empty        unconfigured ok
usb2/1.3           unknown      empty        unconfigured ok
usb2/1.4           unknown      empty        unconfigured ok
usb2/1.5           unknown      empty        unconfigured ok
usb2/1.6           unknown      empty        unconfigured ok
usb2/2             unknown      empty        unconfigured ok
usb2/3             unknown      empty        unconfigured ok
usb3/1             usb-hub      connected    configured   ok
usb3/1.1           unknown      empty        unconfigured ok
usb3/1.2           unknown      empty        unconfigured ok
usb3/1.3           unknown      empty        unconfigured ok
usb3/1.4           unknown      empty        unconfigured ok
usb3/1.5           unknown      empty        unconfigured ok
usb3/1.6           unknown      empty        unconfigured ok
usb3/1.7           unknown      empty        unconfigured ok
usb3/1.8           unknown      empty        unconfigured ok
usb3/2             unknown      empty        unconfigured ok
usb3/3             unknown      empty        unconfigured ok

Without the AP being visible to cfgadm it does not seem possible to reset the device!


Files

watch.d (3.91 KB) watch.d Joshua M. Clulow, 2023-11-27 11:19 PM
Actions #1

Updated by Joshua M. Clulow 3 months ago

I asked truss to show me what cfgadm was doing:

$ truss -o /tmp/wtf -t open,ioctl,stat cfgadm usb
...

Indeed, there was one attachment point with which we were having trouble:

$ less /tmp/wtf
...
stat("/devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2", 0x080419A4) = 0
open("/devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2", O_RDONLY) = 3
ioctl(3, 0xDC0014, 0x08041E30)                  = 0
open("/etc/dev/.devlink_db", O_RDONLY)          = 3
open("/devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2", O_RDONLY) = 3
ioctl(3, 0xDC0015, 0x08041E14)                  = 0
ioctl(3, 0xDC0015, 0x08041E14)                  = 0
open("/devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2", O_RDONLY) = 3
ioctl(3, 0xDC0015, 0x08041E14)                  = 0
ioctl(3, 0xDC0015, 0x08041E14)                  Err#22 EINVAL
...

Looking at the device in the kernel, we can see that it does indeed not have the strings we are after:

> 0xfffffe0bc5772040::usba_device -p
NAME    INST DIP              PATH
usbftdi  9   fffffe0bac31c050 /pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7/device@2

    EP  TYPE  DIR STATE   P_HANDLE         P_POLICY         EP DESCR
      0 Cntrl Out IDLE    fffffe0feabcab78 fffffe0feabcabb0 fffffe0feabcabb2
      2 Bulk  Out IDLE    fffffe0feabcd550 fffffe0feabcd588 fffffe0feabcd58a
      1 Bulk  In  IDLE    fffffe0feabca8d8 fffffe0feabca910 fffffe0feabca912

> 0xfffffe0bc5772040::print usba_device_t usb_dev_descr[]
usb_dev_descr = {
    usb_dev_descr->bLength = 0x12
    usb_dev_descr->bDescriptorType = 0x1
    usb_dev_descr->bcdUSB = 0x200
    usb_dev_descr->bDeviceClass = 0
    usb_dev_descr->bDeviceSubClass = 0
    usb_dev_descr->bDeviceProtocol = 0
    usb_dev_descr->bMaxPacketSize0 = 0x40
    usb_dev_descr->idVendor = 0x403
    usb_dev_descr->idProduct = 0x6014
    usb_dev_descr->bcdDevice = 0x900
    usb_dev_descr->iManufacturer = 0x1
    usb_dev_descr->iProduct = 0x2
    usb_dev_descr->iSerialNumber = 0x3
    usb_dev_descr->bNumConfigurations = 0x1
}

> 0xfffffe0bc5772040::print usba_device_t usb_mfg_str usb_product_str usb_serialno_str
usb_mfg_str = 0
usb_product_str = 1
usb_serialno_str = 0

This implies usba_get_dev_string_descrs() was not able to load the strings from the device, which makes sense here given the state of the flash when the device was inserted.

I wrote a D script that emits information about the operations being performed by cfgadm (specifically, in the usb.so plugin) here:

#!/usr/sbin/dtrace -qCs

inline unsigned int DEVCTL_IOC = (0xDC << 16);
inline unsigned int DEVCTL_AP_GETSTATE = (DEVCTL_IOC | 20);
inline unsigned int DEVCTL_AP_CONTROL = (DEVCTL_IOC | 21);

inline string iocn[int r] =
    r == DEVCTL_AP_GETSTATE ? "DEVCTL_AP_GETSTATE" :
    r == DEVCTL_AP_CONTROL ? "DEVCTL_AP_CONTROL" :
    "?";

/*
 * Commands for DEVCTL_AP_CONTROL on USB devices.
 * See also "uts/common/sys/usb/hubd/hubd_impl.h", etc.
 */
#define HUBD_GET_CFGADM_NAME            0x10    /* get driver's name */
#define HUBD_GET_CURRENT_CONFIG         0x20    /* get current config index */
#define HUBD_GET_DEVICE_PATH            0x40    /* get /devices path */
#define HUBD_REFRESH_DEVDB              0x80    /* refresh USB device DB */
#define USB_DESCR_TYPE_DEV                      0x01
#define USB_DESCR_TYPE_STRING                   0x03
/*
 * With USB_DESCR_TYPE_STRING sub-command, these are the various
 * string sub-options.
 */
#define HUBD_MFG_STR            1               /* get manufacturer string */
#define HUBD_PRODUCT_STR        2               /* get product-id string */
#define HUBD_SERIALNO_STR       3               /* get serial-no-id string */
#define HUBD_CFG_DESCR_STR      4               /* get config descr string */

inline string cmdn[int r] =
    r == HUBD_GET_CFGADM_NAME ? "HUBD_GET_CFGADM_NAME" :
    r == HUBD_GET_CURRENT_CONFIG ? "HUBD_GET_CURRENT_CONFIG" :
    r == HUBD_GET_DEVICE_PATH ? "HUBD_GET_DEVICE_PATH" :
    r == HUBD_REFRESH_DEVDB ? "HUBD_REFRESH_DEVDB" :
    r == USB_DESCR_TYPE_DEV ? "USB_DESCR_TYPE_DEV" :
    r == USB_DESCR_TYPE_STRING ? "USB_DESCR_TYPE_STRING" :
    "?";

inline string miscn[int r] =
    r == HUBD_MFG_STR ? "HUBD_MFG_STR" :
    r == HUBD_PRODUCT_STR ? "HUBD_PRODUCT_STR" :
    r == HUBD_SERIALNO_STR ? "HUBD_SERIALNO_STR" :
    r == HUBD_CFG_DESCR_STR ? "HUBD_CFG_DESCR_STR" :
    "?";

inline string watch =
    "/devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2";

syscall::open:return
/pid == $target && (this->fd = (int)arg1) >= 0
  && fds[this->fd].fi_pathname == watch/
{
    printf("%4d -> %s\n", this->fd, fds[this->fd].fi_pathname);
    watching[this->fd] = 1;
}

syscall::ioctl:entry
/pid == $target && watching[(this->fd = (int)arg0)]/
{
    self->req = (int)arg1;

    printf("%4d ioctl(req %08X [%s])\n", this->fd, self->req,
        iocn[self->req]);

    self->sizep = (userland uint32_t *)NULL;
    if (self->req == DEVCTL_AP_CONTROL) {
        /*
         * We know in this case that the argument is a struct
         * hubd_ioctl_data because it is a USB device.
         */
        if (curpsinfo->pr_dmodel == PR_MODEL_ILP32) {
            this->d32 = (userland hubd_ioctl_data_32_t *)arg2;
            print(*this->d32);
            this->cmd = this->d32->cmd;
            this->misc = this->d32->misc_arg;
            this->getsize = this->d32->get_size;
            if (this->getsize && this->d32->bufsiz == 4) {
                self->sizep =
                    (userland uint32_t *)this->d32->buf;
            }
        } else {
            this->d64 = (userland hubd_ioctl_data_t *)arg2;
            print(*this->d64);
            this->cmd = this->d64->cmd;
            this->misc = this->d64->misc_arg;
            this->getsize = this->d64->get_size;
            if (this->getsize && this->d64->bufsiz == 4) {
                self->sizep =
                    (userland uint32_t *)this->d64->buf;
            }
        }
        ustack();

        printf("    command = %s\n", cmdn[this->cmd]);
        if (this->cmd == USB_DESCR_TYPE_STRING) {
            printf("    misc arg = %s\n", miscn[this->misc]);
        }
        if (this->getsize) {
            printf("    is a get size request!\n");
        }

        printf("\n");
    }
}

syscall::ioctl:return
/pid == $target && self->req/
{
    this->ret = (int)arg1;

    printf("%4d ioctl(req %08X [%s]) -> %d, 0x%X [errno %d]\n",
        this->fd, self->req, iocn[self->req],
        this->ret, this->ret, errno);

    if (this->ret == 0 && self->sizep != NULL) {
        printf("    returned size = %d (0x%x)\n",
            *self->sizep, *self->sizep);
        printf("\n");
    }

    self->req = 0;
    self->sizep = 0;
}

syscall::close:entry
/pid == $target && watching[(this->fd = (int)arg0)]/
{
    printf("%4d closed\n\n", this->fd);
    watching[this->fd] = 0;
}

Running the script, we can see the failure:

$ pfexec ppriv -s A+dtrace_kernel,dtrace_proc,dtrace_user $$
$ dtrace -qCs watch.d -c 'cfgadm usb'
   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0014 [DEVCTL_AP_GETSTATE])
   3 ioctl(req 00DC0014 [DEVCTL_AP_GETSTATE]) -> 0, 0x0 [errno 0]
   3 closed

   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x1
    uint32_t port = 0x2
    uint32_t get_size = 0x1
    caddr32_t buf = 0x80452c0
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x5f
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_DEV
    is a get size request!

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
    returned size = 18 (0x12)

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x1
    uint32_t port = 0x2
    uint32_t get_size = 0
    caddr32_t buf = 0x8fba050
    uint32_t bufsiz = 0x12
    uint32_t misc_arg = 0
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x5f
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_DEV

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
   3 closed

   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x3
    uint32_t port = 0x2
    uint32_t get_size = 0x1
    caddr32_t buf = 0x80452c0
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0x1
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x9a
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_STRING
    misc arg = HUBD_MFG_STR
    is a get size request!

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
    returned size = 0 (0x0)

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x3
    uint32_t port = 0x2
    uint32_t get_size = 0
    caddr32_t buf = 0x8fbc868
    uint32_t bufsiz = 0
    uint32_t misc_arg = 0x1
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x9a
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_STRING
    misc arg = HUBD_MFG_STR

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> -1, 0xFFFFFFFF [errno 22]
   3 closed

Ap_Id                          Type         Receptacle   Occupant     Condition
usb1/1                         unknown      empty        unconfigured ok
usb1/2                         unknown      empty        unconfigured ok
usb1/3                         unknown      empty        unconfigured ok
usb1/4                         unknown      empty        unconfigured ok
usb1/5                         unknown      empty        unconfigured ok
usb1/6                         unknown      empty        unconfigured ok
usb1/7                         unknown      empty        unconfigured ok
usb1/8                         unknown      empty        unconfigured ok
usb2/1                         usb-hub      connected    configured   ok
usb2/1.1                       usb-device   connected    configured   ok
usb2/1.2                       usb-hub      connected    configured   ok
usb2/1.2.1                     usb-device   connected    configured   ok
usb2/1.2.2                     usb-device   connected    configured   ok
usb2/1.2.3                     usb-miscell  connected    configured   ok
usb2/1.2.4                     usb-device   connected    configured   ok
usb2/1.2.5                     usb-miscell  connected    configured   ok
usb2/1.2.6                     usb-miscell  connected    configured   ok
usb2/1.2.7                     usb-hub      connected    configured   ok
usb2/1.2.7.1                   unknown      empty        unconfigured ok
usb2/1.2.7.3                   unknown      empty        unconfigured ok
usb2/1.2.7.4                   unknown      empty        unconfigured ok
usb2/1.2.7.5                   usb-miscell  connected    configured   ok
usb2/1.2.7.6                   unknown      empty        unconfigured ok
usb2/1.2.7.7                   unknown      empty        unconfigured ok
usb2/1.3                       unknown      empty        unconfigured ok
usb2/1.4                       unknown      empty        unconfigured ok
usb2/1.5                       unknown      empty        unconfigured ok
usb2/1.6                       unknown      empty        unconfigured ok
usb2/2                         unknown      empty        unconfigured ok
usb2/3                         unknown      empty        unconfigured ok
usb3/1                         usb-hub      connected    configured   ok
usb3/1.1                       unknown      empty        unconfigured ok
usb3/1.2                       unknown      empty        unconfigured ok
usb3/1.3                       unknown      empty        unconfigured ok
usb3/1.4                       unknown      empty        unconfigured ok
usb3/1.5                       unknown      empty        unconfigured ok
usb3/1.6                       unknown      empty        unconfigured ok
usb3/1.7                       unknown      empty        unconfigured ok
usb3/1.8                       unknown      empty        unconfigured ok
usb3/2                         unknown      empty        unconfigured ok
usb3/3                         unknown      empty        unconfigured ok

Of particular note: we use USB_DESCR_TYPE_STRING with the HUBD_MFG_STR string to get the size of the buffer we'll need. The kernel tells us the buffer is size zero, so we allocate such a buffer (ahem) and go back for the string. Unfortunately the code in the kernel then kicks us back out with EINVAL. Were we running DEBUG bits, we would be able to see a "String is NULL" message at USB debugging level 3.

It seems there actually is some logic to handle a zero-length string in do_control_ioctl() (in lib/cfgadm_plugins/usb/common/cfga_usb.c) but it only applies for HUBD_CFG_DESCR_STR and not the other string types. In other cases we just fail out of enumerating the particular attachment point altogether, which is unfortunate because it is definitely there.

I decided to patch the kernel a little to confirm this. The offset of usb_mfg_str in usba_device_t is 0x778 on this machine:

> ::print -ta usba_device_t ! grep usb_mfg_str
    778 char *usb_mfg_str

Starting at the place in usba_hubdi_ioctl() where we use that offset:

usba_hubdi_ioctl+0xc9a:         movq   0x778(%rbx),%rbx
usba_hubdi_ioctl+0xca1:         jmp    -0x47e   <usba_hubdi_ioctl+0x828>

And then on to...

usba_hubdi_ioctl+0x828:         testq  %rbx,%rbx
usba_hubdi_ioctl+0x82b:         movl   -0x80(%rbp),%r13d
usba_hubdi_ioctl+0x82f:         je     +0x416   <usba_hubdi_ioctl+0xc4b>

In this case we know the point is NULL (we looked before) so on to:

usba_hubdi_ioctl+0xc4b:         testl  %r13d,%r13d
usba_hubdi_ioctl+0xc4e:         movl   $0x0,-0xa0(%rbp)
usba_hubdi_ioctl+0xc58:         je     -0xf5    <usba_hubdi_ioctl+0xb69>

We go here if size (from the user program) is 0, which it is, so on to:

usba_hubdi_ioctl+0xb69:         movl   $0x16,%r11d
usba_hubdi_ioctl+0xb6f:         jmp    -0x7cc   <usba_hubdi_ioctl+0x3a8>

There we set EINVAL and head out of the function. If I replace the zero check with nops:

> usba_hubdi_ioctl+0xc58::dis -n 1
usba_hubdi_ioctl+0xc4e:         movl   $0x0,-0xa0(%rbp)
usba_hubdi_ioctl+0xc58:         je     -0xf5    <usba_hubdi_ioctl+0xb69>
usba_hubdi_ioctl+0xc5e:         movl   -0x70(%rbp),%edx

> usba_hubdi_ioctl+0xc58/v 90 90 90 90 90 90
usba_hubdi_ioctl+0xc58:         0xf     =       0x90
usba_hubdi_ioctl+0xc59:         0x84    =       0x90
usba_hubdi_ioctl+0xc5a:         0xb     =       0x90
usba_hubdi_ioctl+0xc5b:         0xff    =       0x90
usba_hubdi_ioctl+0xc5c:         0xff    =       0x90
usba_hubdi_ioctl+0xc5d:         0xff    =       0x90

> usba_hubdi_ioctl+0xc58::dis -n 6
...
usba_hubdi_ioctl+0xc4e:         movl   $0x0,-0xa0(%rbp)
usba_hubdi_ioctl+0xc58:         nop
usba_hubdi_ioctl+0xc59:         nop
usba_hubdi_ioctl+0xc5a:         nop
usba_hubdi_ioctl+0xc5b:         nop
usba_hubdi_ioctl+0xc5c:         nop
usba_hubdi_ioctl+0xc5d:         nop
usba_hubdi_ioctl+0xc5e:         movl   -0x70(%rbp),%edx
...

Then things work roughly as expected!

$ dtrace -qCs watch.d -c 'cfgadm usb'
   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0014 [DEVCTL_AP_GETSTATE])
   3 ioctl(req 00DC0014 [DEVCTL_AP_GETSTATE]) -> 0, 0x0 [errno 0]
   3 closed

   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x1
    uint32_t port = 0x2
    uint32_t get_size = 0x1
    caddr32_t buf = 0x80465f0
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x5f
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_DEV
    is a get size request!

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
    returned size = 18 (0x12)

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x1
    uint32_t port = 0x2
    uint32_t get_size = 0
    caddr32_t buf = 0x8faf050
    uint32_t bufsiz = 0x12
    uint32_t misc_arg = 0
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x5f
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_DEV

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
   3 closed

   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x3
    uint32_t port = 0x2
    uint32_t get_size = 0x1
    caddr32_t buf = 0x80465f0
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0x1
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x9a
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_STRING
    misc arg = HUBD_MFG_STR
    is a get size request!

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
    returned size = 0 (0x0)

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x3
    uint32_t port = 0x2
    uint32_t get_size = 0
    caddr32_t buf = 0x8fb1868
    uint32_t bufsiz = 0
    uint32_t misc_arg = 0x1
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x9a
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_STRING
    misc arg = HUBD_MFG_STR

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
   3 closed

   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x3
    uint32_t port = 0x2
    uint32_t get_size = 0x1
    caddr32_t buf = 0x80465f0
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0x2
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0xe1
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_STRING
    misc arg = HUBD_PRODUCT_STR
    is a get size request!

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
    returned size = 0 (0x0)

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x3
    uint32_t port = 0x2
    uint32_t get_size = 0
    caddr32_t buf = 0x8fb1b60
    uint32_t bufsiz = 0
    uint32_t misc_arg = 0x2
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0xe1
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_STRING
    misc arg = HUBD_PRODUCT_STR

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
   3 closed

   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x3
    uint32_t port = 0x2
    uint32_t get_size = 0x1
    caddr32_t buf = 0x80465f0
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0x3
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x125
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_STRING
    misc arg = HUBD_SERIALNO_STR
    is a get size request!

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
    returned size = 0 (0x0)

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x3
    uint32_t port = 0x2
    uint32_t get_size = 0
    caddr32_t buf = 0x8fb1b70
    uint32_t bufsiz = 0
    uint32_t misc_arg = 0x3
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x125
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_STRING
    misc arg = HUBD_SERIALNO_STR

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
   3 closed

   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x20
    uint32_t port = 0x2
    uint32_t get_size = 0x1
    caddr32_t buf = 0x80465b0
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0
}
              libc.so.1`ioctl+0x15
              usb.so.1`get_config+0x3f
              usb.so.1`fill_in_ap_info+0x14b
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = HUBD_GET_CURRENT_CONFIG
    is a get size request!

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
    returned size = 4 (0x4)

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x20
    uint32_t port = 0x2
    uint32_t get_size = 0
    caddr32_t buf = 0x8fb1b80
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0
}
              libc.so.1`ioctl+0x15
              usb.so.1`get_config+0x3f
              usb.so.1`fill_in_ap_info+0x14b
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = HUBD_GET_CURRENT_CONFIG

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
   3 closed

   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x3
    uint32_t port = 0x2
    uint32_t get_size = 0x1
    caddr32_t buf = 0x80465f0
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0x4
}
              libc.so.1`ioctl+0x15
              usb.so.1`fill_in_ap_info+0x17d
              usb.so.1`cfga_list_ext+0x383
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = USB_DESCR_TYPE_STRING
    misc arg = HUBD_CFG_DESCR_STR
    is a get size request!

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
    returned size = 0 (0x0)

   3 closed

   3 -> /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2
   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x10
    uint32_t port = 0x2
    uint32_t get_size = 0x1
    caddr32_t buf = 0x8046660
    uint32_t bufsiz = 0x4
    uint32_t misc_arg = 0
}
              libc.so.1`ioctl+0x15
              usb.so.1`cfga_list_ext+0x3a6
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = HUBD_GET_CFGADM_NAME
    is a get size request!

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
    returned size = 7 (0x7)

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL])
hubd_ioctl_data_32_t {
    uint32_t cmd = 0x10
    uint32_t port = 0x2
    uint32_t get_size = 0
    caddr32_t buf = 0x8fb1b70
    uint32_t bufsiz = 0x7
    uint32_t misc_arg = 0
}
              libc.so.1`ioctl+0x15
              usb.so.1`cfga_list_ext+0x3a6
              libcfgadm.so.1`stat_plugin_v2+0x7b
              libcfgadm.so.1`do_list_common_impl+0xf4
              libcfgadm.so.1`do_list_common+0xcc
              libdevinfo.so.1`walk_one_minor_list+0x61
              libdevinfo.so.1`di_walk_minor+0x86
              libcfgadm.so.1`list_common+0xd6
              libcfgadm.so.1`config_list_ext+0x122
              cfgadm`main+0xa5b
              cfgadm`_start_crt+0x9a
              cfgadm`_start+0x1a
    command = HUBD_GET_CFGADM_NAME

   3 ioctl(req 00DC0015 [DEVCTL_AP_CONTROL]) -> 0, 0x0 [errno 0]
   3 closed

Ap_Id                          Type         Receptacle   Occupant     Condition
usb1/1                         unknown      empty        unconfigured ok
usb1/2                         unknown      empty        unconfigured ok
usb1/3                         unknown      empty        unconfigured ok
usb1/4                         unknown      empty        unconfigured ok
usb1/5                         unknown      empty        unconfigured ok
usb1/6                         unknown      empty        unconfigured ok
usb1/7                         unknown      empty        unconfigured ok
usb1/8                         unknown      empty        unconfigured ok
usb2/1                         usb-hub      connected    configured   ok
usb2/1.1                       usb-device   connected    configured   ok
usb2/1.2                       usb-hub      connected    configured   ok
usb2/1.2.1                     usb-device   connected    configured   ok
usb2/1.2.2                     usb-device   connected    configured   ok
usb2/1.2.3                     usb-miscell  connected    configured   ok
usb2/1.2.4                     usb-device   connected    configured   ok
usb2/1.2.5                     usb-miscell  connected    configured   ok
usb2/1.2.6                     usb-miscell  connected    configured   ok
usb2/1.2.7                     usb-hub      connected    configured   ok
usb2/1.2.7.1                   unknown      empty        unconfigured ok
usb2/1.2.7.2                   usb-device   connected    configured   ok  # Yay!
usb2/1.2.7.3                   unknown      empty        unconfigured ok
usb2/1.2.7.4                   unknown      empty        unconfigured ok
usb2/1.2.7.5                   usb-miscell  connected    configured   ok
usb2/1.2.7.6                   unknown      empty        unconfigured ok
usb2/1.2.7.7                   unknown      empty        unconfigured ok
usb2/1.3                       unknown      empty        unconfigured ok
usb2/1.4                       unknown      empty        unconfigured ok
usb2/1.5                       unknown      empty        unconfigured ok
usb2/1.6                       unknown      empty        unconfigured ok
usb2/2                         unknown      empty        unconfigured ok
usb2/3                         unknown      empty        unconfigured ok
usb3/1                         usb-hub      connected    configured   ok
usb3/1.1                       unknown      empty        unconfigured ok
usb3/1.2                       unknown      empty        unconfigured ok
usb3/1.3                       unknown      empty        unconfigured ok
usb3/1.4                       unknown      empty        unconfigured ok
usb3/1.5                       unknown      empty        unconfigured ok
usb3/1.6                       unknown      empty        unconfigured ok
usb3/1.7                       unknown      empty        unconfigured ok
usb3/1.8                       unknown      empty        unconfigured ok
usb3/2                         unknown      empty        unconfigured ok
usb3/3                         unknown      empty        unconfigured ok

We can ask for the strings (which are trash, because there is no null termination in the mishandled buffer):

$ cfgadm -lv usb2/1.2.7.2 | cat -vet
Ap_Id                          Receptacle   Occupant     Condition  Information$
When         Type         Busy     Phys_Id$
usb2/1.2.7.2                   connected    configured   ok         Mfg: 8~M^H  Product: X~M^H  Serial: H~M^HM- M-uM^H^I  NConfigs: 1  Config: 0  <no cfg str descr>$
unavailable  usb-device   n        /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2$

I was able to kick the device, which then reloaded the ROM:

$ pfexec cfgadm -v -y -x usb_reset usb2/1.2.7.2
$ pfexec cfgadm -lv usb2/1.2.7.2 | cat -vet
Ap_Id                          Receptacle   Occupant     Condition  Information$
When         Type         Busy     Phys_Id$
usb2/1.2.7.2                   connected    configured   ok         Mfg: Adafruit  Product: FT232H  Serial: FT2PANJC  NConfigs: 1  Config: 0  <no cfg str descr>$
unavailable  usb-device   n        /devices/pci@0,0/pci1028,577@1a/hub@1/hub@2/hub@7:1.2.7.2$

These routines clearly need to be amended to understand that all of the enumerated strings may well be of zero length or missing altogether.

Actions

Also available in: Atom PDF