]> err.no Git - linux-2.6/blobdiff - drivers/infiniband/hw/ipath/ipath_driver.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireles...
[linux-2.6] / drivers / infiniband / hw / ipath / ipath_driver.c
index d1bbee50b5baec2069b662af4fbe3ea4d3a60cbb..acf30c06a0c0ff8eb1981e692c7cc2818b78c4cc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -89,6 +89,10 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("QLogic <support@qlogic.com>");
 MODULE_DESCRIPTION("QLogic InfiniPath driver");
 
+/*
+ * Table to translate the LINKTRAININGSTATE portion of
+ * IBCStatus to a human-readable form.
+ */
 const char *ipath_ibcstatus_str[] = {
        "Disabled",
        "LinkUp",
@@ -103,9 +107,20 @@ const char *ipath_ibcstatus_str[] = {
        "CfgWaitRmt",
        "CfgIdle",
        "RecovRetrain",
-       "LState0xD",            /* unused */
+       "CfgTxRevLane",         /* unused before IBA7220 */
        "RecovWaitRmt",
        "RecovIdle",
+       /* below were added for IBA7220 */
+       "CfgEnhanced",
+       "CfgTest",
+       "CfgWaitRmtTest",
+       "CfgWaitCfgEnhanced",
+       "SendTS_T",
+       "SendTstIdles",
+       "RcvTS_T",
+       "SendTst_TS1s",
+       "LTState18", "LTState19", "LTState1A", "LTState1B",
+       "LTState1C", "LTState1D", "LTState1E", "LTState1F"
 };
 
 static void __devexit ipath_remove_one(struct pci_dev *);
@@ -114,8 +129,10 @@ static int __devinit ipath_init_one(struct pci_dev *,
 
 /* Only needed for registration, nothing else needs this info */
 #define PCI_VENDOR_ID_PATHSCALE 0x1fc1
+#define PCI_VENDOR_ID_QLOGIC 0x1077
 #define PCI_DEVICE_ID_INFINIPATH_HT 0xd
 #define PCI_DEVICE_ID_INFINIPATH_PE800 0x10
+#define PCI_DEVICE_ID_INFINIPATH_7220 0x7220
 
 /* Number of seconds before our card status check...  */
 #define STATUS_TIMEOUT 60
@@ -123,6 +140,7 @@ static int __devinit ipath_init_one(struct pci_dev *,
 static const struct pci_device_id ipath_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_HT) },
        { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) },
+       { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_INFINIPATH_7220) },
        { 0, }
 };
 
@@ -138,19 +156,6 @@ static struct pci_driver ipath_driver = {
        },
 };
 
-static void ipath_check_status(struct work_struct *work)
-{
-       struct ipath_devdata *dd = container_of(work, struct ipath_devdata,
-                                               status_work.work);
-
-       /*
-        * If we don't have any interrupts, let the user know and
-        * don't bother checking again.
-        */
-       if (dd->ipath_int_counter == 0)
-               dev_err(&dd->pcidev->dev, "No interrupts detected.\n");
-}
-
 static inline void read_bars(struct ipath_devdata *dd, struct pci_dev *dev,
                             u32 *bar0, u32 *bar1)
 {
@@ -218,8 +223,6 @@ static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev)
        dd->pcidev = pdev;
        pci_set_drvdata(pdev, dd);
 
-       INIT_DELAYED_WORK(&dd->status_work, ipath_check_status);
-
        list_add(&dd->ipath_list, &ipath_dev_list);
 
 bail_unlock:
@@ -348,7 +351,14 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
 
        ipath_disable_armlaunch(dd);
 
