PATCH usbip small redesign

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

in the last few weeks I worked on better support of usbip for embedded devices running openwrt and ddwrt. After compiling the kernel with lockdep, I decided to rewrite the current locking logic and some more parts of the usbip driver:

- Rewrote debugging code. Removed sysfs debugging flags and replaced it with macro code for usual debug messages and verbose ones. - Removed sending of unlink urbs. This makes no sense in virtual connections ?! Unlink urbs are now given back in vhci's dequeue function. This has the advantage that the calling usb device driver code does not block until it waits for never returning urbs to complete. I am not very sure if this should stay this way forever ;) But at the moment it makes the code much more stable. - Removed usual usb_hcd_giveback_urb() calls. Some urb completion callback routines assume to be called in interrupt context and do not hold their locks interrupt safe. It's now done by usbip_hcd_giveback_urb. This function disables interrupts first.
 - Some code cleanups.

After theses changes I can run this driver with no more kernel panics and deadlocks.

But anyway there are some few usb-storage devices that do not work correctly yet. As far as I debugged it yet, they stop completing after about 12 submitted urbs on the host side with xhci or ehci. But it works with the dwc_otg hcd. After a timeout on the vhci side, the usb-storage code calls a command_abort function that can lead to a deadlock in the usb-storage code. A lockdep output of this attached to this mail. However, detach and reattach the device make it work.

I had tested these changes, with 2 x86 machines(kernel 3.2.11 and 3.7.2) and openwrt (kernel 3.3.8 and 3.7.2) on two embedded devices (ARM and MIPS). I have only about 4 usb devices to test with, so please check my changes against all your usb devices.

this patch is done by git diff e6577f3189d82a729b13e38f3d135f1becd6d294 from git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git tag v3.7.2

Because of the very small space on embedded devices, I forked the current userspace code and freed it of it's glib dependency. I removed all this libtool and gnu automake stuff, too. It's now running with cmake.
git://ddf-software.de/usbip_cli

Signed-off-by: Daniel Danzberger <daniel@xxxxxxxxxx>

Jan 15 16:56:03 lappi kernel: [  150.478063] connection closed
Jan 15 16:56:03 lappi kernel: [  150.478419] usb 5-1: USB disconnect, device number 2
Jan 15 16:56:09 lappi kernel: [  155.937740] 
Jan 15 16:56:09 lappi kernel: [  155.937752] =========================================================
Jan 15 16:56:09 lappi kernel: [  155.937757] [ INFO: possible irq lock inversion dependency detected ]
Jan 15 16:56:09 lappi kernel: [  155.937765] 3.7.2+ #17 Tainted: G           O
Jan 15 16:56:09 lappi kernel: [  155.937769] ---------------------------------------------------------
Jan 15 16:56:09 lappi kernel: [  155.937774] scsi_eh_6/5034 just changed the state of lock:
Jan 15 16:56:09 lappi kernel: [  155.937779]  (&(shost->host_lock)->rlock){+.-...}, at: [<ffffffffa04e58c0>] command_abort+0x21/0x86 [usb_storage]
Jan 15 16:56:09 lappi kernel: [  155.937805] but this lock was taken by another, HARDIRQ-safe lock in the past:
Jan 15 16:56:09 lappi kernel: [  155.937809]  (&(&host->lock)->rlock){-.-...}
Jan 15 16:56:09 lappi kernel: [  155.937809] 
Jan 15 16:56:09 lappi kernel: [  155.937809] and interrupts could create inverse lock ordering between them.
Jan 15 16:56:09 lappi kernel: [  155.937809] 
Jan 15 16:56:09 lappi kernel: [  155.937819] 
Jan 15 16:56:09 lappi kernel: [  155.937819] other info that might help us debug this:
Jan 15 16:56:09 lappi kernel: [  155.937824]  Possible interrupt unsafe locking scenario:
Jan 15 16:56:09 lappi kernel: [  155.937824] 
Jan 15 16:56:09 lappi kernel: [  155.937829]        CPU0                    CPU1
Jan 15 16:56:09 lappi kernel: [  155.937833]        ----                    ----
Jan 15 16:56:09 lappi kernel: [  155.937836]   lock(&(shost->host_lock)->rlock);
Jan 15 16:56:09 lappi kernel: [  155.937844]                                local_irq_disable();
Jan 15 16:56:09 lappi kernel: [  155.937847]                                lock(&(&host->lock)->rlock);
Jan 15 16:56:09 lappi kernel: [  155.937854]                                lock(&(shost->host_lock)->rlock);
Jan 15 16:56:09 lappi kernel: [  155.937861]   <Interrupt>
Jan 15 16:56:09 lappi kernel: [  155.937864]     lock(&(&host->lock)->rlock);
Jan 15 16:56:09 lappi kernel: [  155.937870] 
Jan 15 16:56:09 lappi kernel: [  155.937870]  *** DEADLOCK ***
Jan 15 16:56:09 lappi kernel: [  155.937870] 
Jan 15 16:56:09 lappi kernel: [  155.937878] 1 lock held by scsi_eh_6/5034:
Jan 15 16:56:09 lappi kernel: [  155.937882]  #0:  (&(shost->host_lock)->rlock){+.-...}, at: [<ffffffffa04e58c0>] command_abort+0x21/0x86 [usb_storage]
Jan 15 16:56:09 lappi kernel: [  155.937900] 
Jan 15 16:56:09 lappi kernel: [  155.937900] the shortest dependencies between 2nd lock and 1st lock:
Jan 15 16:56:09 lappi kernel: [  155.937938]  -> (&(&host->lock)->rlock){-.-...} ops: 18581 {
Jan 15 16:56:09 lappi kernel: [  155.937951]     IN-HARDIRQ-W at:
Jan 15 16:56:09 lappi kernel: [  155.937957]                       [<ffffffff8108c72e>] __lock_acquire+0x2b4/0xe6d
Jan 15 16:56:09 lappi kernel: [  155.937968]                       [<ffffffff8108d7b1>] lock_acquire+0x9f/0x112
Jan 15 16:56:09 lappi kernel: [  155.937976]                       [<ffffffff813bfbb8>] _raw_spin_lock+0x36/0x6b
Jan 15 16:56:09 lappi kernel: [  155.937985]                       [<ffffffffa003526d>] ahci_interrupt+0x4b/0x59f [libahci]
Jan 15 16:56:09 lappi kernel: [  155.938001]                       [<ffffffff810ba834>] handle_irq_event_percpu+0x40/0x1c7
Jan 15 16:56:09 lappi kernel: [  155.938013]                       [<ffffffff810baa02>] handle_irq_event+0x47/0x69
Jan 15 16:56:09 lappi kernel: [  155.938022]                       [<ffffffff810bd23c>] handle_edge_irq+0xb0/0xdd
Jan 15 16:56:09 lappi kernel: [  155.938030]                       [<ffffffff81010d29>] handle_irq+0x128/0x135
Jan 15 16:56:09 lappi kernel: [  155.938043]                       [<ffffffff813c945d>] do_IRQ+0x4d/0xa5
Jan 15 16:56:09 lappi kernel: [  155.938053]                       [<ffffffff813c07b2>] ret_from_intr+0x0/0x1a
Jan 15 16:56:09 lappi kernel: [  155.938061]                       [<ffffffff81016a29>] cpu_idle+0xb1/0xf1
Jan 15 16:56:09 lappi kernel: [  155.938071]                       [<ffffffff8139f9c7>] rest_init+0x12b/0x132
Jan 15 16:56:09 lappi kernel: [  155.938079]                       [<ffffffff8182bb9b>] start_kernel+0x3b9/0x3c6
Jan 15 16:56:09 lappi kernel: [  155.938090]                       [<ffffffff8182b2d6>] x86_64_start_reservations+0xb1/0xb5
Jan 15 16:56:09 lappi kernel: [  155.938098]                       [<ffffffff8182b3d8>] x86_64_start_kernel+0xfe/0x10b
Jan 15 16:56:09 lappi kernel: [  155.938106]     IN-SOFTIRQ-W at:
Jan 15 16:56:09 lappi kernel: [  155.938111]                       [<ffffffff8108c747>] __lock_acquire+0x2cd/0xe6d
Jan 15 16:56:09 lappi kernel: [  155.938118]                       [<ffffffff8108d7b1>] lock_acquire+0x9f/0x112
Jan 15 16:56:09 lappi kernel: [  155.938125]                       [<ffffffff813bfbb8>] _raw_spin_lock+0x36/0x6b
Jan 15 16:56:09 lappi kernel: [  155.938132]                       [<ffffffffa003526d>] ahci_interrupt+0x4b/0x59f [libahci]
Jan 15 16:56:09 lappi kernel: [  155.938147]                       [<ffffffff810ba834>] handle_irq_event_percpu+0x40/0x1c7
Jan 15 16:56:09 lappi kernel: [  155.938157]                       [<ffffffff810baa02>] handle_irq_event+0x47/0x69
Jan 15 16:56:09 lappi kernel: [  155.938166]                       [<ffffffff810bd23c>] handle_edge_irq+0xb0/0xdd
Jan 15 16:56:09 lappi kernel: [  155.938173]                       [<ffffffff81010d29>] handle_irq+0x128/0x135
Jan 15 16:56:09 lappi kernel: [  155.938183]                       [<ffffffff813c945d>] do_IRQ+0x4d/0xa5
Jan 15 16:56:09 lappi kernel: [  155.938191]                       [<ffffffff813c07b2>] ret_from_intr+0x0/0x1a
Jan 15 16:56:09 lappi kernel: [  155.938199]                       [<ffffffff81049240>] __do_softirq+0x88/0x1f9
Jan 15 16:56:09 lappi kernel: [  155.938210]                       [<ffffffff813c8bbc>] call_softirq+0x1c/0x30
Jan 15 16:56:09 lappi kernel: [  155.938218]                       [<ffffffff81010d80>] do_softirq+0x4a/0xa2
Jan 15 16:56:09 lappi kernel: [  155.938227]                       [<ffffffff810494c6>] irq_exit+0x51/0xad
Jan 15 16:56:09 lappi kernel: [  155.938236]                       [<ffffffff813c9531>] smp_apic_timer_interrupt+0x7c/0x8a
Jan 15 16:56:09 lappi kernel: [  155.938245]                       [<ffffffff813c8472>] apic_timer_interrupt+0x72/0x80
Jan 15 16:56:09 lappi kernel: [  155.938253]                       [<ffffffff81016a29>] cpu_idle+0xb1/0xf1
Jan 15 16:56:09 lappi kernel: [  155.938262]                       [<ffffffff8139f9c7>] rest_init+0x12b/0x132
Jan 15 16:56:09 lappi kernel: [  155.938269]                       [<ffffffff8182bb9b>] start_kernel+0x3b9/0x3c6
Jan 15 16:56:09 lappi kernel: [  155.938276]                       [<ffffffff8182b2d6>] x86_64_start_reservations+0xb1/0xb5
Jan 15 16:56:09 lappi kernel: [  155.938284]                       [<ffffffff8182b3d8>] x86_64_start_kernel+0xfe/0x10b
Jan 15 16:56:09 lappi kernel: [  155.938292]     INITIAL USE at:
Jan 15 16:56:09 lappi kernel: [  155.938297]                      [<ffffffff8108c806>] __lock_acquire+0x38c/0xe6d
Jan 15 16:56:09 lappi kernel: [  155.938304]                      [<ffffffff8108d7b1>] lock_acquire+0x9f/0x112
Jan 15 16:56:09 lappi kernel: [  155.938311]                      [<ffffffff813c050d>] _raw_spin_lock_irqsave+0x4b/0x85
Jan 15 16:56:09 lappi kernel: [  155.938319]                      [<ffffffffa00e1d8a>] ata_dev_init+0x37/0x92 [libata]
Jan 15 16:56:09 lappi kernel: [  155.938346]                      [<ffffffffa00e1e50>] ata_link_init+0x6b/0xad [libata]
Jan 15 16:56:09 lappi kernel: [  155.938370]                      [<ffffffffa00e2526>] ata_port_alloc+0x1d3/0x1e3 [libata]
Jan 15 16:56:09 lappi kernel: [  155.938394]                      [<ffffffffa00e25e0>] ata_host_alloc+0xaa/0xe7 [libata]
Jan 15 16:56:09 lappi kernel: [  155.938416]                      [<ffffffffa00e2632>] ata_host_alloc_pinfo+0x15/0x9a [libata]
Jan 15 16:56:09 lappi kernel: [  155.938438]                      [<ffffffffa0071825>] ahci_init_one+0x4ef/0x876 [ahci]
Jan 15 16:56:09 lappi kernel: [  155.938452]                      [<ffffffff8120dcdc>] local_pci_probe+0x3e/0x66
Jan 15 16:56:09 lappi kernel: [  155.938462]                      [<ffffffff8120df63>] pci_device_probe+0xc4/0xea
Jan 15 16:56:09 lappi kernel: [  155.938470]                      [<ffffffff8129de1a>] driver_probe_device+0x9f/0x1ba
Jan 15 16:56:09 lappi kernel: [  155.938482]                      [<ffffffff8129df88>] __driver_attach+0x53/0x74
Jan 15 16:56:09 lappi kernel: [  155.938491]                      [<ffffffff8129c45c>] bus_for_each_dev+0x57/0x89
Jan 15 16:56:09 lappi kernel: [  155.938500]                      [<ffffffff8129d8ee>] driver_attach+0x1e/0x20
Jan 15 16:56:09 lappi kernel: [  155.938508]                      [<ffffffff8129d56d>] bus_add_driver+0xfe/0x223
Jan 15 16:56:09 lappi kernel: [  155.938518]                      [<ffffffff8129e54c>] driver_register+0x93/0x119
Jan 15 16:56:09 lappi kernel: [  155.938527]                      [<ffffffff8120d344>] __pci_register_driver+0x5f/0x64
Jan 15 16:56:09 lappi kernel: [  155.938535]                      [<ffffffffa007801e>] joydev_correct+0x1e/0x56 [joydev]
Jan 15 16:56:09 lappi kernel: [  155.938545]                      [<ffffffff810020d5>] do_one_initcall+0x7f/0x13a
Jan 15 16:56:09 lappi kernel: [  155.938553]                      [<ffffffff81098b28>] sys_init_module+0x7f/0x1c2
Jan 15 16:56:09 lappi kernel: [  155.938561]                      [<ffffffff813c7919>] system_call_fastpath+0x16/0x1b
Jan 15 16:56:09 lappi kernel: [  155.938569]   }
Jan 15 16:56:09 lappi kernel: [  155.938573]   ... key      at: [<ffffffffa00fa0f8>] __key.40747+0x0/0xffffffffffff6c93 [libata]
Jan 15 16:56:09 lappi kernel: [  155.938595]   ... acquired at:
Jan 15 16:56:09 lappi kernel: [  155.938598]    [<ffffffff8108d7b1>] lock_acquire+0x9f/0x112
Jan 15 16:56:09 lappi kernel: [  155.938605]    [<ffffffff813c050d>] _raw_spin_lock_irqsave+0x4b/0x85
Jan 15 16:56:09 lappi kernel: [  155.938612]    [<ffffffffa0046123>] scsi_schedule_eh+0x1b/0x64 [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.938638]    [<ffffffffa00e6ea4>] ata_std_sched_eh+0x4f/0x54 [libata]
Jan 15 16:56:09 lappi kernel: [  155.938665]    [<ffffffffa00e73f2>] ata_port_schedule_eh+0x13/0x15 [libata]
Jan 15 16:56:09 lappi kernel: [  155.938690]    [<ffffffffa00e26fb>] __ata_port_probe+0x44/0x55 [libata]
Jan 15 16:56:09 lappi kernel: [  155.938713]    [<ffffffffa00e272e>] ata_port_probe+0x22/0x37 [libata]
Jan 15 16:56:09 lappi kernel: [  155.938734]    [<ffffffffa00e2778>] async_port_probe+0x35/0x51 [libata]
Jan 15 16:56:09 lappi kernel: [  155.938756]    [<ffffffff810668f3>] async_run_entry_fn+0xa4/0x150
Jan 15 16:56:09 lappi kernel: [  155.938764]    [<ffffffff8105bb63>] process_one_work+0x1e7/0x3a2
Jan 15 16:56:09 lappi kernel: [  155.938773]    [<ffffffff8105bfff>] worker_thread+0x126/0x1c4
Jan 15 16:56:09 lappi kernel: [  155.938780]    [<ffffffff8105fd89>] kthread+0xb1/0xb9
Jan 15 16:56:09 lappi kernel: [  155.938787]    [<ffffffff813c786c>] ret_from_fork+0x7c/0xb0
Jan 15 16:56:09 lappi kernel: [  155.938794] 
Jan 15 16:56:09 lappi kernel: [  155.938797] -> (&(shost->host_lock)->rlock){+.-...} ops: 36315 {
Jan 15 16:56:09 lappi kernel: [  155.938810]    HARDIRQ-ON-W at:
Jan 15 16:56:09 lappi kernel: [  155.938815]                     [<ffffffff8108ae5a>] mark_held_locks+0x71/0x99
Jan 15 16:56:09 lappi kernel: [  155.938825]                     [<ffffffff8108b020>] trace_hardirqs_on_caller+0x19e/0x1ad
Jan 15 16:56:09 lappi kernel: [  155.938835]                     [<ffffffff8108b03c>] trace_hardirqs_on+0xd/0xf
Jan 15 16:56:09 lappi kernel: [  155.938844]                     [<ffffffffa02d0044>] usbip_hcd_giveback_urb+0x3f/0x48 [vhci_hcd]
Jan 15 16:56:09 lappi kernel: [  155.938854]                     [<ffffffffa02d010a>] vhci_urb_dequeue+0xbd/0xce [vhci_hcd]
Jan 15 16:56:09 lappi kernel: [  155.938863]                     [<ffffffffa000abac>] unlink1+0xcf/0xe2 [usbcore]
Jan 15 16:56:09 lappi kernel: [  155.938890]                     [<ffffffffa000bc06>] usb_hcd_unlink_urb+0x66/0x87 [usbcore]
Jan 15 16:56:09 lappi kernel: [  155.938914]                     [<ffffffffa000c3d3>] usb_unlink_urb+0x26/0x3c [usbcore]
Jan 15 16:56:09 lappi kernel: [  155.938938]                     [<ffffffffa04e691f>] usb_stor_stop_transport+0x30/0x52 [usb_storage]
Jan 15 16:56:09 lappi kernel: [  155.938949]                     [<ffffffffa04e5903>] command_abort+0x64/0x86 [usb_storage]
Jan 15 16:56:09 lappi kernel: [  155.938958]                     [<ffffffffa0046a5a>] scsi_error_handler+0x2e4/0x5da [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.938983]                     [<ffffffff8105fd89>] kthread+0xb1/0xb9
Jan 15 16:56:09 lappi kernel: [  155.938990]                     [<ffffffff813c786c>] ret_from_fork+0x7c/0xb0
Jan 15 16:56:09 lappi kernel: [  155.938998]    IN-SOFTIRQ-W at:
Jan 15 16:56:09 lappi kernel: [  155.939003]                     [<ffffffff8108c747>] __lock_acquire+0x2cd/0xe6d
Jan 15 16:56:09 lappi kernel: [  155.939010]                     [<ffffffff8108d7b1>] lock_acquire+0x9f/0x112
Jan 15 16:56:09 lappi kernel: [  155.939017]                     [<ffffffff813c050d>] _raw_spin_lock_irqsave+0x4b/0x85
Jan 15 16:56:09 lappi kernel: [  155.939025]                     [<ffffffffa0048c5d>] scsi_device_unbusy+0x29/0xa2 [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.939049]                     [<ffffffffa0040db8>] scsi_finish_command+0x2a/0xf2 [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.939069]                     [<ffffffffa0048ef9>] scsi_softirq_done+0x106/0x10f [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.939092]                     [<ffffffff811dc5f8>] blk_done_softirq+0x7c/0x90
Jan 15 16:56:09 lappi kernel: [  155.939101]                     [<ffffffff81049285>] __do_softirq+0xcd/0x1f9
Jan 15 16:56:09 lappi kernel: [  155.939110]                     [<ffffffff810493d9>] run_ksoftirqd+0x28/0x4e
Jan 15 16:56:09 lappi kernel: [  155.939118]                     [<ffffffff810677c4>] smpboot_thread_fn+0x134/0x150
Jan 15 16:56:09 lappi kernel: [  155.939126]                     [<ffffffff8105fd89>] kthread+0xb1/0xb9
Jan 15 16:56:09 lappi kernel: [  155.939133]                     [<ffffffff813c786c>] ret_from_fork+0x7c/0xb0
Jan 15 16:56:09 lappi kernel: [  155.939141]    INITIAL USE at:
Jan 15 16:56:09 lappi kernel: [  155.939145]                    [<ffffffff8108c806>] __lock_acquire+0x38c/0xe6d
Jan 15 16:56:09 lappi kernel: [  155.939153]                    [<ffffffff8108d7b1>] lock_acquire+0x9f/0x112
Jan 15 16:56:09 lappi kernel: [  155.939159]                    [<ffffffff813c050d>] _raw_spin_lock_irqsave+0x4b/0x85
Jan 15 16:56:09 lappi kernel: [  155.939167]                    [<ffffffffa0046123>] scsi_schedule_eh+0x1b/0x64 [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.939189]                    [<ffffffffa00e6ea4>] ata_std_sched_eh+0x4f/0x54 [libata]
Jan 15 16:56:09 lappi kernel: [  155.939216]                    [<ffffffffa00e73f2>] ata_port_schedule_eh+0x13/0x15 [libata]
Jan 15 16:56:09 lappi kernel: [  155.939242]                    [<ffffffffa00e26fb>] __ata_port_probe+0x44/0x55 [libata]
Jan 15 16:56:09 lappi kernel: [  155.939265]                    [<ffffffffa00e272e>] ata_port_probe+0x22/0x37 [libata]
Jan 15 16:56:09 lappi kernel: [  155.939287]                    [<ffffffffa00e2778>] async_port_probe+0x35/0x51 [libata]
Jan 15 16:56:09 lappi kernel: [  155.939309]                    [<ffffffff810668f3>] async_run_entry_fn+0xa4/0x150
Jan 15 16:56:09 lappi kernel: [  155.939317]                    [<ffffffff8105bb63>] process_one_work+0x1e7/0x3a2
Jan 15 16:56:09 lappi kernel: [  155.939325]                    [<ffffffff8105bfff>] worker_thread+0x126/0x1c4
Jan 15 16:56:09 lappi kernel: [  155.939333]                    [<ffffffff8105fd89>] kthread+0xb1/0xb9
Jan 15 16:56:09 lappi kernel: [  155.939340]                    [<ffffffff813c786c>] ret_from_fork+0x7c/0xb0
Jan 15 16:56:09 lappi kernel: [  155.939347]  }
Jan 15 16:56:09 lappi kernel: [  155.939351]  ... key      at: [<ffffffffa0064528>] __key.30654+0x0/0xfffffffffffea5e7 [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.939372]  ... acquired at:
Jan 15 16:56:09 lappi kernel: [  155.939375]    [<ffffffff8108a4b0>] check_usage_backwards+0x85/0x96
Jan 15 16:56:09 lappi kernel: [  155.939385]    [<ffffffff8108aca7>] mark_lock+0x105/0x247
Jan 15 16:56:09 lappi kernel: [  155.939393]    [<ffffffff8108ae5a>] mark_held_locks+0x71/0x99
Jan 15 16:56:09 lappi kernel: [  155.939402]    [<ffffffff8108b020>] trace_hardirqs_on_caller+0x19e/0x1ad
Jan 15 16:56:09 lappi kernel: [  155.939411]    [<ffffffff8108b03c>] trace_hardirqs_on+0xd/0xf
Jan 15 16:56:09 lappi kernel: [  155.939420]    [<ffffffffa02d0044>] usbip_hcd_giveback_urb+0x3f/0x48 [vhci_hcd]
Jan 15 16:56:09 lappi kernel: [  155.939429]    [<ffffffffa02d010a>] vhci_urb_dequeue+0xbd/0xce [vhci_hcd]
Jan 15 16:56:09 lappi kernel: [  155.939437]    [<ffffffffa000abac>] unlink1+0xcf/0xe2 [usbcore]
Jan 15 16:56:09 lappi kernel: [  155.939461]    [<ffffffffa000bc06>] usb_hcd_unlink_urb+0x66/0x87 [usbcore]
Jan 15 16:56:09 lappi kernel: [  155.939483]    [<ffffffffa000c3d3>] usb_unlink_urb+0x26/0x3c [usbcore]
Jan 15 16:56:09 lappi kernel: [  155.939506]    [<ffffffffa04e691f>] usb_stor_stop_transport+0x30/0x52 [usb_storage]
Jan 15 16:56:09 lappi kernel: [  155.939517]    [<ffffffffa04e5903>] command_abort+0x64/0x86 [usb_storage]
Jan 15 16:56:09 lappi kernel: [  155.939526]    [<ffffffffa0046a5a>] scsi_error_handler+0x2e4/0x5da [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.939548]    [<ffffffff8105fd89>] kthread+0xb1/0xb9
Jan 15 16:56:09 lappi kernel: [  155.939554]    [<ffffffff813c786c>] ret_from_fork+0x7c/0xb0
Jan 15 16:56:09 lappi kernel: [  155.939561] 
Jan 15 16:56:09 lappi kernel: [  155.939565] 
Jan 15 16:56:09 lappi kernel: [  155.939565] stack backtrace:
Jan 15 16:56:09 lappi kernel: [  155.939573] Pid: 5034, comm: scsi_eh_6 Tainted: G           O 3.7.2+ #17
Jan 15 16:56:09 lappi kernel: [  155.939577] Call Trace:
Jan 15 16:56:09 lappi kernel: [  155.939588]  [<ffffffff813b9471>] print_irq_inversion_bug.part.32+0x1a1/0x1b0
Jan 15 16:56:09 lappi kernel: [  155.939599]  [<ffffffff8108a4b0>] check_usage_backwards+0x85/0x96
Jan 15 16:56:09 lappi kernel: [  155.939610]  [<ffffffff8108a42b>] ? print_shortest_lock_dependencies+0x185/0x185
Jan 15 16:56:09 lappi kernel: [  155.939620]  [<ffffffff8108aca7>] mark_lock+0x105/0x247
Jan 15 16:56:09 lappi kernel: [  155.939630]  [<ffffffff8108ae5a>] mark_held_locks+0x71/0x99
Jan 15 16:56:09 lappi kernel: [  155.939640]  [<ffffffffa02d0044>] ? usbip_hcd_giveback_urb+0x3f/0x48 [vhci_hcd]
Jan 15 16:56:09 lappi kernel: [  155.939650]  [<ffffffff8108b020>] trace_hardirqs_on_caller+0x19e/0x1ad
Jan 15 16:56:09 lappi kernel: [  155.939660]  [<ffffffff8108b03c>] trace_hardirqs_on+0xd/0xf
Jan 15 16:56:09 lappi kernel: [  155.939669]  [<ffffffffa02d0044>] usbip_hcd_giveback_urb+0x3f/0x48 [vhci_hcd]
Jan 15 16:56:09 lappi kernel: [  155.939678]  [<ffffffffa02d010a>] vhci_urb_dequeue+0xbd/0xce [vhci_hcd]
Jan 15 16:56:09 lappi kernel: [  155.939704]  [<ffffffffa000abac>] unlink1+0xcf/0xe2 [usbcore]
Jan 15 16:56:09 lappi kernel: [  155.939732]  [<ffffffffa000bc06>] usb_hcd_unlink_urb+0x66/0x87 [usbcore]
Jan 15 16:56:09 lappi kernel: [  155.939758]  [<ffffffffa000c3d3>] usb_unlink_urb+0x26/0x3c [usbcore]
Jan 15 16:56:09 lappi kernel: [  155.939769]  [<ffffffffa04e691f>] usb_stor_stop_transport+0x30/0x52 [usb_storage]
Jan 15 16:56:09 lappi kernel: [  155.939779]  [<ffffffffa04e5903>] command_abort+0x64/0x86 [usb_storage]
Jan 15 16:56:09 lappi kernel: [  155.939806]  [<ffffffffa0046a5a>] scsi_error_handler+0x2e4/0x5da [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.939832]  [<ffffffffa0046776>] ? scsi_eh_get_sense+0x185/0x185 [scsi_mod]
Jan 15 16:56:09 lappi kernel: [  155.939840]  [<ffffffff8105fd89>] kthread+0xb1/0xb9
Jan 15 16:56:09 lappi kernel: [  155.939849]  [<ffffffff8105fcd8>] ? __kthread_parkme+0x65/0x65
Jan 15 16:56:09 lappi kernel: [  155.939857]  [<ffffffff813c786c>] ret_from_fork+0x7c/0xb0
Jan 15 16:56:09 lappi kernel: [  155.939865]  [<ffffffff8105fcd8>] ? __kthread_parkme+0x65/0x65
Jan 15 16:56:09 lappi kernel: [  155.939929] scsi 6:0:0:0: Device offlined - not ready after error recovery



diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig
index 199b1d4..b6c4c3b 100644
--- a/drivers/staging/usbip/Kconfig
+++ b/drivers/staging/usbip/Kconfig
@@ -43,3 +43,10 @@ config USBIP_DEBUG
 	default N
 	---help---
 	  This enables the debug messages from the USB/IP drivers.
+
+config USBIP_DEBUG_VERBOSE
+	bool "Verbose debug messages for USB/IP"
+	depends on USBIP_CORE
+	default N
+	---help---
+	  This enables the verbose debug messages from the USB/IP drivers.
diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile
index 9ecd615..9cf7469 100644
--- a/drivers/staging/usbip/Makefile
+++ b/drivers/staging/usbip/Makefile
@@ -1,4 +1,5 @@
 ccflags-$(CONFIG_USBIP_DEBUG) := -DDEBUG
+ccflags-$(CONFIG_USBIP_DEBUG_VERBOSE) := -DDEBUG_VERBOSE
 
 obj-$(CONFIG_USBIP_CORE) += usbip-core.o
 usbip-core-y := usbip_common.o usbip_event.o
diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h
index a73e437..d164be8 100644
--- a/drivers/staging/usbip/stub.h
+++ b/drivers/staging/usbip/stub.h
@@ -17,9 +17,6 @@
  * USA.
  */
 
-#ifndef __USBIP_STUB_H
-#define __USBIP_STUB_H
-
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -35,6 +32,7 @@
 struct stub_device {
 	struct usb_interface *interface;
 	struct usb_device *udev;
+	struct list_head list;
 
 	struct usbip_device ud;
 	__u32 devid;
@@ -46,18 +44,13 @@ struct stub_device {
 	 * stub_priv is always linked to any one of 3 lists;
 	 *	priv_init: linked to this until the comletion of a urb.
 	 *	priv_tx  : linked to this after the completion of a urb.
-	 *	priv_free: linked to this after the sending of the result.
 	 *
-	 * Any of these list operations should be locked by priv_lock.
+	 * Any of these list operations should be locked by list_lock.
 	 */
-	spinlock_t priv_lock;
+	spinlock_t lock;
+
 	struct list_head priv_init;
 	struct list_head priv_tx;
-	struct list_head priv_free;
-
-	/* see comments for unlinking in stub_rx.c */
-	struct list_head unlink_tx;
-	struct list_head unlink_free;
 
 	wait_queue_head_t tx_waitq;
 };
@@ -68,14 +61,6 @@ struct stub_priv {
 	struct list_head list;
 	struct stub_device *sdev;
 	struct urb *urb;
-
-	int unlinking;
-};
-
-struct stub_unlink {
-	unsigned long seqnum;
-	struct list_head list;
-	__u32 status;
 };
 
 /* same as SYSFS_BUS_ID_SIZE */
@@ -104,9 +89,5 @@ void stub_device_cleanup_urbs(struct stub_device *sdev);
 int stub_rx_loop(void *data);
 
 /* stub_tx.c */
-void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
-			     __u32 status);
 void stub_complete(struct urb *urb);
 int stub_tx_loop(void *data);
-
-#endif /* __USBIP_STUB_H */
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index c8d79a7..0706b31 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -18,6 +18,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/file.h>
 #include <linux/kthread.h>
 #include <linux/module.h>
 
@@ -59,18 +60,13 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr,
 			   char *buf)
 {
 	struct stub_device *sdev = dev_get_drvdata(dev);
-	int status;
 
 	if (!sdev) {
 		dev_err(dev, "sdev is null\n");
 		return -ENODEV;
 	}
 
-	spin_lock(&sdev->ud.lock);
-	status = sdev->ud.status;
-	spin_unlock(&sdev->ud.lock);
-
-	return snprintf(buf, PAGE_SIZE, "%d\n", status);
+	return snprintf(buf, PAGE_SIZE, "%d\n", sdev->ud.status);
 }
 static DEVICE_ATTR(usbip_status, S_IRUGO, show_status, NULL);
 
@@ -109,12 +105,17 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
 			spin_unlock(&sdev->ud.lock);
 			return -EINVAL;
 		}
+#if 0
+		setnodelay(socket);
+		setkeepalive(socket);
+		setreuse(socket);
+#endif
 		sdev->ud.tcp_socket = socket;
 
 		spin_unlock(&sdev->ud.lock);
 
-		sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud, "stub_rx");
-		sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud, "stub_tx");
+		sdev->ud.tcp_rx = kthread_run(stub_rx_loop, &sdev->ud, "stub_rx");
+		sdev->ud.tcp_tx = kthread_run(stub_tx_loop, &sdev->ud, "stub_tx");
 
 		spin_lock(&sdev->ud.lock);
 		sdev->ud.status = SDEV_ST_USED;
@@ -149,14 +150,8 @@ static int stub_add_files(struct device *dev)
 	if (err)
 		goto err_sockfd;
 
-	err = device_create_file(dev, &dev_attr_usbip_debug);
-	if (err)
-		goto err_debug;
-
 	return 0;
 
-err_debug:
-	device_remove_file(dev, &dev_attr_usbip_sockfd);
 err_sockfd:
 	device_remove_file(dev, &dev_attr_usbip_status);
 err_status:
@@ -167,13 +162,13 @@ static void stub_remove_files(struct device *dev)
 {
 	device_remove_file(dev, &dev_attr_usbip_status);
 	device_remove_file(dev, &dev_attr_usbip_sockfd);
-	device_remove_file(dev, &dev_attr_usbip_debug);
 }
 
 static void stub_shutdown_connection(struct usbip_device *ud)
 {
 	struct stub_device *sdev = container_of(ud, struct stub_device, ud);
 
+	usbip_dbg("shutdown\n");
 	/*
 	 * When removing an exported device, kernel panic sometimes occurred
 	 * and then EIP was sk_wait_data of stub_rx thread. Is this because
@@ -186,15 +181,13 @@ static void stub_shutdown_connection(struct usbip_device *ud)
 		kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
 	}
 
+	usbip_dbg("stop rx/tx threads\n");
+
 	/* 1. stop threads */
-	if (ud->tcp_rx) {
-		kthread_stop_put(ud->tcp_rx);
-		ud->tcp_rx = NULL;
-	}
-	if (ud->tcp_tx) {
-		kthread_stop_put(ud->tcp_tx);
-		ud->tcp_tx = NULL;
-	}
+	if (ud->tcp_rx && !task_is_dead(ud->tcp_rx))
+		kthread_stop(ud->tcp_rx);
+	if (ud->tcp_tx && !task_is_dead(ud->tcp_tx))
+		kthread_stop(ud->tcp_tx);
 
 	/*
 	 * 2. close the socket
@@ -202,31 +195,18 @@ static void stub_shutdown_connection(struct usbip_device *ud)
 	 * tcp_socket is freed after threads are killed so that usbip_xmit does
 	 * not touch NULL socket.
 	 */
+	usbip_dbg("release socket\n");
 	if (ud->tcp_socket) {
-		sock_release(ud->tcp_socket);
+		fput(ud->tcp_socket->file);
 		ud->tcp_socket = NULL;
 	}
 
+	usbip_dbg("stub_dev cleanup\n");
+
 	/* 3. free used data */
 	stub_device_cleanup_urbs(sdev);
 
-	/* 4. free stub_unlink */
-	{
-		unsigned long flags;
-		struct stub_unlink *unlink, *tmp;
-
-		spin_lock_irqsave(&sdev->priv_lock, flags);
-		list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
-			list_del(&unlink->list);
-			kfree(unlink);
-		}
-		list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free,
-					 list) {
-			list_del(&unlink->list);
-			kfree(unlink);
-		}
-		spin_unlock_irqrestore(&sdev->priv_lock, flags);
-	}
+	usbip_dbg("done\n");
 }
 
 static void stub_device_reset(struct usbip_device *ud)
@@ -304,12 +284,10 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev,
 	spin_lock_init(&sdev->ud.lock);
 	sdev->ud.tcp_socket	= NULL;
 
+	spin_lock_init(&sdev->lock);
+
 	INIT_LIST_HEAD(&sdev->priv_init);
 	INIT_LIST_HEAD(&sdev->priv_tx);
-	INIT_LIST_HEAD(&sdev->priv_free);
-	INIT_LIST_HEAD(&sdev->unlink_free);
-	INIT_LIST_HEAD(&sdev->unlink_tx);
-	spin_lock_init(&sdev->priv_lock);
 
 	init_waitqueue_head(&sdev->tx_waitq);
 
@@ -330,8 +308,6 @@ static int stub_device_free(struct stub_device *sdev)
 		return -EINVAL;
 
 	kfree(sdev);
-	pr_debug("kfree udev ok\n");
-
 	return 0;
 }
 
@@ -432,6 +408,8 @@ static int stub_probe(struct usb_interface *interface,
 		dev_err(&interface->dev, "stub_add_files for %s\n", udev_busid);
 		usb_set_intfdata(interface, NULL);
 		usb_put_intf(interface);
+		usb_put_dev(udev);
+		kthread_stop(sdev->ud.eh);
 
 		busid_priv->interf_count = 0;
 		busid_priv->sdev = NULL;
@@ -522,11 +500,11 @@ static void stub_disconnect(struct usb_interface *interface)
 	}
 }
 
-/*
+/* 
  * Presence of pre_reset and post_reset prevents the driver from being unbound
  * when the device is being reset
  */
-
+ 
 int stub_pre_reset(struct usb_interface *interface)
 {
 	dev_dbg(&interface->dev, "pre_reset\n");
@@ -546,4 +524,4 @@ struct usb_driver stub_driver = {
 	.id_table	= stub_table,
 	.pre_reset	= stub_pre_reset,
 	.post_reset	= stub_post_reset,
-};
+ };
diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c
index 705a9e5..14ef680 100644
--- a/drivers/staging/usbip/stub_main.c
+++ b/drivers/staging/usbip/stub_main.c
@@ -20,6 +20,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
+
 #include "usbip_common.h"
 #include "stub.h"
 
