#define EVENT_DEV_ASLEEP               7
 #define EVENT_DEV_OPEN                 8
 #define EVENT_STAT_UPDATE              9
+#define EVENT_DEV_DISCONNECT           10
 
 struct statstage {
        struct mutex                    access_lock;    /* for stats access */
 
 static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data)
 {
-       u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL);
+       u32 *buf;
        int ret;
 
+       if (test_bit(EVENT_DEV_DISCONNECT, &dev->flags))
+               return -ENODEV;
+
+       buf = kmalloc(sizeof(u32), GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
 
 static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data)
 {
-       u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL);
+       u32 *buf;
        int ret;
 
+       if (test_bit(EVENT_DEV_DISCONNECT, &dev->flags))
+               return -ENODEV;
+
+       buf = kmalloc(sizeof(u32), GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
                /* software-driven interface shutdown */
                case -ECONNRESET:
                case -ESHUTDOWN:
+                       netif_dbg(dev, tx_err, dev->net,
+                                 "tx err interface gone %d\n",
+                                 entry->urb->status);
                        break;
 
                case -EPROTO:
                case -ETIME:
                case -EILSEQ:
                        netif_stop_queue(dev->net);
+                       netif_dbg(dev, tx_err, dev->net,
+                                 "tx err queue stopped %d\n",
+                                 entry->urb->status);
                        break;
                default:
                        netif_dbg(dev, tx_err, dev->net,
-                                 "tx err %d\n", entry->urb->status);
+                                 "unknown tx err %d\n",
+                                 entry->urb->status);
                        break;
                }
        }
                        lan78xx_defer_kevent(dev, EVENT_RX_HALT);
                        break;
                case -ENODEV:
+               case -ENOENT:
                        netif_dbg(dev, ifdown, dev->net, "device gone\n");
                        netif_device_detach(dev->net);
                        break;
                lan78xx_defer_kevent(dev, EVENT_TX_HALT);
                usb_autopm_put_interface_async(dev->intf);
                break;
+       case -ENODEV:
+       case -ENOENT:
+               netif_dbg(dev, tx_err, dev->net,
+                         "tx: submit urb err %d (disconnected?)", ret);
+               netif_device_detach(dev->net);
+               break;
        default:
                usb_autopm_put_interface_async(dev->intf);
                netif_dbg(dev, tx_err, dev->net,
 
        dev = container_of(work, struct lan78xx_net, wq.work);
 
+       if (test_bit(EVENT_DEV_DISCONNECT, &dev->flags))
+               return;
+
        if (usb_autopm_get_interface(dev->intf) < 0)
                return;
 
 
        /* software-driven interface shutdown */
        case -ENOENT:                   /* urb killed */
+       case -ENODEV:                   /* hardware gone */
        case -ESHUTDOWN:                /* hardware gone */
                netif_dbg(dev, ifdown, dev->net,
                          "intr shutdown, code %d\n", status);
                break;
        }
 
-       if (!netif_running(dev->net))
+       if (!netif_device_present(dev->net) ||
+           !netif_running(dev->net)) {
+               netdev_warn(dev->net, "not submitting new status URB");
                return;
+       }
 
        memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
        status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status != 0)
+
+       switch (status) {
+       case  0:
+               break;
+       case -ENODEV:
+       case -ENOENT:
+               netif_dbg(dev, timer, dev->net,
+                         "intr resubmit %d (disconnect?)", status);
+               netif_device_detach(dev->net);
+               break;
+       default:
                netif_err(dev, timer, dev->net,
                          "intr resubmit --> %d\n", status);
+               break;
+       }
 }
 
 static void lan78xx_disconnect(struct usb_interface *intf)
        if (!dev)
                return;
 
+       set_bit(EVENT_DEV_DISCONNECT, &dev->flags);
+
        udev = interface_to_usbdev(intf);
        net = dev->net;
+
+       unregister_netdev(net);
+
+       cancel_delayed_work_sync(&dev->wq);
+
        phydev = net->phydev;
 
        phy_unregister_fixup_for_uid(PHY_KSZ9031RNX, 0xfffffff0);
        if (phy_is_pseudo_fixed_link(phydev))
                fixed_phy_unregister(phydev);
 
-       unregister_netdev(net);
-
-       cancel_delayed_work_sync(&dev->wq);
-
        usb_scuttle_anchored_urbs(&dev->deferred);
 
+       if (timer_pending(&dev->stat_monitor))
+               del_timer_sync(&dev->stat_monitor);
+
        lan78xx_unbind(dev, intf);
 
        usb_kill_urb(dev->urb_intr);