-       writeq(0, piobuf); /* length 0, no dwords actually sent */
+       /*
+        * length 0, no dwords actually sent, and mark as VL15
+        * on chips where that may matter (due to IB flowcontrol)
+        */
+       if ((dd->ipath_flags & IPATH_HAS_PBC_CNT))
+               writeq(1UL << 63, piobuf);
+       else
+               writeq(0, piobuf);
        ipath_flush_wc();
 
        /*
@@ -389,6 +399,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
        struct ipath_devdata *dd;
        unsigned long long addr;
        u32 bar0 = 0, bar1 = 0;
+       u8 rev;
 
        dd = ipath_alloc_devdata(pdev);
        if (IS_ERR(dd)) {
@@ -420,7 +431,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
        }
        addr = pci_resource_start(pdev, 0);
        len = pci_resource_len(pdev, 0);
-       ipath_cdbg(VERBOSE, "regbase (0) %llx len %d pdev->irq %d, vend %x/%x "
+       ipath_cdbg(VERBOSE, "regbase (0) %llx len %d irq %d, vend %x/%x "
                   "driver_data %lx\n", addr, len, pdev->irq, ent->vendor,
                   ent->device, ent->driver_data);
 
@@ -524,6 +535,13 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
                              "CONFIG_PCI_MSI is not enabled\n", ent->device);
                return -ENODEV;
 #endif
+       case PCI_DEVICE_ID_INFINIPATH_7220:
+#ifndef CONFIG_PCI_MSI
+               ipath_dbg("CONFIG_PCI_MSI is not enabled, "
+                         "using INTx for unit %u\n", dd->ipath_unit);
+#endif
+               ipath_init_iba7220_funcs(dd);
+               break;
        default:
                ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, "
                              "failing\n", ent->device);
@@ -545,7 +563,13 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
                goto bail_regions;
        }
 
-       dd->ipath_pcirev = pdev->revision;
+       ret = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+       if (ret) {
+               ipath_dev_err(dd, "Failed to read PCI revision ID unit "
+                             "%u: err %d\n", dd->ipath_unit, -ret);
+               goto bail_regions;      /* shouldn't ever happen */
+       }
+       dd->ipath_pcirev = rev;
 
 #if defined(__powerpc__)
        /* There isn't a generic way to specify writethrough mappings */
@@ -568,14 +592,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
        ipath_cdbg(VERBOSE, "mapped io addr %llx to kregbase %p\n",
                   addr, dd->ipath_kregbase);
 
-       /*
-        * clear ipath_flags here instead of in ipath_init_chip as it is set
-        * by ipath_setup_htconfig.
-        */
-       dd->ipath_flags = 0;
-       dd->ipath_lli_counter = 0;
-       dd->ipath_lli_errors = 0;
-
        if (dd->ipath_f_bus(dd, pdev))
                ipath_dev_err(dd, "Failed to setup config space; "
                              "continuing anyway\n");
@@ -620,9 +636,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
        ipath_diag_add(dd);
        ipath_register_ib_device(dd);
 
-       /* Check that card status in STATUS_TIMEOUT seconds. */
-       schedule_delayed_work(&dd->status_work, HZ * STATUS_TIMEOUT);
-
        goto bail;
 
 bail_irqsetup:
@@ -667,6 +680,10 @@ static void __devexit cleanup_device(struct ipath_devdata *dd)
                ipath_disable_wc(dd);
        }
 
+       if (dd->ipath_spectriggerhit)
+               dev_info(&dd->pcidev->dev, "%lu special trigger hits\n",
+                        dd->ipath_spectriggerhit);
+
        if (dd->ipath_pioavailregs_dma) {
                dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
                                  (void *) dd->ipath_pioavailregs_dma,
@@ -753,7 +770,6 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev)
         */
        ipath_shutdown_device(dd);
 
-       cancel_delayed_work(&dd->status_work);
        flush_scheduled_work();
 
        if (dd->verbs_dev)
@@ -876,18 +892,52 @@ int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs)
                           (unsigned long long) ipath_read_kreg64(
                                   dd, dd->ipath_kregs->kr_ibcctrl),
                           (unsigned long long) val,
-                          ipath_ibcstatus_str[val & 0xf]);
+                          ipath_ibcstatus_str[val & dd->ibcs_lts_mask]);
        }
        return (dd->ipath_flags & state) ? 0 : -ETIMEDOUT;
 }
 