@@ -201,24 +202,18 @@ static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead)
 
 static struct stub_priv *stub_priv_pop(struct stub_device *sdev)
 {
-	unsigned long flags;
 	struct stub_priv *priv;
+	unsigned long flags;
 
-	spin_lock_irqsave(&sdev->priv_lock, flags);
-
+	spin_lock_irqsave(&sdev->lock, flags);
 	priv = stub_priv_pop_from_listhead(&sdev->priv_init);
 	if (priv)
 		goto done;
 
 	priv = stub_priv_pop_from_listhead(&sdev->priv_tx);
-	if (priv)
-		goto done;
-
-	priv = stub_priv_pop_from_listhead(&sdev->priv_free);
 
 done:
-	spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
+	spin_unlock_irqrestore(&sdev->lock, flags);
 	return priv;
 }
 
@@ -246,9 +241,8 @@ static int __init usbip_host_init(void)
 {
 	int ret;
 
-	init_busid_table();
-
 	stub_priv_cache = KMEM_CACHE(stub_priv, SLAB_HWCACHE_ALIGN);
+
 	if (!stub_priv_cache) {
 		pr_err("kmem_cache_create failed\n");
 		return -ENOMEM;
@@ -267,6 +261,7 @@ static int __init usbip_host_init(void)
 		goto err_create_file;
 	}
 
+	init_busid_table();
 	pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
 	return ret;
 
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
index 694cfd7..8b4611b 100644
--- a/drivers/staging/usbip/stub_rx.c
+++ b/drivers/staging/usbip/stub_rx.c
@@ -69,7 +69,7 @@ static int is_reset_device_cmd(struct urb *urb)
 	if ((req->bRequest == USB_REQ_SET_FEATURE) &&
 	    (req->bRequestType == USB_RT_PORT) &&
 	    (value == USB_PORT_FEAT_RESET)) {
-		usbip_dbg_stub_rx("reset_device_cmd, port %u\n", index);
+		usbip_dbg("reset_device_cmd, port %u\n", index);
 		return 1;
 	} else
 		return 0;
@@ -122,7 +122,7 @@ static int tweak_set_interface_cmd(struct urb *urb)
 	alternate = le16_to_cpu(req->wValue);
 	interface = le16_to_cpu(req->wIndex);
 
-	usbip_dbg_stub_rx("set_interface: inf %u alt %u\n",
+	usbip_dbg("set_interface: inf %u alt %u\n",
 			  interface, alternate);
 
 	ret = usb_set_interface(urb->dev, interface, alternate);
@@ -155,7 +155,7 @@ static int tweak_set_configuration_cmd(struct urb *urb)
 	 * eventually reassigned to the device as far as driver matching
 	 * condition is kept.
 	 *
-	 * Unfortunately, an existing usbip connection will be dropped
+	 * Unfortunatelly, an existing usbip connection will be dropped
 	 * due to this driver unbinding. So, skip here.
 	 * A user may need to set a special configuration value before
 	 * exporting the device.
@@ -200,107 +200,16 @@ static void tweak_special_requests(struct urb *urb)
 	if (usb_pipetype(urb->pipe) != PIPE_CONTROL)
 		return;
 
-	if (is_clear_halt_cmd(urb))
-		/* tweak clear_halt */
+	if (is_clear_halt_cmd(urb)) 
 		 tweak_clear_halt_cmd(urb);
-
-	else if (is_set_interface_cmd(urb))
-		/* tweak set_interface */
+	else if (is_set_interface_cmd(urb)) 
 		tweak_set_interface_cmd(urb);
-
 	else if (is_set_configuration_cmd(urb))
-		/* tweak set_configuration */
 		tweak_set_configuration_cmd(urb);
-
-	else if (is_reset_device_cmd(urb))
+	else if (is_reset_device_cmd(urb)) 
 		tweak_reset_device_cmd(urb);
-	else
-		usbip_dbg_stub_rx("no need to tweak\n");
 }
 
-/*
- * stub_recv_unlink() unlinks the URB by a call to usb_unlink_urb().
- * By unlinking the urb asynchronously, stub_rx can continuously
- * process coming urbs.  Even if the urb is unlinked, its completion
- * handler will be called and stub_tx will send a return pdu.
- *
- * See also comments about unlinking strategy in vhci_hcd.c.
- */
-static int stub_recv_cmd_unlink(struct stub_device *sdev,
-				struct usbip_header *pdu)
-{
-	unsigned long flags;
-
-	struct stub_priv *priv;
-
-	spin_lock_irqsave(&sdev->priv_lock, flags);
-
-	list_for_each_entry(priv, &sdev->priv_init, list) {
-		if (priv->seqnum == pdu->u.cmd_unlink.seqnum) {
-			int ret;
-
-			dev_info(&priv->urb->dev->dev, "unlink urb %p\n",
-				 priv->urb);
-
-			/*
-			 * This matched urb is not completed yet (i.e., be in
-			 * flight in usb hcd hardware/driver). Now we are
-			 * cancelling it. The unlinking flag means that we are
-			 * now not going to return the normal result pdu of a
-			 * submission request, but going to return a result pdu
-			 * of the unlink request.
-			 */
-			priv->unlinking = 1;
-
-			/*
-			 * In the case that unlinking flag is on, prev->seqnum
-			 * is changed from the seqnum of the cancelling urb to
-			 * the seqnum of the unlink request. This will be used
-			 * to make the result pdu of the unlink request.
-			 */
-			priv->seqnum = pdu->base.seqnum;
-
-			spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-			/*
-			 * usb_unlink_urb() is now out of spinlocking to avoid
-			 * spinlock recursion since stub_complete() is
-			 * sometimes called in this context but not in the
-			 * interrupt context.  If stub_complete() is executed
-			 * before we call usb_unlink_urb(), usb_unlink_urb()
-			 * will return an error value. In this case, stub_tx
-			 * will return the result pdu of this unlink request
-			 * though submission is completed and actual unlinking
-			 * is not executed. OK?
-			 */
-			/* In the above case, urb->status is not -ECONNRESET,
-			 * so a driver in a client host will know the failure
-			 * of the unlink request ?
-			 */
-			ret = usb_unlink_urb(priv->urb);
-			if (ret != -EINPROGRESS)
-				dev_err(&priv->urb->dev->dev,
-					"failed to unlink a urb %p, ret %d\n",
-					priv->urb, ret);
-			return 0;
-		}
-	}
-
-	usbip_dbg_stub_rx("seqnum %d is not pending\n",
-			  pdu->u.cmd_unlink.seqnum);
-
-	/*
-	 * The urb of the unlink target is not found in priv_init queue. It was
-	 * already completed and its results is/was going to be sent by a
-	 * CMD_RET pdu. In this case, usb_unlink_urb() is not needed. We only
-	 * return the completeness of this unlink request to vhci_hcd.
-	 */
-	stub_enqueue_ret_unlink(sdev, pdu->base.seqnum, 0);
-
-	spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-	return 0;
-}
 
 static int valid_request(struct stub_device *sdev, struct usbip_header *pdu)
 {
@@ -308,12 +217,10 @@ static int valid_request(struct stub_device *sdev, struct usbip_header *pdu)
 	int valid = 0;
 
 	if (pdu->base.devid == sdev->devid) {
-		spin_lock(&ud->lock);
 		if (ud->status == SDEV_ST_USED) {
 			/* A request is valid. */
 			valid = 1;
 		}
-		spin_unlock(&ud->lock);
 	}
 
 	return valid;
@@ -322,30 +229,22 @@ static int valid_request(struct stub_device *sdev, struct usbip_header *pdu)
 static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,
 					 struct usbip_header *pdu)
 {
-	struct stub_priv *priv;
 	struct usbip_device *ud = &sdev->ud;
+	struct stub_priv *priv;
 	unsigned long flags;
 
-	spin_lock_irqsave(&sdev->priv_lock, flags);
-
-	priv = kmem_cache_zalloc(stub_priv_cache, GFP_ATOMIC);
+	priv = kmem_cache_zalloc(stub_priv_cache, GFP_KERNEL);
 	if (!priv) {
 		dev_err(&sdev->interface->dev, "alloc stub_priv\n");
-		spin_unlock_irqrestore(&sdev->priv_lock, flags);
 		usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
 		return NULL;
 	}
-
 	priv->seqnum = pdu->base.seqnum;
 	priv->sdev = sdev;
 
-	/*
-	 * After a stub_priv is linked to a list_head,
-	 * our error handler can free allocated data.
-	 */
+	spin_lock_irqsave(&sdev->lock, flags);
 	list_add_tail(&priv->list, &sdev->priv_init);
-
-	spin_unlock_irqrestore(&sdev->priv_lock, flags);
+	spin_unlock_irqrestore(&sdev->lock, flags);
 
 	return priv;
 }
@@ -367,6 +266,15 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir)
 	}
 
 	epd = &ep->desc;
+#if 0
+	/* epnum 0 is always control */
+	if (epnum == 0) {
+		if (dir == USBIP_DIR_OUT)
+			return usb_sndctrlpipe(udev, 0);
+		else
+			return usb_rcvctrlpipe(udev, 0);
+	}
+#endif
 	if (usb_endpoint_xfer_control(epd)) {
 		if (dir == USBIP_DIR_OUT)
 			return usb_sndctrlpipe(udev, epnum);
@@ -406,12 +314,14 @@ static void masking_bogus_flags(struct urb *urb)
 	struct usb_device		*dev;
 	struct usb_host_endpoint	*ep;
 	int				is_out;
-	unsigned int	allowed;
+	unsigned int allowed;
+	unsigned int origin_flags;
+	const int pipetypes[4] = {
+		PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+	};
 
-	if (!urb || urb->hcpriv || !urb->complete)
-		return;
 	dev = urb->dev;
-	if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
+	if (dev->state < USB_STATE_UNAUTHENTICATED)
 		return;
 
 	ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
@@ -432,6 +342,13 @@ static void masking_bogus_flags(struct urb *urb)
 		is_out = usb_endpoint_dir_out(&ep->desc);
 	}
 
+	/* Check that the pipe's type matches the endpoint's type */
+	if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) {
+		dev_err(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
+			usb_pipetype(urb->pipe), pipetypes[xfertype]);
+		return;
+	}
+	
 	/* enforce simple/standard policy */
 	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT |
 		   URB_DIR_MASK | URB_FREE_BUFFER);
@@ -451,17 +368,27 @@ static void masking_bogus_flags(struct urb *urb)
 		allowed |= URB_ISO_ASAP;
 		break;
 	}
+
+	origin_flags = urb->transfer_flags;
 	urb->transfer_flags &= allowed;
+	
+	if (urb->transfer_flags != origin_flags)
+		usbip_dbg("orgin transfer_flags %d"
+			" != allowed transfer_flags %d\n",
+			origin_flags, 
+			urb->transfer_flags
+			);
 }
 
 static void stub_recv_cmd_submit(struct stub_device *sdev,
 				 struct usbip_header *pdu)
 {
-	int ret;
 	struct stub_priv *priv;
 	struct usbip_device *ud = &sdev->ud;
 	struct usb_device *udev = sdev->udev;
 	int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction);
+	int ret;
+	const unsigned char empty[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
 	priv = stub_priv_alloc(sdev, pdu);
 	if (!priv)
@@ -483,7 +410,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
 	/* set priv->urb->transfer_buffer */
 	if (pdu->u.cmd_submit.transfer_buffer_length > 0) {
 		priv->urb->transfer_buffer =
-			kzalloc(pdu->u.cmd_submit.transfer_buffer_length,
+			kmalloc(pdu->u.cmd_submit.transfer_buffer_length,
 				GFP_KERNEL);
 		if (!priv->urb->transfer_buffer) {
 			dev_err(&sdev->interface->dev, "malloc x_buff\n");
@@ -491,14 +418,20 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
 			return;
 		}
 	}
-
+		
 	/* set priv->urb->setup_packet */
-	priv->urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8,
-					  GFP_KERNEL);
-	if (!priv->urb->setup_packet) {
-		dev_err(&sdev->interface->dev, "allocate setup_packet\n");
-		usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
-		return;
+	if (memcmp(pdu->u.cmd_submit.setup, empty, 8)) {
+		priv->urb->setup_packet = kmemdup(pdu->u.cmd_submit.setup,
+						8,
+					  	GFP_KERNEL
+						);
+		if (!priv->urb->setup_packet) {
+			dev_err(&sdev->interface->dev,
+				"allocate setup_packet\n"
+				);
+			usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+			return;
+		}
 	}
 
 	/* set other members from the base header of pdu */
@@ -509,22 +442,26 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
 
 	usbip_pack_pdu(pdu, priv->urb, USBIP_CMD_SUBMIT, 0);
 
-
 	if (usbip_recv_xbuff(ud, priv->urb) < 0)
 		return;
-
 	if (usbip_recv_iso(ud, priv->urb) < 0)
 		return;
 
 	/* no need to submit an intercepted request, but harmless? */
 	tweak_special_requests(priv->urb);
-
 	masking_bogus_flags(priv->urb);
+
+	usbip_dump_urb(priv->urb);
+	
+	if (usb_pipeout(pipe) && priv->urb->transfer_buffer)
+		usbip_dump_buffer((char *)priv->urb->transfer_buffer,
+				priv->urb->transfer_buffer_length
+				);
+
 	/* urb is now ready to submit */
 	ret = usb_submit_urb(priv->urb, GFP_KERNEL);
-
 	if (ret == 0)
-		usbip_dbg_stub_rx("submit urb ok, seqnum %u\n",
+		usbip_dbg("submit urb ok, seqnum %u\n",
 				  pdu->base.seqnum);
 	else {
 		dev_err(&sdev->interface->dev, "submit_urb error, %d\n", ret);
@@ -538,10 +475,10 @@ static void stub_recv_cmd_submit(struct stub_device *sdev,
 		usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT);
 	}
 
-	usbip_dbg_stub_rx("Leave\n");
 	return;
 }
 
+
 /* recv a pdu */
 static void stub_rx_pdu(struct usbip_device *ud)
 {
@@ -550,12 +487,10 @@ static void stub_rx_pdu(struct usbip_device *ud)
 	struct stub_device *sdev = container_of(ud, struct stub_device, ud);
 	struct device *dev = &sdev->interface->dev;
 
-	usbip_dbg_stub_rx("Enter\n");
-
 	memset(&pdu, 0, sizeof(pdu));
 
 	/* 1. receive a pdu header */
-	ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
+	ret = usbip_xmit(0, ud->tcp_socket, (char *)&pdu, sizeof(pdu), 0);
 	if (ret != sizeof(pdu)) {
 		dev_err(dev, "recv a header, %d\n", ret);
 		usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
@@ -563,9 +498,7 @@ static void stub_rx_pdu(struct usbip_device *ud)
 	}
 
 	usbip_header_correct_endian(&pdu, 0);
-
-	if (usbip_dbg_flag_stub_rx)
-		usbip_dump_header(&pdu);
+	usbip_dump_header(&pdu);
 
 	if (!valid_request(sdev, &pdu)) {
 		dev_err(dev, "recv invalid request\n");
@@ -574,20 +507,15 @@ static void stub_rx_pdu(struct usbip_device *ud)
 	}
 
 	switch (pdu.base.command) {
-	case USBIP_CMD_UNLINK:
-		stub_recv_cmd_unlink(sdev, &pdu);
-		break;
-
 	case USBIP_CMD_SUBMIT:
 		stub_recv_cmd_submit(sdev, &pdu);
 		break;
-
 	default:
 		/* NOTREACHED */
 		dev_err(dev, "unknown pdu\n");
 		usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-		break;
-	}
+	break;
+}
 }
 
 int stub_rx_loop(void *data)
diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c
index 023fda3..bea7511 100644
--- a/drivers/staging/usbip/stub_tx.c
+++ b/drivers/staging/usbip/stub_tx.c
@@ -23,52 +23,33 @@
 #include "usbip_common.h"
 #include "stub.h"
 
+
 static void stub_free_priv_and_urb(struct stub_priv *priv)
 {
 	struct urb *urb = priv->urb;
+	struct stub_device *sdev = priv->sdev;
+	unsigned long flags;
 
-	kfree(urb->setup_packet);
-	kfree(urb->transfer_buffer);
+	spin_lock_irqsave(&sdev->lock, flags);
 	list_del(&priv->list);
+	spin_unlock_irqrestore(&sdev->lock, flags);
+
+	if (likely(urb->setup_packet))
+		kfree(urb->setup_packet);
+	if (likely(urb->transfer_buffer))
+		kfree(urb->transfer_buffer);
+
 	kmem_cache_free(stub_priv_cache, priv);
 	usb_free_urb(urb);
 }
 
-/* be in spin_lock_irqsave(&sdev->priv_lock, flags) */
-void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
-			     __u32 status)
-{
-	struct stub_unlink *unlink;
-
-	unlink = kzalloc(sizeof(struct stub_unlink), GFP_ATOMIC);
-	if (!unlink) {
-		dev_err(&sdev->interface->dev, "alloc stub_unlink\n");
-		usbip_event_add(&sdev->ud, VDEV_EVENT_ERROR_MALLOC);
-		return;
-	}
-
-	unlink->seqnum = seqnum;
-	unlink->status = status;
-
-	list_add_tail(&unlink->list, &sdev->unlink_tx);
-}
 
-/**
- * stub_complete - completion handler of a usbip urb
- * @urb: pointer to the urb completed
- *
- * When a urb has completed, the USB core driver calls this function mostly in
- * the interrupt context. To return the result of a urb, the completed urb is
- * linked to the pending list of returning.
- *
- */
 void stub_complete(struct urb *urb)
 {
 	struct stub_priv *priv = (struct stub_priv *) urb->context;
 	struct stub_device *sdev = priv->sdev;
-	unsigned long flags;
 
-	usbip_dbg_stub_tx("complete! status %d\n", urb->status);
+	usbip_dbg("complete! status %d\n", urb->status);
 
 	switch (urb->status) {
 	case 0:
@@ -85,6 +66,10 @@ void stub_complete(struct urb *urb)
 	case -EPIPE:
 		dev_info(&urb->dev->dev, "endpoint %d is stalled\n",
 			 usb_pipeendpoint(urb->pipe));
+
+		break;
+	case -EREMOTEIO:
+		dev_info(&urb->dev->dev, "remote io error\n");
 		break;
 	case -ESHUTDOWN:
 		dev_info(&urb->dev->dev, "device removed?\n");
@@ -95,17 +80,12 @@ void stub_complete(struct urb *urb)
 		break;
 	}
 
-	/* link a urb to the queue of tx. */
-	spin_lock_irqsave(&sdev->priv_lock, flags);
-	if (priv->unlinking) {
-		stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status);
-		stub_free_priv_and_urb(priv);
-	} else {
-		list_move_tail(&priv->list, &sdev->priv_tx);
-	}
-	spin_unlock_irqrestore(&sdev->priv_lock, flags);
+	/* urb completed, 
+	 * move it to the tx queue */
+	spin_lock(&sdev->lock);
+	list_move_tail(&priv->list, &sdev->priv_tx);
+	spin_unlock(&sdev->lock);
 
-	/* wake up tx_thread */
 	wake_up(&sdev->tx_waitq);
 }
 
@@ -127,46 +107,35 @@ static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urb *urb)
 	usbip_pack_pdu(rpdu, urb, USBIP_RET_SUBMIT, 1);
 }
 
-static void setup_ret_unlink_pdu(struct usbip_header *rpdu,
-				 struct stub_unlink *unlink)
-{
-	setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum);
-	rpdu->u.ret_unlink.status = unlink->status;
-}
-
-static struct stub_priv *dequeue_from_priv_tx(struct stub_device *sdev)
+static inline struct stub_priv * dequeue_tx_urb(struct stub_device *sdev)
 {
-	unsigned long flags;
 	struct stub_priv *priv, *tmp;
+	unsigned long flags;
 
-	spin_lock_irqsave(&sdev->priv_lock, flags);
-
+	spin_lock_irqsave(&sdev->lock, flags);
 	list_for_each_entry_safe(priv, tmp, &sdev->priv_tx, list) {
-		list_move_tail(&priv->list, &sdev->priv_free);
-		spin_unlock_irqrestore(&sdev->priv_lock, flags);
-		return priv;
+		goto out;
 	}
+	priv = NULL;
 
-	spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-	return NULL;
+out:
+	spin_unlock_irqrestore(&sdev->lock, flags);
+	return priv;
 }
 
 static int stub_send_ret_submit(struct stub_device *sdev)
 {
-	unsigned long flags;
-	struct stub_priv *priv, *tmp;
-
+	struct stub_priv *priv;
 	struct msghdr msg;
 	size_t txsize;
-
 	size_t total_size = 0;
 
-	while ((priv = dequeue_from_priv_tx(sdev)) != NULL) {
+	while ( (priv = dequeue_tx_urb(sdev)) ) {
+
 		int ret;
 		struct urb *urb = priv->urb;
 		struct usbip_header pdu_header;
-		void *iso_buffer = NULL;
+		struct usbip_iso_packet_descriptor *iso_buffer = NULL;
 		struct kvec *iov = NULL;
 		int iovnum = 0;
 
@@ -180,7 +149,6 @@ static int stub_send_ret_submit(struct stub_device *sdev)
 			iovnum = 2;
 
 		iov = kzalloc(iovnum * sizeof(struct kvec), GFP_KERNEL);
-
 		if (!iov) {
 			usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC);
 			return -1;
@@ -190,7 +158,7 @@ static int stub_send_ret_submit(struct stub_device *sdev)
 
 		/* 1. setup usbip_header */
 		setup_ret_submit_pdu(&pdu_header, urb);
-		usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n",
+		usbip_dbg("setup txdata seqnum: %d urb: %p\n",
 				  pdu_header.base.seqnum, urb);
 		/*usbip_dump_header(pdu_header);*/
 		usbip_header_correct_endian(&pdu_header, 1);
@@ -206,8 +174,13 @@ static int stub_send_ret_submit(struct stub_device *sdev)
 		    urb->actual_length > 0) {
 			iov[iovnum].iov_base = urb->transfer_buffer;
 			iov[iovnum].iov_len  = urb->actual_length;
+
+			usbip_dump_buffer((char *)iov[iovnum].iov_base, 
+					iov[iovnum].iov_len 
+					);
 			iovnum++;
 			txsize += urb->actual_length;
+
 		} else if (usb_pipein(urb->pipe) &&
 			   usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
 			/*
@@ -270,96 +243,16 @@ static int stub_send_ret_submit(struct stub_device *sdev)
 			usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
 			return -1;
 		}
-
 		kfree(iov);
 		kfree(iso_buffer);
-
-		total_size += txsize;
-	}
-
-	spin_lock_irqsave(&sdev->priv_lock, flags);
-	list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) {
 		stub_free_priv_and_urb(priv);
-	}
-	spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-	return total_size;
-}
-
-static struct stub_unlink *dequeue_from_unlink_tx(struct stub_device *sdev)
-{
-	unsigned long flags;
-	struct stub_unlink *unlink, *tmp;
-
-	spin_lock_irqsave(&sdev->priv_lock, flags);
-
-	list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
-		list_move_tail(&unlink->list, &sdev->unlink_free);
-		spin_unlock_irqrestore(&sdev->priv_lock, flags);
-		return unlink;
-	}
-
-	spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-	return NULL;
-}
-
-static int stub_send_ret_unlink(struct stub_device *sdev)
-{
-	unsigned long flags;
-	struct stub_unlink *unlink, *tmp;
-
-	struct msghdr msg;
-	struct kvec iov[1];
-	size_t txsize;
-
-	size_t total_size = 0;
-
-	while ((unlink = dequeue_from_unlink_tx(sdev)) != NULL) {
-		int ret;
-		struct usbip_header pdu_header;
-
-		txsize = 0;
-		memset(&pdu_header, 0, sizeof(pdu_header));
-		memset(&msg, 0, sizeof(msg));
-		memset(&iov, 0, sizeof(iov));
-
-		usbip_dbg_stub_tx("setup ret unlink %lu\n", unlink->seqnum);
-
-		/* 1. setup usbip_header */
-		setup_ret_unlink_pdu(&pdu_header, unlink);
-		usbip_header_correct_endian(&pdu_header, 1);
-
-		iov[0].iov_base = &pdu_header;
-		iov[0].iov_len  = sizeof(pdu_header);
-		txsize += sizeof(pdu_header);
-
-		ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov,
-				     1, txsize);
-		if (ret != txsize) {
-			dev_err(&sdev->interface->dev,
-				"sendmsg failed!, retval %d for %zd\n",
-				ret, txsize);
-			usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
-			return -1;
-		}
-
-		usbip_dbg_stub_tx("send txdata\n");
 		total_size += txsize;
 	}
 
-	spin_lock_irqsave(&sdev->priv_lock, flags);
-
-	list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free, list) {
-		list_del(&unlink->list);
-		kfree(unlink);
-	}
-
-	spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
 	return total_size;
 }
 
+
 int stub_tx_loop(void *data)
 {
 	struct usbip_device *ud = data;
@@ -369,30 +262,13 @@ int stub_tx_loop(void *data)
 		if (usbip_event_happened(ud))
 			break;
 
-		/*
-		 * send_ret_submit comes earlier than send_ret_unlink.  stub_rx
-		 * looks at only priv_init queue. If the completion of a URB is
-		 * earlier than the receive of CMD_UNLINK, priv is moved to
-		 * priv_tx queue and stub_rx does not find the target priv. In
-		 * this case, vhci_rx receives the result of the submit request
-		 * and then receives the result of the unlink request. The
-		 * result of the submit is given back to the usbcore as the
-		 * completion of the unlink request. The request of the
-		 * unlink is ignored. This is ok because a driver who calls
-		 * usb_unlink_urb() understands the unlink was too late by
-		 * getting the status of the given-backed URB which has the
-		 * status of usb_submit_urb().
-		 */
-		if (stub_send_ret_submit(sdev) < 0)
-			break;
-
-		if (stub_send_ret_unlink(sdev) < 0)
+		if ( (stub_send_ret_submit(sdev)) < 0)
 			break;
 
 		wait_event_interruptible(sdev->tx_waitq,
-					 (!list_empty(&sdev->priv_tx) ||
-					  !list_empty(&sdev->unlink_tx) ||
-					  kthread_should_stop()));
+					(!list_empty(&sdev->priv_tx)) ||
+					kthread_should_stop()
+					);
 	}
 
 	return 0;
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 57f11f9..01bd367 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -22,9 +22,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/stat.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <net/sock.h>
 
 #include "usbip_common.h"
@@ -32,37 +30,42 @@
 #define DRIVER_AUTHOR "Takahiro Hirofuchi <hirofuchi@xxxxxxxxxxxxxxxxxxxxx>"
 #define DRIVER_DESC "USB/IP Core"
 
-#ifdef CONFIG_USBIP_DEBUG
-unsigned long usbip_debug_flag = 0xffffffff;
-#else
-unsigned long usbip_debug_flag;
-#endif
-EXPORT_SYMBOL_GPL(usbip_debug_flag);
-module_param(usbip_debug_flag, ulong, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(usbip_debug_flag, "debug flags (defined in usbip_common.h)");
-
-/* FIXME */
-struct device_attribute dev_attr_usbip_debug;
-EXPORT_SYMBOL_GPL(dev_attr_usbip_debug);
-
-static ssize_t show_flag(struct device *dev, struct device_attribute *attr,
-			 char *buf)
-{
-	return sprintf(buf, "%lx\n", usbip_debug_flag);
-}
 
-static ssize_t store_flag(struct device *dev, struct device_attribute *attr,
-			  const char *buf, size_t count)
-{
-	sscanf(buf, "%lx", &usbip_debug_flag);
-	return count;
-}
-DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag);
+EXPORT_SYMBOL_GPL(usbip_dump_urb);
+EXPORT_SYMBOL_GPL(usbip_dump_header);
+EXPORT_SYMBOL_GPL(usbip_dump_buffer);
 
-static void usbip_dump_buffer(char *buff, int bufflen)
+#ifdef DEBUG_VERBOSE
+void usbip_dump_buffer(unsigned char *buff, int bufflen)
 {
-	print_hex_dump(KERN_DEBUG, "usbip-core", DUMP_PREFIX_OFFSET, 16, 4,
-		       buff, bufflen, false);
+	int i,j;
+	char linebuf[80];
+	int pos=0;
+
+	usbip_dbg("\n");
+	
+	for (i=0; i<bufflen; i+=16) {
+		pos+=sprintf(linebuf+pos,"%8i: ",i);
+		for (j=i; j<i+16; j++) {
+			if (j<bufflen)
+				pos+=sprintf(linebuf+pos,"%02X ",(int)(buff)[j]);
+			else
+				pos+=sprintf(linebuf+pos,"   ");
+		}
+		for (j=i; j<i+16; j++) {
+			if (j<bufflen)
+				pos+=sprintf(linebuf+pos,
+					"%c",
+					(buff[j]>=32&&buff[j]<128)
+					? ((char*)buff)[j]:'.'
+					);
+			else
+				pos+=sprintf(linebuf+pos," ");
+		}
+		pos+=sprintf(linebuf+pos,"\n");
+		printk("%s",linebuf);
+		pos=0;
+	}
 }
 
 static void usbip_dump_pipe(unsigned int p)
@@ -161,7 +164,8 @@ static void usbip_dump_usb_device(struct usb_device *udev)
 	dev_dbg(dev, "have_langid %d, string_langid %d\n",
 		udev->have_langid, udev->string_langid);
 
-	dev_dbg(dev, "maxchild %d\n", udev->maxchild);
+	dev_dbg(dev, "maxchild %d, children %p\n",
+		udev->maxchild, udev->children);
 }
 
 static void usbip_dump_request_type(__u8 rt)
@@ -267,7 +271,7 @@ void usbip_dump_urb(struct urb *urb)
 	dev_dbg(dev, "   urb                   :%p\n", urb);
 	dev_dbg(dev, "   dev                   :%p\n", urb->dev);
 
-	usbip_dump_usb_device(urb->dev);
+	//usbip_dump_usb_device(urb->dev);
 
 	dev_dbg(dev, "   pipe                  :%08x ", urb->pipe);
 
@@ -292,7 +296,6 @@ void usbip_dump_urb(struct urb *urb)
 	dev_dbg(dev, "   context               :%p\n", urb->context);
 	dev_dbg(dev, "   complete              :%p\n", urb->complete);
 }
-EXPORT_SYMBOL_GPL(usbip_dump_urb);
 
 void usbip_dump_header(struct usbip_header *pdu)
 {
@@ -335,22 +338,35 @@ void usbip_dump_header(struct usbip_header *pdu)
 		break;
 	}
 }
-EXPORT_SYMBOL_GPL(usbip_dump_header);
 
-/* Receive data over TCP/IP. */
-int usbip_recv(struct socket *sock, void *buf, int size)
+#else	/* NO DEBUG_VERBOSE */
+
+void usbip_dump_urb(struct urb *urb)
+{
+}
+
+void usbip_dump_header(struct usbip_header *pdu)
+{
+}
+
+void usbip_dump_buffer(unsigned char *buff, int bufflen)
+{
+}
+
+#endif	 /* DEBUG_VERBOSE */
+
+
+/*
+ * Send/receive messages over TCP/IP. I refer drivers/block/nbd.c
+ */
+int usbip_xmit(int send, struct socket *sock, char *buf, int size,
+	       int msg_flags)
 {
 	int result;
 	struct msghdr msg;
 	struct kvec iov;
 	int total = 0;
 
-	/* for blocks of if (usbip_dbg_flag_xmit) */
-	char *bp = buf;
-	int osize = size;
-
-	usbip_dbg_xmit("enter\n");
-
 	if (!sock || !buf || !size) {
 		pr_err("invalid arg, sock %p buff %p size %d\n", sock, buf,
 		       size);
@@ -366,38 +382,33 @@ int usbip_recv(struct socket *sock, void *buf, int size)
 		msg.msg_control = NULL;
 		msg.msg_controllen = 0;
 		msg.msg_namelen    = 0;
-		msg.msg_flags      = MSG_NOSIGNAL;
+		msg.msg_flags      = msg_flags | MSG_NOSIGNAL;
+
+		if (send)
+			result = kernel_sendmsg(sock, &msg, &iov, 1, size);
+		else
+			result = kernel_recvmsg(sock, &msg, &iov, 1, size,
+						MSG_WAITALL);
 
-		result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL);
 		if (result <= 0) {
-			pr_debug("receive sock %p buf %p size %u ret %d total %d\n",
-				 sock, buf, size, result, total);
+			pr_debug("%s sock %p buf %p size %u ret %d total %d\n",
+				 send ? "send" : "receive", sock, buf, size,
+				 result, total);
 			goto err;
 		}
 
 		size -= result;
 		buf += result;
 		total += result;
-	} while (size > 0);
-
-	if (usbip_dbg_flag_xmit) {
-		if (!in_interrupt())
-			pr_debug("%-10s:", current->comm);
-		else
-			pr_debug("interrupt  :");
 
-		pr_debug("receiving....\n");
-		usbip_dump_buffer(bp, osize);
-		pr_debug("received, osize %d ret %d size %d total %d\n",
-			osize, result, size, total);
-	}
+	} while (size > 0);
 
 	return total;
 
 err:
 	return result;
 }
-EXPORT_SYMBOL_GPL(usbip_recv);
+EXPORT_SYMBOL_GPL(usbip_xmit);
 
 struct socket *sockfd_to_socket(unsigned int sockfd)
 {
@@ -413,8 +424,10 @@ struct socket *sockfd_to_socket(unsigned int sockfd)
 
 	inode = file->f_dentry->d_inode;
 
-	if (!inode || !S_ISSOCK(inode->i_mode))
+	if (!inode || !S_ISSOCK(inode->i_mode)) {
+		fput(file);
 		return NULL;
+	}
 
 	socket = SOCKET_I(inode);
 
@@ -423,9 +436,10 @@ struct socket *sockfd_to_socket(unsigned int sockfd)
 EXPORT_SYMBOL_GPL(sockfd_to_socket);
 
 /* there may be more cases to tweak the flags. */
-static unsigned int tweak_transfer_flags(unsigned int flags)
+static inline unsigned int tweak_transfer_flags(unsigned int flags)
 {
 	flags &= ~URB_NO_TRANSFER_DMA_MAP;
+	//flags |= URB_SHORT_NOT_OK;
 	return flags;
 }
 
@@ -639,28 +653,26 @@ static void usbip_pack_iso(struct usbip_iso_packet_descriptor *iso,
 }
 
 /* must free buffer */
-void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen)
+struct usbip_iso_packet_descriptor*
+usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen)
 {
-	void *buff;
 	struct usbip_iso_packet_descriptor *iso;
 	int np = urb->number_of_packets;
 	ssize_t size = np * sizeof(*iso);
 	int i;
 
-	buff = kzalloc(size, GFP_KERNEL);
-	if (!buff)
+	iso = kzalloc(size, GFP_KERNEL);
+	if (!iso)
 		return NULL;
 
 	for (i = 0; i < np; i++) {
-		iso = buff + (i * sizeof(*iso));
-
-		usbip_pack_iso(iso, &urb->iso_frame_desc[i], 1);
-		usbip_iso_packet_correct_endian(iso, 1);
+		usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 1);
+		usbip_iso_packet_correct_endian(&iso[i], 1);
 	}
 
 	*bufflen = size;
 
-	return buff;
+	return iso;
 }
 EXPORT_SYMBOL_GPL(usbip_alloc_iso_desc_pdu);
 
@@ -689,7 +701,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
 	if (!buff)
 		return -ENOMEM;
 
-	ret = usbip_recv(ud->tcp_socket, buff, size);
+	ret = usbip_xmit(0, ud->tcp_socket, buff, size, 0);
 	if (ret != size) {
 		dev_err(&urb->dev->dev, "recv iso_frame_descriptor, %d\n",
 			ret);
@@ -703,11 +715,12 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
 		return -EPIPE;
 	}
 
+	iso = (struct usbip_iso_packet_descriptor *) buff;
 	for (i = 0; i < np; i++) {
 		iso = buff + (i * sizeof(*iso));
 
-		usbip_iso_packet_correct_endian(iso, 0);
-		usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0);
+		usbip_iso_packet_correct_endian(&iso[i], 0);
+		usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0);
 		total_length += urb->iso_frame_desc[i].actual_length;
 	}
 
@@ -738,25 +751,26 @@ EXPORT_SYMBOL_GPL(usbip_recv_iso);
  * buffer and iso packets need to be stored and be in propeper endian in urb
  * before calling this function
  */