+static void decode_sdma_errs(struct ipath_devdata *dd, ipath_err_t err,
+       char *buf, size_t blen)
+{
+       static const struct {
+               ipath_err_t err;
+               const char *msg;
+       } errs[] = {
+               { INFINIPATH_E_SDMAGENMISMATCH, "SDmaGenMismatch" },
+               { INFINIPATH_E_SDMAOUTOFBOUND, "SDmaOutOfBound" },
+               { INFINIPATH_E_SDMATAILOUTOFBOUND, "SDmaTailOutOfBound" },
+               { INFINIPATH_E_SDMABASE, "SDmaBase" },
+               { INFINIPATH_E_SDMA1STDESC, "SDma1stDesc" },
+               { INFINIPATH_E_SDMARPYTAG, "SDmaRpyTag" },
+               { INFINIPATH_E_SDMADWEN, "SDmaDwEn" },
+               { INFINIPATH_E_SDMAMISSINGDW, "SDmaMissingDw" },
+               { INFINIPATH_E_SDMAUNEXPDATA, "SDmaUnexpData" },
+               { INFINIPATH_E_SDMADESCADDRMISALIGN, "SDmaDescAddrMisalign" },
+               { INFINIPATH_E_SENDBUFMISUSE, "SendBufMisuse" },
+               { INFINIPATH_E_SDMADISABLED, "SDmaDisabled" },
+       };
+       int i;
+       int expected;
+       size_t bidx = 0;
+
+       for (i = 0; i < ARRAY_SIZE(errs); i++) {
+               expected = (errs[i].err != INFINIPATH_E_SDMADISABLED) ? 0 :
+                       test_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status);
+               if ((err & errs[i].err) && !expected)
+                       bidx += snprintf(buf + bidx, blen - bidx,
+                                        "%s ", errs[i].msg);
+       }
+}
+
 /*
  * Decode the error status into strings, deciding whether to always
  * print * it or not depending on "normal packet errors" vs everything
  * else.   Return 1 if "real" errors, otherwise 0 if only packet
  * errors, so caller can decide what to print with the string.
  */
-int ipath_decode_err(char *buf, size_t blen, ipath_err_t err)
+int ipath_decode_err(struct ipath_devdata *dd, char *buf, size_t blen,
+       ipath_err_t err)
 {
        int iserr = 1;
        *buf = '\0';
@@ -925,6 +975,8 @@ int ipath_decode_err(char *buf, size_t blen, ipath_err_t err)
                strlcat(buf, "rbadversion ", blen);
        if (err & INFINIPATH_E_RHDR)
                strlcat(buf, "rhdr ", blen);
+       if (err & INFINIPATH_E_SENDSPECIALTRIGGER)
+               strlcat(buf, "sendspecialtrigger ", blen);
        if (err & INFINIPATH_E_RLONGPKTLEN)
                strlcat(buf, "rlongpktlen ", blen);
        if (err & INFINIPATH_E_RMAXPKTLEN)
@@ -967,6 +1019,10 @@ int ipath_decode_err(char *buf, size_t blen, ipath_err_t err)
                strlcat(buf, "hardware ", blen);
        if (err & INFINIPATH_E_RESET)
                strlcat(buf, "reset ", blen);
+       if (err & INFINIPATH_E_SDMAERRS)
+               decode_sdma_errs(dd, err, buf, blen);
+       if (err & INFINIPATH_E_INVALIDEEPCMD)
+               strlcat(buf, "invalideepromcmd ", blen);
 done:
        return iserr;
 }
@@ -1720,26 +1776,81 @@ bail:
  */
 void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
 {
+       unsigned long flags;
+
+       if (dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) {
+               ipath_cdbg(VERBOSE, "Ignore while in autonegotiation\n");
+               goto bail;
+       }
+       /*
+        * If we have SDMA, and it's not disabled, we have to kick off the
+        * abort state machine, provided we aren't already aborting.
+        * If we are in the process of aborting SDMA (!DISABLED, but ABORTING),
+        * we skip the rest of this routine. It is already "in progress"
+        */
+       if (dd->ipath_flags & IPATH_HAS_SEND_DMA) {
+               int skip_cancel;
+               u64 *statp = &dd->ipath_sdma_status;
+
+               spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
+               skip_cancel =
+                       !test_bit(IPATH_SDMA_DISABLED, statp) &&
+                       test_and_set_bit(IPATH_SDMA_ABORTING, statp);
+               spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
+               if (skip_cancel)
+                       goto bail;
+       }
+
        ipath_dbg("Cancelling all in-progress send buffers\n");
 
        /* skip armlaunch errs for a while */
        dd->ipath_lastcancel = jiffies + HZ / 2;
 
        /*
-        * the abort bit is auto-clearing.  We read scratch to be sure
-        * that cancels and the abort have taken effect in the chip.
+        * The abort bit is auto-clearing.  We also don't want pioavail
+        * update happening during this, and we don't want any other
+        * sends going out, so turn those off for the duration.  We read
+        * the scratch register to be sure that cancels and the abort
+        * have taken effect in the chip.  Otherwise two parts are same
+        * as ipath_force_pio_avail_update()
         */
+       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+       dd->ipath_sendctrl &= ~(INFINIPATH_S_PIOBUFAVAILUPD
+               | INFINIPATH_S_PIOENABLE);
        ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-               INFINIPATH_S_ABORT);