-void usbip_pad_iso(struct usbip_device *ud, struct urb *urb)
+int usbip_pad_iso(struct usbip_device *ud, struct urb *urb)
 {
 	int np = urb->number_of_packets;
 	int i;
+	int ret;
 	int actualoffset = urb->actual_length;
 
 	if (!usb_pipeisoc(urb->pipe))
-		return;
+		return 0;
 
 	/* if no packets or length of data is 0, then nothing to unpack */
 	if (np == 0 || urb->actual_length == 0)
-		return;
+		return 0;
 
 	/*
 	 * if actual_length is transfer_buffer_length then no padding is
 	 * present.
 	*/
 	if (urb->actual_length == urb->transfer_buffer_length)
-		return;
+		return 0;
 
 	/*
 	 * loop over all packets from last to first (to prevent overwritting
@@ -768,6 +782,8 @@ void usbip_pad_iso(struct usbip_device *ud, struct urb *urb)
 			urb->transfer_buffer + actualoffset,
 			urb->iso_frame_desc[i].actual_length);
 	}
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(usbip_pad_iso);
 
@@ -778,6 +794,7 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
 	int size;
 
 	if (ud->side == USBIP_STUB) {
+
 		/* stub_rx.c */
 		/* the direction of urb must be OUT. */
 		if (usb_pipein(urb->pipe))
@@ -797,7 +814,8 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
 	if (!(size > 0))
 		return 0;
 
-	ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
+	ret = usbip_xmit(0, ud->tcp_socket, (char *)urb->transfer_buffer,
+			 size, 0);
 	if (ret != size) {
 		dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
 		if (ud->side == USBIP_STUB) {
@@ -823,6 +841,7 @@ static void __exit usbip_core_exit(void)
 	return;
 }
 
+
 module_init(usbip_core_init);
 module_exit(usbip_core_exit);
 
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
index 5d89c0f..a2392e8 100644
--- a/drivers/staging/usbip/usbip_common.h
+++ b/drivers/staging/usbip/usbip_common.h
@@ -32,76 +32,29 @@
 
 #define USBIP_VERSION "1.0.0"
 
-#undef pr_fmt
-
 #ifdef DEBUG
-#define pr_fmt(fmt)     KBUILD_MODNAME ": %s:%d: " fmt, __func__, __LINE__
+#define usbip_dbg(fmt, args...) \
+	printk(KBUILD_MODNAME ": %s:%d: " fmt, __func__, __LINE__, ##args)
+
+#else 
+#define usbip_dbg(fmt, args...)	
+#endif
+
+#ifdef DEBUG_VERBOSE
+#define usbip_dbg_verbose(fmt, args...) \
+	printk(KBUILD_MODNAME ": %s:%d: " fmt, __func__, __LINE__, ##args)
 #else
-#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
+#define usbip_dbg_verbose(fmt, args...)	
 #endif
 
-enum {
-	usbip_debug_xmit	= (1 << 0),
-	usbip_debug_sysfs	= (1 << 1),
-	usbip_debug_urb		= (1 << 2),
-	usbip_debug_eh		= (1 << 3),
-
-	usbip_debug_stub_cmp	= (1 << 8),
-	usbip_debug_stub_dev	= (1 << 9),
-	usbip_debug_stub_rx	= (1 << 10),
-	usbip_debug_stub_tx	= (1 << 11),
-
-	usbip_debug_vhci_rh	= (1 << 8),
-	usbip_debug_vhci_hc	= (1 << 9),
-	usbip_debug_vhci_rx	= (1 << 10),
-	usbip_debug_vhci_tx	= (1 << 11),
-	usbip_debug_vhci_sysfs  = (1 << 12)
-};
 
-#define usbip_dbg_flag_xmit	(usbip_debug_flag & usbip_debug_xmit)
-#define usbip_dbg_flag_vhci_rh	(usbip_debug_flag & usbip_debug_vhci_rh)
-#define usbip_dbg_flag_vhci_hc	(usbip_debug_flag & usbip_debug_vhci_hc)
-#define usbip_dbg_flag_vhci_rx	(usbip_debug_flag & usbip_debug_vhci_rx)
-#define usbip_dbg_flag_vhci_tx	(usbip_debug_flag & usbip_debug_vhci_tx)
-#define usbip_dbg_flag_stub_rx	(usbip_debug_flag & usbip_debug_stub_rx)
-#define usbip_dbg_flag_stub_tx	(usbip_debug_flag & usbip_debug_stub_tx)
-#define usbip_dbg_flag_vhci_sysfs  (usbip_debug_flag & usbip_debug_vhci_sysfs)
-
-extern unsigned long usbip_debug_flag;
-extern struct device_attribute dev_attr_usbip_debug;
-
-#define usbip_dbg_with_flag(flag, fmt, args...)		\
-	do {						\
-		if (flag & usbip_debug_flag)		\
-			pr_debug(fmt, ##args);		\
-	} while (0)
-
-#define usbip_dbg_sysfs(fmt, args...) \
-	usbip_dbg_with_flag(usbip_debug_sysfs, fmt , ##args)
-#define usbip_dbg_xmit(fmt, args...) \
-	usbip_dbg_with_flag(usbip_debug_xmit, fmt , ##args)
-#define usbip_dbg_urb(fmt, args...) \
-	usbip_dbg_with_flag(usbip_debug_urb, fmt , ##args)
-#define usbip_dbg_eh(fmt, args...) \
-	usbip_dbg_with_flag(usbip_debug_eh, fmt , ##args)
-
-#define usbip_dbg_vhci_rh(fmt, args...)	\
-	usbip_dbg_with_flag(usbip_debug_vhci_rh, fmt , ##args)
-#define usbip_dbg_vhci_hc(fmt, args...)	\
-	usbip_dbg_with_flag(usbip_debug_vhci_hc, fmt , ##args)
-#define usbip_dbg_vhci_rx(fmt, args...)	\
-	usbip_dbg_with_flag(usbip_debug_vhci_rx, fmt , ##args)
-#define usbip_dbg_vhci_tx(fmt, args...)	\
-	usbip_dbg_with_flag(usbip_debug_vhci_tx, fmt , ##args)
-#define usbip_dbg_vhci_sysfs(fmt, args...) \
-	usbip_dbg_with_flag(usbip_debug_vhci_sysfs, fmt , ##args)
-
-#define usbip_dbg_stub_cmp(fmt, args...) \
-	usbip_dbg_with_flag(usbip_debug_stub_cmp, fmt , ##args)
-#define usbip_dbg_stub_rx(fmt, args...) \
-	usbip_dbg_with_flag(usbip_debug_stub_rx, fmt , ##args)
-#define usbip_dbg_stub_tx(fmt, args...) \
-	usbip_dbg_with_flag(usbip_debug_stub_tx, fmt , ##args)
+#define usbip_info(fmt, args...) \
+	pr_info(KBUILD_MODNAME ": " fmt, ##args)
+
+#define usbip_err(fmt, args...) \
+	pr_err(KBUILD_MODNAME ": " fmt, ##args)
+
+
 
 /*
  * USB/IP request headers
@@ -189,6 +142,14 @@ struct usbip_header_ret_submit {
 } __packed;
 
 /**
+ *  * struct usbip_header_ret_unlink - USBIP_RET_UNLINK packet header
+ *   * @status: return status of the request
+ *    */
+struct usbip_header_ret_unlink {
+	        __s32 status;
+} __packed;
+
+/**
  * struct usbip_header_cmd_unlink - USBIP_CMD_UNLINK packet header
  * @seqnum: the URB seqnum to unlink
  */
@@ -197,14 +158,6 @@ struct usbip_header_cmd_unlink {
 } __packed;
 
 /**
- * struct usbip_header_ret_unlink - USBIP_RET_UNLINK packet header
- * @status: return status of the request
- */
-struct usbip_header_ret_unlink {
-	__s32 status;
-} __packed;
-
-/**
  * struct usbip_header - common header for all usbip packets
  * @base: the basic header
  * @u: packet type dependent header
@@ -292,38 +245,26 @@ struct usbip_device {
 	} eh_ops;
 };
 
-#define kthread_get_run(threadfn, data, namefmt, ...)			   \
-({									   \
-	struct task_struct *__k						   \
-		= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
-	if (!IS_ERR(__k)) {						   \
-		get_task_struct(__k);					   \
-		wake_up_process(__k);					   \
-	}								   \
-	__k;								   \
-})
-
-#define kthread_stop_put(k)		\
-	do {				\
-		kthread_stop(k);	\
-		put_task_struct(k);	\
-	} while (0)
 
 /* usbip_common.c */
 void usbip_dump_urb(struct urb *purb);
 void usbip_dump_header(struct usbip_header *pdu);
+void usbip_dump_buffer(unsigned char *buff, int bufflen);
 
-int usbip_recv(struct socket *sock, void *buf, int size);
+int usbip_xmit(int send, struct socket *sock, char *buf, int size,
+	       int msg_flags);
 struct socket *sockfd_to_socket(unsigned int sockfd);
 
 void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
 		    int pack);
 void usbip_header_correct_endian(struct usbip_header *pdu, int send);
 
-void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen);
+struct usbip_iso_packet_descriptor*
+usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen);
+
 /* some members of urb must be substituted before. */
 int usbip_recv_iso(struct usbip_device *ud, struct urb *urb);
-void usbip_pad_iso(struct usbip_device *ud, struct urb *urb);
+int usbip_pad_iso(struct usbip_device *ud, struct urb *urb);
 int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb);
 
 /* usbip_event.c */
@@ -344,4 +285,9 @@ static inline int interface_to_devnum(struct usb_interface *interface)
 	return udev->devnum;
 }
 
+static inline int interface_to_infnum(struct usb_interface *interface)
+{
+	return interface->cur_altsetting->desc.bInterfaceNumber;
+}
+
 #endif /* __USBIP_COMMON_H */
diff --git a/drivers/staging/usbip/usbip_event.c b/drivers/staging/usbip/usbip_event.c
index d332a34..75bb683 100644
--- a/drivers/staging/usbip/usbip_event.c
+++ b/drivers/staging/usbip/usbip_event.c
@@ -18,19 +18,17 @@
  */
 
 #include <linux/kthread.h>
-#include <linux/export.h>
+#include <linux/module.h>
 
 #include "usbip_common.h"
 
 static int event_handler(struct usbip_device *ud)
 {
-	usbip_dbg_eh("enter\n");
-
 	/*
 	 * Events are handled by only this thread.
 	 */
 	while (usbip_event_happened(ud)) {
-		usbip_dbg_eh("pending event %lx\n", ud->event);
+		usbip_dbg("pending event %lx\n", ud->event);
 
 		/*
 		 * NOTE: shutdown must come first.
@@ -69,11 +67,12 @@ static int event_handler_loop(void *data)
 		wait_event_interruptible(ud->eh_waitq,
 					 usbip_event_happened(ud) ||
 					 kthread_should_stop());
-		usbip_dbg_eh("wakeup\n");
+		usbip_dbg("wakeup\n");
 
 		if (event_handler(ud) < 0)
 			break;
 	}
+	usbip_dbg("done\n");
 
 	return 0;
 }
@@ -99,28 +98,24 @@ void usbip_stop_eh(struct usbip_device *ud)
 		return; /* do not wait for myself */
 
 	kthread_stop(ud->eh);
-	usbip_dbg_eh("usbip_eh has finished\n");
+	usbip_dbg("usbip_eh has finished\n");
 }
 EXPORT_SYMBOL_GPL(usbip_stop_eh);
 
 void usbip_event_add(struct usbip_device *ud, unsigned long event)
 {
-	spin_lock(&ud->lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ud->lock, flags);
 	ud->event |= event;
+	spin_unlock_irqrestore(&ud->lock, flags);
+
 	wake_up(&ud->eh_waitq);
-	spin_unlock(&ud->lock);
 }
 EXPORT_SYMBOL_GPL(usbip_event_add);
 
 int usbip_event_happened(struct usbip_device *ud)
 {
-	int happened = 0;
-
-	spin_lock(&ud->lock);
-	if (ud->event != 0)
-		happened = 1;
-	spin_unlock(&ud->lock);
-
-	return happened;
+	return ud->event;
 }
 EXPORT_SYMBOL_GPL(usbip_event_happened);
diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h
index c66b8b3..8c4d921 100644
--- a/drivers/staging/usbip/vhci.h
+++ b/drivers/staging/usbip/vhci.h
@@ -8,9 +8,6 @@
  *
  */
 
-#ifndef __USBIP_VHCI_H
-#define __USBIP_VHCI_H
-
 #include <linux/device.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
@@ -43,10 +40,7 @@ struct vhci_device {
 	/* vhci_priv is linked to one of them. */
 	struct list_head priv_tx;
 	struct list_head priv_rx;
-
-	/* vhci_unlink is linked to one of them */
-	struct list_head unlink_tx;
-	struct list_head unlink_rx;
+	struct list_head unlinked_urbs;
 
 	/* vhci_tx thread sleeps for this queue */
 	wait_queue_head_t waitq_tx;
@@ -54,24 +48,24 @@ struct vhci_device {
 
 /* urb->hcpriv, use container_of() */
 struct vhci_priv {
-	unsigned long seqnum;
 	struct list_head list;
-
 	struct vhci_device *vdev;
 	struct urb *urb;
+	unsigned long seqnum;
 };
 
-struct vhci_unlink {
-	/* seqnum of this request */
+struct unlink_urb {
+	struct urb *urb;
 	unsigned long seqnum;
-
 	struct list_head list;
-
-	/* seqnum of the unlink target */
-	unsigned long unlink_seqnum;
 };
 
-/* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */
+/*
+ * The number of ports is less than 16 ?
+ * USB_MAXCHILDREN is statically defined to 16 in usb.h.  Its maximum value
+ * would be 31 because the event_bits[1] of struct usb_hub is defined as
+ * unsigned long in hub.h
+ */
 #define VHCI_NPORTS 8
 
 /* for usb_bus.hcpriv */
@@ -79,17 +73,8 @@ struct vhci_hcd {
 	spinlock_t lock;
 
 	u32 port_status[VHCI_NPORTS];
-
-	unsigned resuming:1;
-	unsigned long re_timeout;
-
 	atomic_t seqnum;
 
-	/*
-	 * NOTE:
-	 * wIndex shows the port number and begins from 1.
-	 * But, the index of this array begins from 0.
-	 */
 	struct vhci_device vdev[VHCI_NPORTS];
 };
 
@@ -99,10 +84,9 @@ extern const struct attribute_group dev_attr_group;
 
 /* vhci_hcd.c */
 void rh_port_connect(int rhport, enum usb_device_speed speed);
-void rh_port_disconnect(int rhport);
+void usbip_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status);
 
 /* vhci_rx.c */
-struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum);
 int vhci_rx_loop(void *data);
 
 /* vhci_tx.c */
@@ -127,5 +111,3 @@ static inline struct device *vhci_dev(struct vhci_hcd *vhci)
 {
 	return vhci_to_hcd(vhci)->self.controller;
 }
-
-#endif /* __USBIP_VHCI_H */
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index 620d1be..75c4280 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -18,11 +18,13 @@
  */
 
 #include <linux/init.h>
+#include <linux/file.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
 
 #include "usbip_common.h"
 #include "vhci.h"
@@ -52,6 +54,7 @@ static int vhci_start(struct usb_hcd *vhci_hcd);
 static void vhci_stop(struct usb_hcd *hcd);
 static int vhci_get_frame_number(struct usb_hcd *hcd);
 
+
 static const char driver_name[] = "vhci_hcd";
 static const char driver_desc[] = "USB/IP Virtual Host Controller";
 
@@ -92,81 +95,46 @@ static const char * const bit_desc[] = {
 	"R31",			/*31*/
 };
 
-static void dump_port_status_diff(u32 prev_status, u32 new_status)
-{
-	int i = 0;
-	u32 bit = 1;
-
-	pr_debug("status prev -> new: %08x -> %08x\n", prev_status, new_status);
-	while (bit) {
-		u32 prev = prev_status & bit;
-		u32 new = new_status & bit;
-		char change;
-
-		if (!prev && new)
-			change = '+';
-		else if (prev && !new)
-			change = '-';
-		else
-			change = ' ';
-
-		if (prev || new)
-			pr_debug(" %c%s\n", change, bit_desc[i]);
-		bit <<= 1;
-		i++;
-	}
-	pr_debug("\n");
-}
 
 void rh_port_connect(int rhport, enum usb_device_speed speed)
 {
-	unsigned long	flags;
+	u32 pstate = the_controller->port_status[rhport];
 
-	usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport);
+	usbip_dbg("rh_port_connect %d\n", rhport);
 
-	spin_lock_irqsave(&the_controller->lock, flags);
-
-	the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
-		| (1 << USB_PORT_FEAT_C_CONNECTION);
+	pstate |= USB_PORT_STAT_CONNECTION | (1 << USB_PORT_FEAT_C_CONNECTION);
 
 	switch (speed) {
 	case USB_SPEED_HIGH:
-		the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED;
+		pstate |= USB_PORT_STAT_HIGH_SPEED;
 		break;
 	case USB_SPEED_LOW:
-		the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED;
+		pstate |= USB_PORT_STAT_LOW_SPEED;
 		break;
 	default:
 		break;
 	}
 
+	the_controller->port_status[rhport] = pstate;
+
 	/* spin_lock(&the_controller->vdev[rhport].ud.lock);
 	 * the_controller->vdev[rhport].ud.status = VDEV_CONNECT;
 	 * spin_unlock(&the_controller->vdev[rhport].ud.lock); */
 
-	spin_unlock_irqrestore(&the_controller->lock, flags);
-
 	usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
 }
 
-void rh_port_disconnect(int rhport)
+static void rh_port_disconnect(int rhport)
 {
-	unsigned long flags;
+	u32 pstate = the_controller->port_status[rhport];
 
-	usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
+	usbip_dbg("rh_port_disconnect %d\n", rhport);
 
-	spin_lock_irqsave(&the_controller->lock, flags);
-	/* stop_activity(dum, driver); */
-	the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
-	the_controller->port_status[rhport] |=
-					(1 << USB_PORT_FEAT_C_CONNECTION);
+	pstate &= ~USB_PORT_STAT_CONNECTION;
+	pstate |= (1 << USB_PORT_FEAT_C_CONNECTION);
 
-	/* not yet complete the disconnection
-	 * spin_lock(&vdev->ud.lock);
-	 * vdev->ud.status = VHC_ST_DISCONNECT;
-	 * spin_unlock(&vdev->ud.lock); */
+	the_controller->port_status[rhport] = pstate;
 
-	spin_unlock_irqrestore(&the_controller->lock, flags);
 	usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
 }
 
@@ -178,54 +146,63 @@ void rh_port_disconnect(int rhport)
 	  | USB_PORT_STAT_C_RESET) << 16)
 
 /*
- * Returns 0 if the status hasn't changed, or the number of bytes in buf.
- * Ports are 0-indexed from the HCD point of view,
- * and 1-indexed from the USB core pointer of view.
+ * This function is almostly the same as dummy_hcd.c:dummy_hub_status() without
+ * suspend/resume support. But, it is modified to provide multiple ports.
  *
  * @buf: a bitmap to show which port status has been changed.
- *  bit  0: reserved
+ *  bit  0: reserved or used for another purpose?
  *  bit  1: the status of port 0 has been changed.
  *  bit  2: the status of port 1 has been changed.
  *  ...
+ *  bit  7: the status of port 6 has been changed.
+ *  bit  8: the status of port 7 has been changed.
+ *  ...
+ *  bit 15: the status of port 14 has been changed.
+ *
+ * So, the maximum number of ports is 31 ( port 0 to port 30) ?
+ *
+ * The return value is the actual transferred length in byte. If nothing has
+ * been changed, return 0. In the case that the number of ports is less than or
+ * equal to 6 (VHCI_NPORTS==7), return 1.
+ *
  */
 static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
 {
 	struct vhci_hcd	*vhci;
-	unsigned long	flags;
-	int		retval;
+	int		retval = 0;
+
+	/* the enough buffer is allocated according to USB_MAXCHILDREN */
+	unsigned long	*event_bits = (unsigned long *) buf;
 	int		rhport;
 	int		changed = 0;
 
-	retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8);
-	memset(buf, 0, retval);
+	*event_bits = 0;
 
 	vhci = hcd_to_vhci(hcd);
 
-	spin_lock_irqsave(&vhci->lock, flags);
 	if (!HCD_HW_ACCESSIBLE(hcd)) {
-		usbip_dbg_vhci_rh("hw accessible flag not on?\n");
-		goto done;
+		usbip_dbg("hw accessible flag in on?\n");
+		return retval;
 	}
 
 	/* check pseudo status register for each port */
 	for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
 		if ((vhci->port_status[rhport] & PORT_C_MASK)) {
 			/* The status of a port has been changed, */
-			usbip_dbg_vhci_rh("port %d status changed\n", rhport);
+			usbip_dbg("port %d is changed\n", rhport);
 
-			buf[(rhport + 1) / 8] |= 1 << (rhport + 1) % 8;
+			*event_bits |= 1 << (rhport + 1);
 			changed = 1;
 		}
 	}
 
-	pr_info("changed %d\n", changed);
+	usbip_dbg_verbose("changed %d\n", changed);
+	if (changed)
+		retval = 1 + (VHCI_NPORTS / 8);
+	else
+		retval = 0;
 
-	if ((hcd->state == HC_STATE_SUSPENDED) && (changed == 1))
-		usb_hcd_resume_root_hub(hcd);
-
-done:
-	spin_unlock_irqrestore(&vhci->lock, flags);
-	return changed ? retval : 0;
+	return retval;
 }
 
 /* See hub_configure in hub.c */
@@ -244,173 +221,111 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc)
 static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 			    u16 wIndex, char *buf, u16 wLength)
 {
+	u32		status;
 	struct vhci_hcd	*dum;
-	int             retval = 0;
 	unsigned long   flags;
+	int             retval = 0;
 	int		rhport;
 
-	u32 prev_port_status[VHCI_NPORTS];
-
 	if (!HCD_HW_ACCESSIBLE(hcd))
 		return -ETIMEDOUT;
 
-	/*
-	 * NOTE:
-	 * wIndex shows the port number and begins from 1.
-	 */
-	usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue,
-			  wIndex);
-	if (wIndex > VHCI_NPORTS)
-		pr_err("invalid port number %d\n", wIndex);
-	rhport = ((__u8)(wIndex & 0x00ff)) - 1;
-
 	dum = hcd_to_vhci(hcd);
-
 	spin_lock_irqsave(&dum->lock, flags);
 
-	/* store old status and compare now and old later */
-	if (usbip_dbg_flag_vhci_rh) {
-		memcpy(prev_port_status, dum->port_status,
-			sizeof(prev_port_status));
-	}
+	rhport = ((__u8)(wIndex & 0x00ff)) - 1;
+	status = dum->port_status[rhport];
+
+	usbip_dbg_verbose("typeReq %x wValue %x wIndex %x\n", typeReq, wValue,
+			  wIndex);
 
 	switch (typeReq) {
 	case ClearHubFeature:
-		usbip_dbg_vhci_rh(" ClearHubFeature\n");
+		usbip_dbg_verbose(" ClearHubFeature\n");
 		break;
 	case ClearPortFeature:
+		usbip_dbg_verbose("ClearPortFeature: %d\n", wValue);
+
 		switch (wValue) {
-		case USB_PORT_FEAT_SUSPEND:
-			if (dum->port_status[rhport] & USB_PORT_STAT_SUSPEND) {
-				/* 20msec signaling */
-				dum->resuming = 1;
-				dum->re_timeout =
-					jiffies + msecs_to_jiffies(20);
-			}
-			break;
 		case USB_PORT_FEAT_POWER:
-			usbip_dbg_vhci_rh(" ClearPortFeature: "
-					  "USB_PORT_FEAT_POWER\n");
-			dum->port_status[rhport] = 0;
-			/* dum->address = 0; */
-			/* dum->hdev = 0; */
-			dum->resuming = 0;
+			status = 0;
 			break;
 		case USB_PORT_FEAT_C_RESET:
-			usbip_dbg_vhci_rh(" ClearPortFeature: "
-					  "USB_PORT_FEAT_C_RESET\n");
 			switch (dum->vdev[rhport].speed) {
+			case USB_SPEED_SUPER:
+				//status |= USB_PORT_STAT_FULL_SPEED;
+				break;
 			case USB_SPEED_HIGH:
-				dum->port_status[rhport] |=
-					USB_PORT_STAT_HIGH_SPEED;
+				status |= USB_PORT_STAT_HIGH_SPEED;
 				break;
 			case USB_SPEED_LOW:
-				dum->port_status[rhport] |=
-					USB_PORT_STAT_LOW_SPEED;
+				status |= USB_PORT_STAT_LOW_SPEED;
 				break;
 			default:
 				break;
+
 			}
 		default:
-			usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n",
-					  wValue);
-			dum->port_status[rhport] &= ~(1 << wValue);
+			status &= ~(1 << wValue);
 			break;
 		}
 		break;
 	case GetHubDescriptor:
-		usbip_dbg_vhci_rh(" GetHubDescriptor\n");
+		usbip_dbg_verbose("GetHubDescriptor\n");
 		hub_descriptor((struct usb_hub_descriptor *) buf);
 		break;
 	case GetHubStatus:
-		usbip_dbg_vhci_rh(" GetHubStatus\n");
+		usbip_dbg_verbose("GetHubStatus\n");
 		*(__le32 *) buf = __constant_cpu_to_le32(0);
 		break;
 	case GetPortStatus:
-		usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex);
-		if (wIndex > VHCI_NPORTS || wIndex < 1) {
-			pr_err("invalid port number %d\n", wIndex);
-			retval = -EPIPE;
-		}
+		if (status & (1 << USB_PORT_FEAT_RESET)) {
+			usbip_dbg_verbose("enable port %d\n", rhport);
 
-		/* we do no care of resume. */
-
-		/* whoever resets or resumes must GetPortStatus to
-		 * complete it!!
-		 *                                   */
-		if (dum->resuming && time_after(jiffies, dum->re_timeout)) {
-			dum->port_status[rhport] |=
-				(1 << USB_PORT_FEAT_C_SUSPEND);
-			dum->port_status[rhport] &=
-				~(1 << USB_PORT_FEAT_SUSPEND);
-			dum->resuming = 0;
-			dum->re_timeout = 0;
-			/* if (dum->driver && dum->driver->resume) {
-			 *	spin_unlock (&dum->lock);
-			 *	dum->driver->resume (&dum->gadget);
-			 *	spin_lock (&dum->lock);
-			 * } */
-		}
+			status &= ~(1 << USB_PORT_FEAT_RESET);
+			status |= USB_PORT_STAT_ENABLE;
 
-		if ((dum->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) !=
-		    0 && time_after(jiffies, dum->re_timeout)) {
-			dum->port_status[rhport] |=
-				(1 << USB_PORT_FEAT_C_RESET);
-			dum->port_status[rhport] &=
-				~(1 << USB_PORT_FEAT_RESET);
-			dum->re_timeout = 0;
-
-			if (dum->vdev[rhport].ud.status ==
-			    VDEV_ST_NOTASSIGNED) {
-				usbip_dbg_vhci_rh(" enable rhport %d "
-						  "(status %u)\n",
-						  rhport,
-						  dum->vdev[rhport].ud.status);
-				dum->port_status[rhport] |=
-					USB_PORT_STAT_ENABLE;
+#if 0
+			switch (dum->vdev[rhport].speed) {
+			case USB_SPEED_HIGH:
+				status |= USB_PORT_STAT_HIGH_SPEED;
+				break;
+			case USB_SPEED_LOW:
+				status |= USB_PORT_STAT_LOW_SPEED;
+				break;
+			default:
+				break;
 			}
-		}
-		((u16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]);
-		((u16 *) buf)[1] = cpu_to_le16(dum->port_status[rhport] >> 16);
+#endif
+		} 
+		((u16 *) buf)[0] = cpu_to_le16(status);
+		((u16 *) buf)[1] = cpu_to_le16(status >> 16);
+
+		usbip_dbg_verbose("GetPortStatus == %x %x\n",
+			((u16 *)buf)[0], ((u16 *)buf)[1]);
 
-		usbip_dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0],
-				  ((u16 *)buf)[1]);
 		break;
 	case SetHubFeature:
-		usbip_dbg_vhci_rh(" SetHubFeature\n");
+		usbip_dbg_verbose(" SetHubFeature\n");
 		retval = -EPIPE;
 		break;
 	case SetPortFeature:
 		switch (wValue) {
-		case USB_PORT_FEAT_SUSPEND:
-			usbip_dbg_vhci_rh(" SetPortFeature: "
-					  "USB_PORT_FEAT_SUSPEND\n");
-			break;
 		case USB_PORT_FEAT_RESET:
-			usbip_dbg_vhci_rh(" SetPortFeature: "
-					  "USB_PORT_FEAT_RESET\n");
-			/* if it's already running, disconnect first */
-			if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) {
-				dum->port_status[rhport] &=
-					~(USB_PORT_STAT_ENABLE |
-					  USB_PORT_STAT_LOW_SPEED |
-					  USB_PORT_STAT_HIGH_SPEED);
-				/* FIXME test that code path! */
-			}
-			/* 50msec reset signaling */
-			dum->re_timeout = jiffies + msecs_to_jiffies(50);
+			usbip_dbg_verbose("reset port\n");
 
-			/* FALLTHROUGH */
+			status &= ~(USB_PORT_STAT_ENABLE
+				 | USB_PORT_STAT_LOW_SPEED
+				 | USB_PORT_STAT_HIGH_SPEED
+				 );
 		default:
-			usbip_dbg_vhci_rh(" SetPortFeature: default %d\n",
-					  wValue);
-			dum->port_status[rhport] |= (1 << wValue);
+			status |= (1 << wValue);
 			break;
 		}
 		break;
 
 	default:
-		pr_err("default: no such request\n");
+		usbip_err("default: no such request\n");
 		/* dev_dbg (hardware,
 		 *		"hub control req%04x v%04x i%04x l%d\n",
 		 *		typeReq, wValue, wIndex, wLength); */
@@ -419,383 +334,220 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 		retval = -EPIPE;
 	}
 
-	if (usbip_dbg_flag_vhci_rh) {
-		pr_debug("port %d\n", rhport);
-		/* Only dump valid port status */
-		if (rhport >= 0) {
-			dump_port_status_diff(prev_port_status[rhport],
-					      dum->port_status[rhport]);
-		}
-	}
-	usbip_dbg_vhci_rh(" bye\n");
-
+	dum->port_status[rhport] = status;
 	spin_unlock_irqrestore(&dum->lock, flags);
-
 	return retval;
 }
 
-static struct vhci_device *get_vdev(struct usb_device *udev)
-{
-	int i;
-
-	if (!udev)
-		return NULL;
-
-	for (i = 0; i < VHCI_NPORTS; i++)
-		if (the_controller->vdev[i].udev == udev)
-			return port_to_vdev(i);
-
-	return NULL;
-}
 
-static void vhci_tx_urb(struct urb *urb)
+static void vhci_tx_urb(struct urb *urb, struct vhci_device *vdev)
 {
-	struct vhci_device *vdev = get_vdev(urb->dev);
 	struct vhci_priv *priv;
-	unsigned long flag;
-
-	if (!vdev) {
-		pr_err("could not get virtual device");
-		/* BUG(); */
-		return;
-	}
+	unsigned long flags;
 
 	priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC);
-
-	spin_lock_irqsave(&vdev->priv_lock, flag);
-
 	if (!priv) {
 		dev_err(&urb->dev->dev, "malloc vhci_priv\n");
-		spin_unlock_irqrestore(&vdev->priv_lock, flag);
 		usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
 		return;
 	}
 
 	priv->seqnum = atomic_inc_return(&the_controller->seqnum);
-	if (priv->seqnum == 0xffff)
-		dev_info(&urb->dev->dev, "seqnum max\n");
-
 	priv->vdev = vdev;
 	priv->urb = urb;
+	urb->hcpriv = priv;
 
-	urb->hcpriv = (void *) priv;
-
+	spin_lock_irqsave(&vdev->priv_lock, flags);
 	list_add_tail(&priv->list, &vdev->priv_tx);
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
 
 	wake_up(&vdev->waitq_tx);
-	spin_unlock_irqrestore(&vdev->priv_lock, flag);
 }
 
-static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
-			    gfp_t mem_flags)
-{
-	struct device *dev = &urb->dev->dev;
-	int ret = 0;
-	unsigned long flags;
-	struct vhci_device *vdev;
-
-	usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
-			  hcd, urb, mem_flags);
 
-	/* patch to usb_sg_init() is in 2.5.60 */
-	BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
+static int handle_usb_control_msg(struct vhci_device *vdev, struct urb *urb)
+{
+	struct usb_ctrlrequest *req;
+	int not_tx_urb = 0;
 
-	spin_lock_irqsave(&the_controller->lock, flags);
+	if (likely(usb_pipedevice(urb->pipe) != 0))
+		return not_tx_urb;
 
-	if (urb->status != -EINPROGRESS) {
-		dev_err(dev, "URB already unlinked!, status %d\n", urb->status);
-		spin_unlock_irqrestore(&the_controller->lock, flags);
-		return urb->status;
-	}
+	req = (struct usb_ctrlrequest *)urb->setup_packet;
+	switch (req->bRequest) {
+	case USB_REQ_SET_ADDRESS:
+		usbip_dbg("set address\n");
+		urb->status = 0;
+		not_tx_urb = 1;
 
-	vdev = port_to_vdev(urb->dev->portnum-1);
+		if (vdev->udev)
+			usb_put_dev(vdev->udev);
+		vdev->udev = usb_get_dev(urb->dev);
 
-	/* refuse enqueue for dead connection */
-	spin_lock(&vdev->ud.lock);
-	if (vdev->ud.status == VDEV_ST_NULL ||
-	    vdev->ud.status == VDEV_ST_ERROR) {
-		dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport);
+		spin_lock(&vdev->ud.lock);
+		vdev->ud.status = VDEV_ST_USED;
 		spin_unlock(&vdev->ud.lock);
-		spin_unlock_irqrestore(&the_controller->lock, flags);
-		return -ENODEV;
+		break;
+	case USB_REQ_GET_DESCRIPTOR:
+		usbip_dbg("get descriptor\n");
+		break;
+	default:
+		usbip_dbg("default: %d\n", req->bRequest);
+		not_tx_urb = 1;
+		break;
 	}
-	spin_unlock(&vdev->ud.lock);
-
-	ret = usb_hcd_link_urb_to_ep(hcd, urb);
-	if (ret)
-		goto no_need_unlink;
-
-	/*
-	 * The enumeration process is as follows;
-	 *
-	 *  1. Get_Descriptor request to DevAddrs(0) EndPoint(0)
-	 *     to get max packet length of default pipe
-	 *
-	 *  2. Set_Address request to DevAddr(0) EndPoint(0)
-	 *
-	 */
-	if (usb_pipedevice(urb->pipe) == 0) {
-		__u8 type = usb_pipetype(urb->pipe);
-		struct usb_ctrlrequest *ctrlreq =
-			(struct usb_ctrlrequest *) urb->setup_packet;
-
-		if (type != PIPE_CONTROL || !ctrlreq) {
-			dev_err(dev, "invalid request to devnum 0\n");
-			ret = -EINVAL;
-			goto no_need_xmit;
-		}
-
-		switch (ctrlreq->bRequest) {
-		case USB_REQ_SET_ADDRESS:
-			/* set_address may come when a device is reset */
-			dev_info(dev, "SetAddress Request (%d) to port %d\n",
-				 ctrlreq->wValue, vdev->rhport);
-
-			if (vdev->udev)
-				usb_put_dev(vdev->udev);
-			vdev->udev = usb_get_dev(urb->dev);
-
-			spin_lock(&vdev->ud.lock);
-			vdev->ud.status = VDEV_ST_USED;
-			spin_unlock(&vdev->ud.lock);
-
-			if (urb->status == -EINPROGRESS) {
-				/* This request is successfully completed. */
-				/* If not -EINPROGRESS, possibly unlinked. */
-				urb->status = 0;
-			}
-
-			goto no_need_xmit;
+	return not_tx_urb;
+}
 
-		case USB_REQ_GET_DESCRIPTOR:
-			if (ctrlreq->wValue == (USB_DT_DEVICE << 8))
-				usbip_dbg_vhci_hc("Not yet?: "
-						  "Get_Descriptor to device 0 "
-						  "(get max pipe size)\n");
+static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+			    gfp_t mem_flags)
+{
+	struct vhci_device *vdev = port_to_vdev(urb->dev->portnum - 1);
+	unsigned long flags;
+	int ret;
+	int not_tx_urb;
 
-			if (vdev->udev)
-				usb_put_dev(vdev->udev);
-			vdev->udev = usb_get_dev(urb->dev);
-			goto out;
+	usbip_dbg("enter, urb %p context: %lu\n", urb, in_interrupt());
 
-		default:
-			/* NOT REACHED */
-			dev_err(dev, "invalid request to devnum 0 bRequest %u, "
-				"wValue %u\n", ctrlreq->bRequest,
-				ctrlreq->wValue);
-			ret =  -EINVAL;
-			goto no_need_xmit;
-		}
+	spin_lock_irqsave(&the_controller->lock, flags);
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	spin_unlock_irqrestore(&the_controller->lock, flags);
 
-	}
+	if (unlikely(ret))
+		goto giveback;
 
-out:
-	vhci_tx_urb(urb);
-	spin_unlock_irqrestore(&the_controller->lock, flags);
+	not_tx_urb = handle_usb_control_msg(vdev, urb);
+	if (unlikely(not_tx_urb))
+		goto unlink;
 
-	return 0;
+	vhci_tx_urb(urb, vdev);
+	return ret;
 
-no_need_xmit:
+unlink:
+	spin_lock_irqsave(&the_controller->lock, flags);
 	usb_hcd_unlink_urb_from_ep(hcd, urb);
-no_need_unlink:
 	spin_unlock_irqrestore(&the_controller->lock, flags);
-	usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
+
+giveback:
+	usbip_hcd_giveback_urb(hcd,
+				urb,
+				urb->status
+				);
 	return ret;
 }
 
-/*
- * vhci_rx gives back the urb after receiving the reply of the urb.  If an
- * unlink pdu is sent or not, vhci_rx receives a normal return pdu and gives
- * back its urb. For the driver unlinking the urb, the content of the urb is
- * not important, but the calling to its completion handler is important; the
- * completion of unlinking is notified by the completion handler.
- *
- *
- * CLIENT SIDE
- *
- * - When vhci_hcd receives RET_SUBMIT,
- *
- *	- case 1a). the urb of the pdu is not unlinking.
- *		- normal case
- *		=> just give back the urb
- *
- *	- case 1b). the urb of the pdu is unlinking.
- *		- usbip.ko will return a reply of the unlinking request.
- *		=> give back the urb now and go to case 2b).
- *
- * - When vhci_hcd receives RET_UNLINK,
- *
- *	- case 2a). a submit request is still pending in vhci_hcd.
- *		- urb was really pending in usbip.ko and urb_unlink_urb() was
- *		  completed there.
- *		=> free a pending submit request
- *		=> notify unlink completeness by giving back the urb
- *
- *	- case 2b). a submit request is *not* pending in vhci_hcd.
- *		- urb was already given back to the core driver.
- *		=> do not give back the urb
- *
- *
- * SERVER SIDE
- *
- * - When usbip receives CMD_UNLINK,
- *
- *	- case 3a). the urb of the unlink request is now in submission.
- *		=> do usb_unlink_urb().
- *		=> after the unlink is completed, send RET_UNLINK.
- *
- *	- case 3b). the urb of the unlink request is not in submission.
- *		- may be already completed or never be received
- *		=> send RET_UNLINK
- *
- */
-static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+static struct unlink_urb *
+alloc_unlink(struct vhci_device *vdev, struct urb *urb, __u32 seqnum)
 {
-	unsigned long flags;
-	struct vhci_priv *priv;
-	struct vhci_device *vdev;
-
-	pr_info("dequeue a urb %p\n", urb);
-
-	spin_lock_irqsave(&the_controller->lock, flags);
-
-	priv = urb->hcpriv;
-	if (!priv) {
-		/* URB was never linked! or will be soon given back by
-		 * vhci_rx. */
-		spin_unlock_irqrestore(&the_controller->lock, flags);
-		return 0;
+	struct unlink_urb *ub;
+	struct urb *urb_backup;
+	char *buf;
+
+	const int buflen = urb->transfer_buffer_length;
+	const int memflags = GFP_ATOMIC;
+
+	ub = (struct unlink_urb *)kmalloc(sizeof(*ub), memflags);
+	if (unlikely(ub == NULL))
+		goto err_mem;
+		
+	urb_backup = kmemdup(urb, sizeof(struct urb), memflags);
+	if (unlikely(urb_backup == NULL)) {
+		kfree(ub);
+		goto err_mem;
 	}
-
-	{
-		int ret = 0;
-		ret = usb_hcd_check_unlink_urb(hcd, urb, status);
-		if (ret) {
-			spin_unlock_irqrestore(&the_controller->lock, flags);
-			return ret;
+	
+	if (buflen > 0) {
+		buf = kmalloc(buflen, memflags);
+		if (unlikely(buf == NULL)) {
+			kfree(ub);
+			kfree(urb);
+			goto err_mem;
 		}
+		urb_backup->transfer_buffer = buf;
 	}
 
-	 /* send unlink request here? */
-	vdev = priv->vdev;
-
-	if (!vdev->ud.tcp_socket) {
-		/* tcp connection is closed */
-		unsigned long flags2;
-
-		spin_lock_irqsave(&vdev->priv_lock, flags2);
-
-		pr_info("device %p seems to be disconnected\n", vdev);
-		list_del(&priv->list);
-		kfree(priv);
-		urb->hcpriv = NULL;
-
-		spin_unlock_irqrestore(&vdev->priv_lock, flags2);
-
-		/*
-		 * If tcp connection is alive, we have sent CMD_UNLINK.
-		 * vhci_rx will receive RET_UNLINK and give back the URB.
-		 * Otherwise, we give back it here.
-		 */
-		pr_info("gives back urb %p\n", urb);
-
-		usb_hcd_unlink_urb_from_ep(hcd, urb);
-
-		spin_unlock_irqrestore(&the_controller->lock, flags);
-		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
-				     urb->status);
-		spin_lock_irqsave(&the_controller->lock, flags);
-
-	} else {
-		/* tcp connection is alive */
-		unsigned long flags2;
-		struct vhci_unlink *unlink;
-
-		spin_lock_irqsave(&vdev->priv_lock, flags2);
-
-		/* setup CMD_UNLINK pdu */
-		unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC);
-		if (!unlink) {
-			pr_err("malloc vhci_unlink\n");
-			spin_unlock_irqrestore(&vdev->priv_lock, flags2);
-			spin_unlock_irqrestore(&the_controller->lock, flags);
-			usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
-			return -ENOMEM;
-		}
+	ub->urb = urb_backup;
+	ub->seqnum = seqnum;
+	return ub;
 
-		unlink->seqnum = atomic_inc_return(&the_controller->seqnum);
-		if (unlink->seqnum == 0xffff)
-			pr_info("seqnum max\n");
-
-		unlink->unlink_seqnum = priv->seqnum;
-
-		pr_info("device %p seems to be still connected\n", vdev);
-
-		/* send cmd_unlink and try to cancel the pending URB in the
-		 * peer */
-		list_add_tail(&unlink->list, &vdev->unlink_tx);
-		wake_up(&vdev->waitq_tx);
-
-		spin_unlock_irqrestore(&vdev->priv_lock, flags2);
-	}
-
-	spin_unlock_irqrestore(&the_controller->lock, flags);
-
-	usbip_dbg_vhci_hc("leave\n");
-	return 0;
+err_mem:
+	usbip_err("cannot allocate memory\n");
+	usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
+	return NULL;
 }
 
-static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
+/*
+ * unlinking urbs in the conventional sense of usb-core 
+ * will not work (safe) for virtual host controllers.
+ *
+ */
+static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
-	struct vhci_unlink *unlink, *tmp;
+        unsigned long flags;
+        struct vhci_priv *priv = urb->hcpriv;
+        struct vhci_device *vdev = port_to_vdev(urb->dev->portnum - 1);
+	struct unlink_urb *ub;
 
-	spin_lock(&the_controller->lock);
-	spin_lock(&vdev->priv_lock);
+        if (priv == NULL) {
+                /* URB was never linked */
+                usbip_err("urb to unlink not even liked yet\n");
+                return 0;
+        }
 
-	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
-		pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);
-		list_del(&unlink->list);
-		kfree(unlink);
-	}
+        /* no need to check the unlink 
+         * usb_hcd_check_unlink checks if the hc 
+         * has seen any interrupts ...and vhci doesn't use interrupts */
 
-	while (!list_empty(&vdev->unlink_rx)) {
-		struct urb *urb;
+	ub = alloc_unlink(vdev, urb, priv->seqnum);
 
-		unlink = list_first_entry(&vdev->unlink_rx, struct vhci_unlink,
-			list);
+	local_irq_save(flags);
 
-		/* give back URB of unanswered unlink request */
-		pr_info("unlink cleanup rx %lu\n", unlink->unlink_seqnum);
+        spin_lock(&the_controller->lock);
+        usb_hcd_unlink_urb_from_ep(hcd, urb);
+        spin_unlock(&the_controller->lock);
 
-		urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
-		if (!urb) {
-			pr_info("the urb (seqnum %lu) was already given back\n",
-				unlink->unlink_seqnum);
-			list_del(&unlink->list);
-			kfree(unlink);
-			continue;
-		}
-
-		urb->status = -ENODEV;
+        spin_lock(&vdev->priv_lock);
+        list_del(&priv->list);
+	if (ub)
+		list_add_tail(&ub->list, &vdev->unlinked_urbs);
+        spin_unlock(&vdev->priv_lock);
 
-		usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+	local_irq_restore(flags);
 
-		list_del(&unlink->list);
+        kfree(priv);
 
-		spin_unlock(&vdev->priv_lock);
-		spin_unlock(&the_controller->lock);
+        if (likely(status == -EINPROGRESS))
+                status = 0;
 
-		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
-				     urb->status);
+        usbip_dbg("unlink urb  %p status %d\n", urb, status);
+        usbip_hcd_giveback_urb(vhci_to_hcd(the_controller),
+                                urb,
+                                status
+                                );
 