+               dd->ipath_sendctrl | INFINIPATH_S_ABORT);
        ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+
+       /* disarm all send buffers */
        ipath_disarm_piobufs(dd, 0,
-               (unsigned)(dd->ipath_piobcnt2k + dd->ipath_piobcnt4k));
-       if (restore_sendctrl) /* else done by caller later */
+               dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
+
+       if (restore_sendctrl) {
+               /* else done by caller later if needed */
+               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+               dd->ipath_sendctrl |= INFINIPATH_S_PIOBUFAVAILUPD |
+                       INFINIPATH_S_PIOENABLE;
                ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                                dd->ipath_sendctrl);
+                       dd->ipath_sendctrl);
+               /* and again, be sure all have hit the chip */
+               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+       }
 
-       /* and again, be sure all have hit the chip */
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+       if ((dd->ipath_flags & IPATH_HAS_SEND_DMA) &&
+           !test_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status) &&
+           test_bit(IPATH_SDMA_RUNNING, &dd->ipath_sdma_status)) {
+               spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
+               /* only wait so long for intr */
+               dd->ipath_sdma_abort_intr_timeout = jiffies + HZ;
+               dd->ipath_sdma_reset_wait = 200;
+               __set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
+               if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
+                       tasklet_hi_schedule(&dd->ipath_sdma_abort_task);
+               spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
+       }
+bail:;
 }
 
 /*
@@ -1880,16 +1991,41 @@ int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
                dd->ipath_ibcctrl |= INFINIPATH_IBCC_LOOPBACK;
                ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
                                 dd->ipath_ibcctrl);
+
+               /* turn heartbeat off, as it causes loopback to fail */
+               dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT,
+                                      IPATH_IB_HRTBT_OFF);
+               /* don't wait */
                ret = 0;
-               goto bail; // no state change to wait for
+               goto bail;
 
        case IPATH_IB_LINK_EXTERNAL:
-               dev_info(&dd->pcidev->dev, "Disabling IB local loopback (normal)\n");
+               dev_info(&dd->pcidev->dev,
+                       "Disabling IB local loopback (normal)\n");
+               dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT,
+                                      IPATH_IB_HRTBT_ON);
                dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LOOPBACK;
                ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
                                 dd->ipath_ibcctrl);
+               /* don't wait */
                ret = 0;
-               goto bail; // no state change to wait for
+               goto bail;
+
+       /*
+        * Heartbeat can be explicitly enabled by the user via
+        * "hrtbt_enable" "file", and if disabled, trying to enable here
+        * will have no effect.  Implicit changes (heartbeat off when
+        * loopback on, and vice versa) are included to ease testing.
+        */
+       case IPATH_IB_LINK_HRTBT:
+               ret = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT,
+                       IPATH_IB_HRTBT_ON);
+               goto bail;
+
+       case IPATH_IB_LINK_NO_HRTBT:
+               ret = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT,
+                       IPATH_IB_HRTBT_OFF);
+               goto bail;
 
        default:
                ipath_dbg("Invalid linkstate 0x%x requested\n", newstate);
@@ -1912,7 +2048,7 @@ bail:
  * sanity checking on this, and we don't deal with what happens to
  * programs that are already running when the size changes.
  * NOTE: changing the MTU will usually cause the IBC to go back to
- * link initialize (IPATH_IBSTATE_INIT) state...
+ * link INIT state...
  */
 int ipath_set_mtu(struct ipath_devdata *dd, u16 arg)
 {
@@ -1981,11 +2117,16 @@ bail:
        return ret;
 }
 
-int ipath_set_lid(struct ipath_devdata *dd, u32 arg, u8 lmc)
+int ipath_set_lid(struct ipath_devdata *dd, u32 lid, u8 lmc)
 {
-       dd->ipath_lid = arg;
+       dd->ipath_lid = lid;
        dd->ipath_lmc = lmc;
 
+       dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LIDLMC, lid |
+               (~((1U << lmc) - 1)) << 16);
+
+       dev_info(&dd->pcidev->dev, "We got a lid: 0x%x\n", lid);
+
        return 0;
 }
 
@@ -2047,9 +2188,8 @@ static void ipath_run_led_override(unsigned long opaque)
         * but leave that to per-chip functions.
         */
        val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
-       ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
-                 dd->ibcs_lts_mask;
-       lstate = (val >> dd->ibcs_ls_shift) & INFINIPATH_IBCS_LINKSTATE_MASK;
+       ltstate = ipath_ib_linktrstate(dd, val);
+       lstate = ipath_ib_linkstate(dd, val);
 
        dd->ipath_f_setextled(dd, lstate, ltstate);
        mod_timer(&dd->ipath_led_override_timer, jiffies + timeoff);
@@ -2125,6 +2265,9 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
        ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
                         dd->ipath_rcvctrl);
 
+       if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
+               teardown_sdma(dd);
+
        /*
         * gracefully stop all sends allowing any in progress to trickle out
         * first.
@@ -2142,9 +2285,16 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
         */
        udelay(5);
 
+       dd->ipath_f_setextled(dd, 0, 0); /* make sure LEDs are off */
+
        ipath_set_ib_lstate(dd, 0, INFINIPATH_IBCC_LINKINITCMD_DISABLE);
        ipath_cancel_sends(dd, 0);
 
+       /*
+        * we are shutting down, so tell components that care.  We don't do
+        * this on just a link state change, much like ethernet, a cable
+        * unplug, etc. doesn't change driver state
+        */
        signal_ib_event(dd, IB_EVENT_PORT_ERR);
 
        /* disable IBC */
@@ -2165,6 +2315,14 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
                del_timer_sync(&dd->ipath_stats_timer);
                dd->ipath_stats_timer_active = 0;
        }
+       if (dd->ipath_intrchk_timer.data) {
+               del_timer_sync(&dd->ipath_intrchk_timer);
+               dd->ipath_intrchk_timer.data = 0;
+       }
+       if (atomic_read(&dd->ipath_led_override_timer_active)) {
+               del_timer_sync(&dd->ipath_led_override_timer);
+               atomic_set(&dd->ipath_led_override_timer_active, 0);
+       }
 
        /*
         * clear all interrupts and errors, so that the next time the driver
@@ -2267,6 +2425,7 @@ static int __init infinipath_init(void)
         */
        idr_init(&unit_table);
        if (!idr_pre_get(&unit_table, GFP_KERNEL)) {
+               printk(KERN_ERR IPATH_DRV_NAME ": idr_pre_get() failed\n");
                ret = -ENOMEM;
                goto bail;
        }
@@ -2358,13 +2517,18 @@ int ipath_reset_device(int unit)
                        }
                }
 
+       if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
+               teardown_sdma(dd);
+
        dd->ipath_flags &= ~IPATH_INITTED;
+       ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
        ret = dd->ipath_f_reset(dd);
-       if (ret != 1)
-               ipath_dbg("reset was not successful\n");
-       ipath_dbg("Trying to reinitialize unit %u after reset attempt\n",
-                 unit);
-       ret = ipath_init_chip(dd, 1);
+       if (ret == 1) {
+               ipath_dbg("Reinitializing unit %u after reset attempt\n",
+                         unit);
+               ret = ipath_init_chip(dd, 1);
+       } else
+               ret = -EAGAIN;
        if (ret)
                ipath_dev_err(dd, "Reinitialize unit %u after "
                              "reset failed with %d\n", unit, ret);