-		spin_lock(&the_controller->lock);
-		spin_lock(&vdev->priv_lock);
+        return 0;
+}
 
-		kfree(unlink);
-	}
 
-	spin_unlock(&vdev->priv_lock);
-	spin_unlock(&the_controller->lock);
+/*
+ * call this function whenever you want to giveback
+ * an urb in usbip.
+ *
+ * complete handlers are usually 
+ * never called from a non-interrutp context
+ * so they might not held their locks interrupt safe.
+ * (btusb)
+ */
+void usbip_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	local_irq_disable();
+	
+	usb_hcd_giveback_urb(vhci_to_hcd(the_controller),
+			urb,
+			status
+			);
+
+	local_irq_enable();
 }
 
 /*
@@ -807,55 +559,26 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
 {
 	struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
 
-	/* need this? see stub_dev.c */
 	if (ud->tcp_socket) {
-		pr_debug("shutdown tcp_socket %p\n", ud->tcp_socket);
+		usbip_dbg("shutdown tcp_socket %p\n", ud->tcp_socket);
 		kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
 	}
 
 	/* kill threads related to this sdev, if v.c. exists */
-	if (vdev->ud.tcp_rx) {
-		kthread_stop_put(vdev->ud.tcp_rx);
-		vdev->ud.tcp_rx = NULL;
-	}
-	if (vdev->ud.tcp_tx) {
-		kthread_stop_put(vdev->ud.tcp_tx);
-		vdev->ud.tcp_tx = NULL;
-	}
-	pr_info("stop threads\n");
+	if (vdev->ud.tcp_rx && !task_is_dead(vdev->ud.tcp_rx)) 
+		kthread_stop(vdev->ud.tcp_rx);
+
+	if (vdev->ud.tcp_tx && !task_is_dead(vdev->ud.tcp_tx))
+		kthread_stop(vdev->ud.tcp_tx);
 
-	/* active connection is closed */
-	if (vdev->ud.tcp_socket != NULL) {
-		sock_release(vdev->ud.tcp_socket);
+	if (vdev->ud.tcp_socket) {
+		fput(vdev->ud.tcp_socket->file);
 		vdev->ud.tcp_socket = NULL;
 	}
-	pr_info("release socket\n");
 
-	vhci_device_unlink_cleanup(vdev);
-
-	/*
-	 * rh_port_disconnect() is a trigger of ...
-	 *   usb_disable_device():
-	 *	disable all the endpoints for a USB device.
-	 *   usb_disable_endpoint():
-	 *	disable endpoints. pending urbs are unlinked(dequeued).
-	 *
-	 * NOTE: After calling rh_port_disconnect(), the USB device drivers of a
-	 * detached device should release used urbs in a cleanup function (i.e.
-	 * xxx_disconnect()). Therefore, vhci_hcd does not need to release
-	 * pushed urbs and their private data in this function.
-	 *
-	 * NOTE: vhci_dequeue() must be considered carefully. When shutting down
-	 * a connection, vhci_shutdown_connection() expects vhci_dequeue()
-	 * gives back pushed urbs and frees their private data by request of
-	 * the cleanup function of a USB driver. When unlinking a urb with an
-	 * active connection, vhci_dequeue() does not give back the urb which
-	 * is actually given back by vhci_rx after receiving its return pdu.
-	 *
-	 */
 	rh_port_disconnect(vdev->rhport);
 
-	pr_info("disconnect device\n");
+	usbip_dbg("vhci device released\n");
 }
 
 
@@ -865,24 +588,31 @@ static void vhci_device_reset(struct usbip_device *ud)
 
 	spin_lock(&ud->lock);
 
+	ud->status = VDEV_ST_NULL;
+
 	vdev->speed  = 0;
 	vdev->devid  = 0;
 
-	if (vdev->udev)
+	if (vdev->udev) {
 		usb_put_dev(vdev->udev);
-	vdev->udev = NULL;
+		vdev->udev = NULL;
+	}
 
-	ud->tcp_socket = NULL;
-	ud->status = VDEV_ST_NULL;
+	if (ud->tcp_socket) {
+		fput(ud->tcp_socket->file);
+		ud->tcp_socket = NULL;
+	}
 
 	spin_unlock(&ud->lock);
 }
 
 static void vhci_device_unusable(struct usbip_device *ud)
 {
-	spin_lock(&ud->lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ud->lock, flags);
 	ud->status = VDEV_ST_ERROR;
-	spin_unlock(&ud->lock);
+	spin_unlock_irqrestore(&ud->lock, flags);
 }
 
 static void vhci_device_init(struct vhci_device *vdev)
@@ -895,8 +625,7 @@ static void vhci_device_init(struct vhci_device *vdev)
 
 	INIT_LIST_HEAD(&vdev->priv_rx);
 	INIT_LIST_HEAD(&vdev->priv_tx);
-	INIT_LIST_HEAD(&vdev->unlink_tx);
-	INIT_LIST_HEAD(&vdev->unlink_rx);
+	INIT_LIST_HEAD(&vdev->unlinked_urbs);
 	spin_lock_init(&vdev->priv_lock);
 
 	init_waitqueue_head(&vdev->waitq_tx);
@@ -914,7 +643,7 @@ static int vhci_start(struct usb_hcd *hcd)
 	int rhport;
 	int err = 0;
 
-	usbip_dbg_vhci_hc("enter vhci_start\n");
+	usbip_dbg("enter vhci_start\n");
 
 	/* initialize private data of usb_hcd */
 
@@ -928,13 +657,12 @@ static int vhci_start(struct usb_hcd *hcd)
 	spin_lock_init(&vhci->lock);
 
 	hcd->power_budget = 0; /* no limit */
-	hcd->state  = HC_STATE_RUNNING;
 	hcd->uses_new_polling = 1;
 
 	/* vhci_hcd is now ready to be controlled through sysfs */
 	err = sysfs_create_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
 	if (err) {
-		pr_err("create sysfs files\n");
+		usbip_err("create sysfs files\n");
 		return err;
 	}
 
@@ -946,7 +674,7 @@ static void vhci_stop(struct usb_hcd *hcd)
 	struct vhci_hcd *vhci = hcd_to_vhci(hcd);
 	int rhport = 0;
 
-	usbip_dbg_vhci_hc("stop VHCI controller\n");
+	usbip_dbg("stop VHCI controller\n");
 
 	/* 1. remove the userland interface of vhci_hcd */
 	sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
@@ -962,56 +690,10 @@ static void vhci_stop(struct usb_hcd *hcd)
 
 static int vhci_get_frame_number(struct usb_hcd *hcd)
 {
-	pr_err("Not yet implemented\n");
-	return 0;
-}
-
-#ifdef CONFIG_PM
-
-/* FIXME: suspend/resume */
-static int vhci_bus_suspend(struct usb_hcd *hcd)
-{
-	struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-
-	dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
-
-	spin_lock_irq(&vhci->lock);
-	/* vhci->rh_state = DUMMY_RH_SUSPENDED;
-	 * set_link_state(vhci); */
-	hcd->state = HC_STATE_SUSPENDED;
-	spin_unlock_irq(&vhci->lock);
-
+	usbip_err("Not yet implemented\n");
 	return 0;
 }
 
-static int vhci_bus_resume(struct usb_hcd *hcd)
-{
-	struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-	int rc = 0;
-
-	dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
-
-	spin_lock_irq(&vhci->lock);
-	if (!HCD_HW_ACCESSIBLE(hcd)) {
-		rc = -ESHUTDOWN;
-	} else {
-		/* vhci->rh_state = DUMMY_RH_RUNNING;
-		 * set_link_state(vhci);
-		 * if (!list_empty(&vhci->urbp_list))
-		 *	mod_timer(&vhci->timer, jiffies); */
-		hcd->state = HC_STATE_RUNNING;
-	}
-	spin_unlock_irq(&vhci->lock);
-
-	return rc;
-}
-
-#else
-
-#define vhci_bus_suspend      NULL
-#define vhci_bus_resume       NULL
-#endif
-
 static struct hc_driver vhci_hc_driver = {
 	.description	= driver_name,
 	.product_desc	= driver_desc,
@@ -1029,8 +711,8 @@ static struct hc_driver vhci_hc_driver = {
 
 	.hub_status_data = vhci_hub_status,
 	.hub_control    = vhci_hub_control,
-	.bus_suspend	= vhci_bus_suspend,
-	.bus_resume	= vhci_bus_resume,
+	.bus_suspend	= NULL,
+	.bus_resume	= NULL
 };
 
 static int vhci_hcd_probe(struct platform_device *pdev)
@@ -1038,13 +720,7 @@ static int vhci_hcd_probe(struct platform_device *pdev)
 	struct usb_hcd		*hcd;
 	int			ret;
 
-	usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id);
-
-	/* will be removed */
-	if (pdev->dev.dma_mask) {
-		dev_info(&pdev->dev, "vhci_hcd DMA not supported\n");
-		return -EINVAL;
-	}
+	usbip_dbg("name %s id %d\n", pdev->name, pdev->id);
 
 	/*
 	 * Allocate and initialize hcd.
@@ -1052,10 +728,11 @@ static int vhci_hcd_probe(struct platform_device *pdev)
 	 */
 	hcd = usb_create_hcd(&vhci_hc_driver, &pdev->dev, dev_name(&pdev->dev));
 	if (!hcd) {
-		pr_err("create hcd failed\n");
+		usbip_err("create hcd failed\n");
 		return -ENOMEM;
 	}
 	hcd->has_tt = 1;
+	hcd->irq = -1; /* NO_IRQ, not defined in x68 irq.h, why ? */
 
 	/* this is private data for vhci_hcd */
 	the_controller = hcd_to_vhci(hcd);
@@ -1066,13 +743,12 @@ static int vhci_hcd_probe(struct platform_device *pdev)
 	 */
 	ret = usb_add_hcd(hcd, 0, 0);
 	if (ret != 0) {
-		pr_err("usb_add_hcd failed %d\n", ret);
+		usbip_err("usb_add_hcd failed %d\n", ret);
 		usb_put_hcd(hcd);
 		the_controller = NULL;
 		return ret;
 	}
 
-	usbip_dbg_vhci_hc("bye\n");
 	return 0;
 }
 
@@ -1096,64 +772,11 @@ static int vhci_hcd_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM
-
-/* what should happen for USB/IP under suspend/resume? */
-static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	struct usb_hcd *hcd;
-	int rhport = 0;
-	int connected = 0;
-	int ret = 0;
-
-	hcd = platform_get_drvdata(pdev);
-
-	spin_lock(&the_controller->lock);
-
-	for (rhport = 0; rhport < VHCI_NPORTS; rhport++)
-		if (the_controller->port_status[rhport] &
-		    USB_PORT_STAT_CONNECTION)
-			connected += 1;
-
-	spin_unlock(&the_controller->lock);
-
-	if (connected > 0) {
-		dev_info(&pdev->dev, "We have %d active connection%s. Do not "
-			 "suspend.\n", connected, (connected == 1 ? "" : "s"));
-		ret =  -EBUSY;
-	} else {
-		dev_info(&pdev->dev, "suspend vhci_hcd");
-		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	}
-
-	return ret;
-}
-
-static int vhci_hcd_resume(struct platform_device *pdev)
-{
-	struct usb_hcd *hcd;
-
-	dev_dbg(&pdev->dev, "%s\n", __func__);
-
-	hcd = platform_get_drvdata(pdev);
-	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	usb_hcd_poll_rh_status(hcd);
-
-	return 0;
-}
-
-#else
-
-#define vhci_hcd_suspend	NULL
-#define vhci_hcd_resume		NULL
-
-#endif
-
 static struct platform_driver vhci_driver = {
 	.probe	= vhci_hcd_probe,
-	.remove	= __devexit_p(vhci_hcd_remove),
-	.suspend = vhci_hcd_suspend,
-	.resume	= vhci_hcd_resume,
+	.remove	= vhci_hcd_remove,
+	.suspend = NULL,
+	.resume	= NULL,
 	.driver	= {
 		.name = (char *) driver_name,
 		.owner = THIS_MODULE,
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index f0eaf04..a41dfe9 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -23,64 +23,84 @@
 #include "usbip_common.h"
 #include "vhci.h"
 
-/* get URB from transmitted urb queue. caller must hold vdev->priv_lock */
-struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum)
+
+static struct urb *
+dequeue_rx(struct vhci_device *vdev, __u32 seqnum)
 {
 	struct vhci_priv *priv, *tmp;
 	struct urb *urb = NULL;
-	int status;
+	unsigned long flags;
 
+	spin_lock_irqsave(&vdev->priv_lock, flags);
 	list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
 		if (priv->seqnum == seqnum) {
 			urb = priv->urb;
-			status = urb->status;
-
-			usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n",
-					  urb, priv, seqnum);
-
-			/* TODO: fix logic here to improve indent situtation */
-			if (status != -EINPROGRESS) {
-				if (status == -ENOENT ||
-				    status == -ECONNRESET)
-					dev_info(&urb->dev->dev,
-						 "urb %p was unlinked "
-						 "%ssynchronuously.\n", urb,
-						 status == -ENOENT ? "" : "a");
-				else
-					dev_info(&urb->dev->dev,
-						 "urb %p may be in a error, "
-						 "status %d\n", urb, status);
-			}
-
-			list_del(&priv->list);
-			kfree(priv);
-			urb->hcpriv = NULL;
-
-			break;
+        		list_del(&priv->list);
+			spin_unlock_irqrestore(&vdev->priv_lock, flags);
+			return urb;
 		}
 	}
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
+	return urb;
+}
 
+static struct urb *
+dequeue_unlink(struct vhci_device *vdev, __u32 seqnum)
+{
+	struct unlink_urb *ub, *tmp;
+	struct urb *urb = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vdev->priv_lock, flags);
+	list_for_each_entry_safe(ub, tmp, &vdev->unlinked_urbs, list) {
+		if (ub->seqnum == seqnum) {
+			urb = ub->urb;
+			list_del(&ub->list);
+			spin_unlock_irqrestore(&vdev->priv_lock, flags);
+
+			kfree(ub);
+			return urb;
+		}
+	}
+	spin_unlock_irqrestore(&vdev->priv_lock, flags);
 	return urb;
 }
 
+static void free_unlinked_urb(struct urb *urb)
+{
+	if (urb->transfer_buffer)
+		kfree(urb->transfer_buffer);
+	kfree(urb);
+}
+
 static void vhci_recv_ret_submit(struct vhci_device *vdev,
 				 struct usbip_header *pdu)
 {
-	struct usbip_device *ud = &vdev->ud;
-	struct urb *urb;
+	const int status = 0;
+	unsigned long seqnum = pdu->base.seqnum;
 	unsigned long flags;
-
-	spin_lock(&vdev->priv_lock);
-	urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
-	spin_unlock(&vdev->priv_lock);
-
-	if (!urb) {
-		pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
-		pr_info("max seqnum %d\n",
-			atomic_read(&the_controller->seqnum));
-		usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
-		return;
+	struct urb *urb;
+	struct usbip_device *ud = &vdev->ud;
+	bool urb_linked = true;
+
+	urb = dequeue_rx(vdev, seqnum);
+	if (unlikely(!urb)) {
+		usbip_dbg("pdu with seqnum %lu is not in rx queue\n",
+			seqnum
+			);
+		urb = dequeue_unlink(vdev, seqnum);
+		if (unlikely(urb == NULL)) {
+			usbip_err("reveived pdu num %lu was never sent\n",
+				seqnum
+				);
+                	usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
+			return;
+		}
+		urb_linked = false;
 	}
+	usbip_dbg("found urb %p seqnum %lu in %s queue\n", urb, seqnum,
+		urb_linked ? "rx" : "unlink"
+		);
 
 	/* unpack the pdu to a urb */
 	usbip_pack_pdu(pdu, urb, USBIP_RET_SUBMIT, 0);
@@ -94,103 +114,36 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
 		return;
 
 	/* restore the padding in iso packets */
-	usbip_pad_iso(ud, urb);
+	if (usbip_pad_iso(ud, urb) < 0)
+		return;
+
+	if (usb_pipein(urb->pipe) && urb->transfer_buffer)
+		usbip_dump_buffer((char *)urb->transfer_buffer,
+				urb->actual_length
+				);
 
-	if (usbip_dbg_flag_vhci_rx)
-		usbip_dump_urb(urb);
+	if (unlikely(urb_linked == false)) {
+		/* urb was never linked or was already
+		 * given back in vhci_deqeue
+		 */
+		free_unlinked_urb(urb);
+		return;
+	}
 
-	usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
+	kfree(urb->hcpriv);
 
 	spin_lock_irqsave(&the_controller->lock, flags);
 	usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
 	spin_unlock_irqrestore(&the_controller->lock, flags);
 
-	usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
-
-	usbip_dbg_vhci_rx("Leave\n");
-
-	return;
+	usbip_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, status);
+	usbip_dbg("urb given back %p status %d\n", urb, status);
 }
 
-static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
-						  struct usbip_header *pdu)
-{
-	struct vhci_unlink *unlink, *tmp;
 
-	spin_lock(&vdev->priv_lock);
-
-	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
-		pr_info("unlink->seqnum %lu\n", unlink->seqnum);
-		if (unlink->seqnum == pdu->base.seqnum) {
-			usbip_dbg_vhci_rx("found pending unlink, %lu\n",
-					  unlink->seqnum);
-			list_del(&unlink->list);
-
-			spin_unlock(&vdev->priv_lock);
-			return unlink;
-		}
-	}
-
-	spin_unlock(&vdev->priv_lock);
-
-	return NULL;
-}
-
-static void vhci_recv_ret_unlink(struct vhci_device *vdev,
-				 struct usbip_header *pdu)
-{
-	struct vhci_unlink *unlink;
-	struct urb *urb;
-	unsigned long flags;
-
-	usbip_dump_header(pdu);
-
-	unlink = dequeue_pending_unlink(vdev, pdu);
-	if (!unlink) {
-		pr_info("cannot find the pending unlink %u\n",
-			pdu->base.seqnum);
-		return;
-	}
-
-	spin_lock(&vdev->priv_lock);
-	urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
-	spin_unlock(&vdev->priv_lock);
-
-	if (!urb) {
-		/*
-		 * I get the result of a unlink request. But, it seems that I
-		 * already received the result of its submit result and gave
-		 * back the URB.
-		 */
-		pr_info("the urb (seqnum %d) was already given back\n",
-			pdu->base.seqnum);
-	} else {
-		usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
-
-		/* If unlink is succeed, status is -ECONNRESET */
-		urb->status = pdu->u.ret_unlink.status;
-		pr_info("urb->status %d\n", urb->status);
-
-		spin_lock_irqsave(&the_controller->lock, flags);
-		usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-		spin_unlock_irqrestore(&the_controller->lock, flags);
-
-		usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
-				     urb->status);
-	}
-
-	kfree(unlink);
-}
-
-static int vhci_priv_tx_empty(struct vhci_device *vdev)
+static inline int vhci_priv_tx_empty(struct vhci_device *vdev)
 {
-	int empty = 0;
-
-	spin_lock(&vdev->priv_lock);
-	empty = list_empty(&vdev->priv_rx);
-	spin_unlock(&vdev->priv_lock);
-
-	return empty;
+	return list_empty(&vdev->priv_rx);
 }
 
 /* recv a pdu */
@@ -200,12 +153,10 @@ static void vhci_rx_pdu(struct usbip_device *ud)
 	struct usbip_header pdu;
 	struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
 
-	usbip_dbg_vhci_rx("Enter\n");
-
 	memset(&pdu, 0, sizeof(pdu));
 
 	/* 1. receive a pdu header */
-	ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
+	ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0);
 	if (ret < 0) {
 		if (ret == -ECONNRESET)
 			pr_info("connection reset by peer\n");
@@ -221,29 +172,24 @@ static void vhci_rx_pdu(struct usbip_device *ud)
 		return;
 	}
 	if (ret == 0) {
-		pr_info("connection closed");
+		usbip_info("connection closed\n");
 		usbip_event_add(ud, VDEV_EVENT_DOWN);
 		return;
 	}
 	if (ret != sizeof(pdu)) {
-		pr_err("received pdu size is %d, should be %d\n", ret,
+		usbip_err("received pdu size is %d, should be %d\n", ret,
 		       (unsigned int)sizeof(pdu));
 		usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
 		return;
 	}
 
 	usbip_header_correct_endian(&pdu, 0);
-
-	if (usbip_dbg_flag_vhci_rx)
-		usbip_dump_header(&pdu);
+	usbip_dump_header(&pdu);
 
 	switch (pdu.base.command) {
 	case USBIP_RET_SUBMIT:
 		vhci_recv_ret_submit(vdev, &pdu);
 		break;
-	case USBIP_RET_UNLINK:
-		vhci_recv_ret_unlink(vdev, &pdu);
-		break;
 	default:
 		/* NOT REACHED */
 		pr_err("unknown pdu %u\n", pdu.base.command);
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
index 7ce9c2f..618730e 100644
--- a/drivers/staging/usbip/vhci_sysfs.c
+++ b/drivers/staging/usbip/vhci_sysfs.c
@@ -18,23 +18,24 @@
  */
 
 #include <linux/kthread.h>
+#include <linux/file.h>
 #include <linux/net.h>
 
 #include "usbip_common.h"
 #include "vhci.h"
 
-/* TODO: refine locking ?*/
 
 /* Sysfs entry to show port status */
 static ssize_t show_status(struct device *dev, struct device_attribute *attr,
 			   char *out)
 {
+	//unsigned long flags;
 	char *s = out;
 	int i = 0;
 
 	BUG_ON(!the_controller || !out);
 
-	spin_lock(&the_controller->lock);
+	//spin_lock_irqsave(&the_controller->lock, flags);
 
 	/*
 	 * output example:
@@ -52,6 +53,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr,
 	for (i = 0; i < VHCI_NPORTS; i++) {
 		struct vhci_device *vdev = port_to_vdev(i);
 
+			
 		spin_lock(&vdev->ud.lock);
 		out += sprintf(out, "%03u %03u ", i, vdev->ud.status);
 
@@ -69,7 +71,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr,
 		spin_unlock(&vdev->ud.lock);
 	}
 
-	spin_unlock(&the_controller->lock);
+	//spin_unlock_irqrestore(&the_controller->lock, flags);
 
 	return out - s;
 }
@@ -80,30 +82,14 @@ static int vhci_port_disconnect(__u32 rhport)
 {
 	struct vhci_device *vdev;
 
-	usbip_dbg_vhci_sysfs("enter\n");
-
-	/* lock */
-	spin_lock(&the_controller->lock);
-
 	vdev = port_to_vdev(rhport);
 
-	spin_lock(&vdev->ud.lock);
 	if (vdev->ud.status == VDEV_ST_NULL) {
-		pr_err("not connected %d\n", vdev->ud.status);
-
-		/* unlock */
-		spin_unlock(&vdev->ud.lock);
-		spin_unlock(&the_controller->lock);
-
+		pr_err("vhci port %d: not connected\n", rhport);
 		return -EINVAL;
 	}
 
-	/* unlock */
-	spin_unlock(&vdev->ud.lock);
-	spin_unlock(&the_controller->lock);
-
 	usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
-
 	return 0;
 }
 
@@ -125,7 +111,7 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
 	if (err < 0)
 		return -EINVAL;
 
-	usbip_dbg_vhci_sysfs("Leave\n");
+	usbip_dbg("Leave\n");
 
 	return count;
 }
@@ -182,7 +168,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 	 */
 	sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed);
 
-	usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n",
+	usbip_dbg("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n",
 			     rhport, sockfd, devid, speed);
 
 	/* check received parameters */
@@ -190,22 +176,18 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 		return -EINVAL;
 
 	/* check sockfd */
+	/* Extract socket from fd. */
+	/* The correct way to clean this up is to fput(socket->file). */
 	socket = sockfd_to_socket(sockfd);
 	if (!socket)
 		return -EINVAL;
 
-	/* now need lock until setting vdev status as used */
-
-	/* begin a lock */
-	spin_lock(&the_controller->lock);
+	/* no locking is needed yet, it's totally safe
+	 * to read the vdev state */
 	vdev = port_to_vdev(rhport);
-	spin_lock(&vdev->ud.lock);
 
 	if (vdev->ud.status != VDEV_ST_NULL) {
-		/* end of the lock */
-		spin_unlock(&vdev->ud.lock);
-		spin_unlock(&the_controller->lock);
-
+		fput(socket->file);
 		dev_err(dev, "port %d already used\n", rhport);
 		return -EINVAL;
 	}
@@ -213,17 +195,15 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
 	dev_info(dev, "rhport(%u) sockfd(%d) devid(%u) speed(%u)\n",
 		 rhport, sockfd, devid, speed);
 
+	/* no locking is needed yet, at this point of code
+	 * we are the only ones that modify our new vhic device */
 	vdev->devid         = devid;
 	vdev->speed         = speed;
 	vdev->ud.tcp_socket = socket;
 	vdev->ud.status     = VDEV_ST_NOTASSIGNED;
 
-	spin_unlock(&vdev->ud.lock);
-	spin_unlock(&the_controller->lock);
-	/* end the lock */
-
-	vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
-	vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
+	vdev->ud.tcp_rx = kthread_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
+	vdev->ud.tcp_tx = kthread_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
 
 	rh_port_connect(rhport, speed);
 
@@ -235,7 +215,6 @@ static struct attribute *dev_attrs[] = {
 	&dev_attr_status.attr,
 	&dev_attr_detach.attr,
 	&dev_attr_attach.attr,
-	&dev_attr_usbip_debug.attr,
 	NULL,
 };
 
diff --git a/drivers/staging/usbip/vhci_tx.c b/drivers/staging/usbip/vhci_tx.c
index 9b437e7..a243f70 100644
--- a/drivers/staging/usbip/vhci_tx.c
+++ b/drivers/staging/usbip/vhci_tx.c
@@ -28,7 +28,7 @@ static void setup_cmd_submit_pdu(struct usbip_header *pdup,  struct urb *urb)
 	struct vhci_priv *priv = ((struct vhci_priv *)urb->hcpriv);
 	struct vhci_device *vdev = priv->vdev;
 
-	usbip_dbg_vhci_tx("URB, local devnum %u, remote devid %u\n",
+	usbip_dbg("URB, local devnum %u, remote devid %u\n",
 			  usb_pipedevice(urb->pipe), vdev->devid);
 
 	pdup->base.command   = USBIP_CMD_SUBMIT;
@@ -44,49 +44,49 @@ static void setup_cmd_submit_pdu(struct usbip_header *pdup,  struct urb *urb)
 		memcpy(pdup->u.cmd_submit.setup, urb->setup_packet, 8);
 }
 
-static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev)
+
+static inline struct vhci_priv * dequeue_tx_urb(struct vhci_device *vdev)
 {
-	unsigned long flags;
 	struct vhci_priv *priv, *tmp;
+	unsigned long flags;
 
 	spin_lock_irqsave(&vdev->priv_lock, flags);
-
-	list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
-		list_move_tail(&priv->list, &vdev->priv_rx);
-		spin_unlock_irqrestore(&vdev->priv_lock, flags);
-		return priv;
+	list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) { 
+		goto dequeue;
 	}
+	priv = NULL;
 
+dequeue:
 	spin_unlock_irqrestore(&vdev->priv_lock, flags);
-
-	return NULL;
+	return priv;
 }
 
 static int vhci_send_cmd_submit(struct vhci_device *vdev)
 {
-	struct vhci_priv *priv = NULL;
-
 	struct msghdr msg;
-	struct kvec iov[3];
+	struct vhci_priv *priv;
+	unsigned long flags;
 	size_t txsize;
-
 	size_t total_size = 0;
+	struct kvec iov[3];
 
-	while ((priv = dequeue_from_priv_tx(vdev)) != NULL) {
+	while ( (priv = dequeue_tx_urb(vdev)) ) {
 		int ret;
 		struct urb *urb = priv->urb;
 		struct usbip_header pdu_header;
-		void *iso_buffer = NULL;
+		struct usbip_iso_packet_descriptor *iso_buffer = NULL;
 
 		txsize = 0;
 		memset(&pdu_header, 0, sizeof(pdu_header));
 		memset(&msg, 0, sizeof(msg));
 		memset(&iov, 0, sizeof(iov));
 
-		usbip_dbg_vhci_tx("setup txdata urb %p\n", urb);
-
 		/* 1. setup usbip_header */
 		setup_cmd_submit_pdu(&pdu_header, urb);
+
+		usbip_dump_header(&pdu_header);
+		usbip_dump_urb(urb);
+
 		usbip_header_correct_endian(&pdu_header, 1);
 
 		iov[0].iov_base = &pdu_header;
@@ -98,6 +98,8 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev)
 			iov[1].iov_base = urb->transfer_buffer;
 			iov[1].iov_len  = urb->transfer_buffer_length;
 			txsize += urb->transfer_buffer_length;
+
+			usbip_dump_buffer((char *)iov[1].iov_base, iov[1].iov_len);
 		}
 
 		/* 3. setup iso_packet_descriptor */
@@ -116,91 +118,34 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev)
 			txsize += len;
 		}
 
+		/* move from tx to rx queue 
+		 *
+		 * free all hc resources for this urb
+		 * after ret_submit returned from usbip host */
+		spin_lock_irqsave(&vdev->priv_lock, flags);
+		list_move_tail(&priv->list, &vdev->priv_rx);
+		spin_unlock_irqrestore(&vdev->priv_lock, flags);
+
+		usbip_dbg("moved urb %p in pdu seqno: %lu to rx_queue\n",
+			urb, priv->seqnum);
+
 		ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize);
 		if (ret != txsize) {
-			pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
+			usbip_err("sendmsg failed!, ret=%d for %zd\n", ret,
 			       txsize);
 			kfree(iso_buffer);
 			usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
 			return -1;
 		}
+		usbip_dbg("sent urb %p in pdu seqno: %lu\n", urb, priv->seqnum);
 
 		kfree(iso_buffer);
-		usbip_dbg_vhci_tx("send txdata\n");
-
 		total_size += txsize;
 	}
 
 	return total_size;
 }
 
-static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
-{
-	unsigned long flags;
-	struct vhci_unlink *unlink, *tmp;
-
-	spin_lock_irqsave(&vdev->priv_lock, flags);
-
-	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
-		list_move_tail(&unlink->list, &vdev->unlink_rx);
-		spin_unlock_irqrestore(&vdev->priv_lock, flags);
-		return unlink;
-	}
-
-	spin_unlock_irqrestore(&vdev->priv_lock, flags);
-
-	return NULL;
-}
-
-static int vhci_send_cmd_unlink(struct vhci_device *vdev)
-{
-	struct vhci_unlink *unlink = NULL;
-
-	struct msghdr msg;
-	struct kvec iov[3];
-	size_t txsize;
-
-	size_t total_size = 0;
-
-	while ((unlink = dequeue_from_unlink_tx(vdev)) != NULL) {
-		int ret;
-		struct usbip_header pdu_header;
-
-		txsize = 0;
-		memset(&pdu_header, 0, sizeof(pdu_header));
-		memset(&msg, 0, sizeof(msg));
-		memset(&iov, 0, sizeof(iov));
-
-		usbip_dbg_vhci_tx("setup cmd unlink, %lu\n", unlink->seqnum);
-
-		/* 1. setup usbip_header */
-		pdu_header.base.command = USBIP_CMD_UNLINK;
-		pdu_header.base.seqnum  = unlink->seqnum;
-		pdu_header.base.devid	= vdev->devid;
-		pdu_header.base.ep	= 0;
-		pdu_header.u.cmd_unlink.seqnum = unlink->unlink_seqnum;
-
-		usbip_header_correct_endian(&pdu_header, 1);
-
-		iov[0].iov_base = &pdu_header;
-		iov[0].iov_len  = sizeof(pdu_header);
-		txsize += sizeof(pdu_header);
-
-		ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 1, txsize);
-		if (ret != txsize) {
-			pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
-			       txsize);
-			usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
-			return -1;
-		}
-
-		usbip_dbg_vhci_tx("send txdata\n");
-
-		total_size += txsize;
-	}
-
-	return total_size;
-}
 
 int vhci_tx_loop(void *data)
 {
@@ -211,16 +156,12 @@ int vhci_tx_loop(void *data)
 		if (vhci_send_cmd_submit(vdev) < 0)
 			break;
 
-		if (vhci_send_cmd_unlink(vdev) < 0)
-			break;
-
 		wait_event_interruptible(vdev->waitq_tx,
 					 (!list_empty(&vdev->priv_tx) ||
-					  !list_empty(&vdev->unlink_tx) ||
-					  kthread_should_stop()));
+					  kthread_should_stop()
+					 ));
 
-		usbip_dbg_vhci_tx("pending urbs ?, now wake up\n");
+		usbip_dbg("pending urbs ?, now wake up\n");
 	}
-
 	return 0;
 }

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux