Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 28 Mar 2009 20:30:43 +0000 (13:30 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 28 Mar 2009 20:30:43 +0000 (13:30 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (119 commits)
  [SCSI] scsi_dh_rdac: Retry for NOT_READY check condition
  [SCSI] mpt2sas: make global symbols unique
  [SCSI] sd: Make revalidate less chatty
  [SCSI] sd: Try READ CAPACITY 16 first for SBC-2 devices
  [SCSI] sd: Refactor sd_read_capacity()
  [SCSI] mpt2sas v00.100.11.15
  [SCSI] mpt2sas: add MPT2SAS_MINOR(221) to miscdevice.h
  [SCSI] ch: Add scsi type modalias
  [SCSI] 3w-9xxx: add power management support
  [SCSI] bsg: add linux/types.h include to bsg.h
  [SCSI] cxgb3i: fix function descriptions
  [SCSI] libiscsi: fix possbile null ptr session command cleanup
  [SCSI] iscsi class: remove host no argument from session creation callout
  [SCSI] libiscsi: pass session failure a session struct
  [SCSI] iscsi lib: remove qdepth param from iscsi host allocation
  [SCSI] iscsi lib: have lib create work queue for transmitting IO
  [SCSI] iscsi class: fix lock dep warning on logout
  [SCSI] libiscsi: don't cap queue depth in iscsi modules
  [SCSI] iscsi_tcp: replace scsi_debug/tcp_debug logging with iscsi conn logging
  [SCSI] libiscsi_tcp: replace tcp_debug/scsi_debug logging with session/conn logging
  ...

1  2 
MAINTAINERS
drivers/net/xen-netfront.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/sg.c
drivers/usb/storage/transport.c
include/linux/bsg.h
include/linux/if_ether.h
include/linux/netdevice.h
include/linux/skbuff.h
net/core/dev.c

diff --combined MAINTAINERS
index 64c89c215b01c360d29b7079c412fc8a1b19d37c,e26fb02ac759e2644afdf5a1ea575506e0434253..d8a4c8d0a5544bbbe9d749b858eb4d4fbb1d13c3
@@@ -765,14 -765,6 +765,14 @@@ L:       linux-wireless@vger.kernel.or
  L:    ath9k-devel@lists.ath9k.org
  S:    Supported
  
 +ATHEROS AR9170 WIRELESS DRIVER
 +P:    Christian Lamparter
 +M:    chunkeey@web.de
 +L:    linux-wireless@vger.kernel.org
 +W:    http://wireless.kernel.org/en/users/Drivers/ar9170
 +S:    Maintained
 +F:    drivers/net/wireless/ar9170/
 +
  ATI_REMOTE2 DRIVER
  P:    Ville Syrjala
  M:    syrjala@sci.fi
@@@ -1019,8 -1011,6 +1019,8 @@@ L:      netdev@vger.kernel.or
  S:    Supported
  
  BROADCOM TG3 GIGABIT ETHERNET DRIVER
 +P:    Matt Carlson
 +M:    mcarlson@broadcom.com
  P:    Michael Chan
  M:    mchan@broadcom.com
  L:    netdev@vger.kernel.org
@@@ -1279,12 -1269,6 +1279,12 @@@ L:    linux-crypto@vger.kernel.or
  T:    git kernel.org:/pub/scm/linux/kernel/git/herbert/crypto-2.6.git
  S:    Maintained
  
 +CRYPTOGRAPHIC RANDOM NUMBER GENERATOR
 +P:    Neil Horman
 +M:    nhorman@tuxdriver.com
 +L:    linux-crypto@vger.kernel.org
 +S:    Maintained
 +
  CS5535 Audio ALSA driver
  P:    Jaya Kumar
  M:    jayakumar.alsa@gmail.com
@@@ -1485,6 -1469,8 +1485,6 @@@ L:      linux-acpi@vger.kernel.or
  S:    Supported
  
  DOCUMENTATION (/Documentation directory)
 -P:    Michael Kerrisk
 -M:    mtk.manpages@gmail.com
  P:    Randy Dunlap
  M:    rdunlap@xenotime.net
  L:    linux-doc@vger.kernel.org
@@@ -2232,11 -2218,6 +2232,11 @@@ M:    stefanr@s5r6.in-berlin.d
  L:    linux1394-devel@lists.sourceforge.net
  S:    Maintained
  
 +INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 +P:    Mimi Zohar
 +M:    zohar@us.ibm.com
 +S:    Supported
 +
  IMS TWINTURBO FRAMEBUFFER DRIVER
  L:    linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
  S:    Orphan
@@@ -2853,7 -2834,7 +2853,7 @@@ P:      Roman Zippe
  M:    zippel@linux-m68k.org
  L:    linux-m68k@lists.linux-m68k.org
  W:    http://www.linux-m68k.org/
 -W:    http://linux-m68k-cvs.ubb.ca/
 +T:    git git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git
  S:    Maintained
  
  M68K ON APPLE MACINTOSH
@@@ -2898,7 -2879,7 +2898,7 @@@ P:      Michael Kerris
  M:    mtk.manpages@gmail.com
  W:    http://www.kernel.org/doc/man-pages
  L:    linux-man@vger.kernel.org
 -S:    Supported
 +S:    Maintained
  
  MARVELL LIBERTAS WIRELESS DRIVER
  P:    Dan Williams
@@@ -3310,6 -3291,16 +3310,16 @@@ L:    orinoco-devel@lists.sourceforge.ne
  W:    http://www.nongnu.org/orinoco/
  S:    Maintained
  
+ OSD LIBRARY
+ P:    Boaz Harrosh
+ M:    bharrosh@panasas.com
+ P:    Benny Halevy
+ M:    bhalevy@panasas.com
+ L:    osd-dev@open-osd.org
+ W:    http://open-osd.org
+ T:    git://git.open-osd.org/open-osd.git
+ S:    Maintained
  P54 WIRELESS DRIVER
  P:    Michael Wu
  M:    flamingice@sourmilk.net
@@@ -3371,8 -3362,10 +3381,8 @@@ S:     Maintaine
  PARISC ARCHITECTURE
  P:    Kyle McMartin
  M:    kyle@mcmartin.ca
 -P:    Matthew Wilcox
 -M:    matthew@wil.cx
 -P:    Grant Grundler
 -M:    grundler@parisc-linux.org
 +P:    Helge Deller
 +M:    deller@gmx.de
  L:    linux-parisc@vger.kernel.org
  W:    http://www.parisc-linux.org/
  T:    git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
@@@ -3610,7 -3603,7 +3620,7 @@@ S:      Maintaine
  RALINK RT2X00 WIRELESS LAN DRIVER
  P:    rt2x00 project
  L:    linux-wireless@vger.kernel.org
 -L:    rt2400-devel@lists.sourceforge.net
 +L:    users@rt2x00.serialmonkey.com
  W:    http://rt2x00.serialmonkey.com/
  S:    Maintained
  T:    git kernel.org:/pub/scm/linux/kernel/git/ivd/rt2x00.git
@@@ -3656,12 -3649,6 +3666,12 @@@ M:    florian.fainelli@telecomint.e
  L:    netdev@vger.kernel.org
  S:    Maintained
  
 +RDS - RELIABLE DATAGRAM SOCKETS
 +P:    Andy Grover
 +M:    andy.grover@oracle.com
 +L:    rds-devel@oss.oracle.com
 +S:    Supported
 +
  READ-COPY UPDATE (RCU)
  P:    Dipankar Sarma
  M:    dipankar@in.ibm.com
@@@ -3753,15 -3740,6 +3763,15 @@@ L:    linux-s390@vger.kernel.or
  W:    http://www.ibm.com/developerworks/linux/linux390/
  S:    Supported
  
 +S390 ZCRYPT DRIVER
 +P:    Felix Beck
 +M:    felix.beck@de.ibm.com
 +P:    Ralph Wuerthner
 +M:    ralph.wuerthner@de.ibm.com
 +M:    linux390@de.ibm.com
 +L:    linux-s390@vger.kernel.org
 +S:    Supported
 +
  S390 ZFCP DRIVER
  P:    Christof Schmitt
  M:    christof.schmitt@de.ibm.com
@@@ -3880,7 -3858,6 +3890,7 @@@ M:      jmorris@namei.or
  L:    linux-kernel@vger.kernel.org
  L:    linux-security-module@vger.kernel.org (suggested Cc:)
  T:    git kernel.org:pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
 +W:    http://security.wiki.kernel.org/
  S:    Supported
  
  SECURITY CONTACT
@@@ -3913,15 -3890,6 +3923,15 @@@ L:    linux-ide@vger.kernel.or
  T:    git kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
  S:    Supported
  
 +SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER
 +P:    Sathya Perla
 +M:    sathyap@serverengines.com
 +P:      Subbu Seetharaman
 +M:      subbus@serverengines.com
 +L:      netdev@vger.kernel.org
 +W:      http://www.serverengines.com
 +S:      Supported
 +
  SFC NETWORK DRIVER
  P:    Steve Hodgson
  P:    Ben Hutchings
@@@ -4322,19 -4290,6 +4332,19 @@@ L:    tlan-devel@lists.sourceforge.net (su
  W:    http://sourceforge.net/projects/tlan/
  S:    Maintained
  
 +TOMOYO SECURITY MODULE
 +P:    Kentaro Takeda
 +M:    takedakn@nttdata.co.jp
 +P:    Tetsuo Handa
 +M:    penguin-kernel@I-love.SAKURA.ne.jp
 +L:    linux-kernel@vger.kernel.org (kernel issues)
 +L:    tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and users in English)
 +L:    tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
 +L:    tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
 +W:    http://tomoyo.sourceforge.jp/
 +T:    quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.2.x/tomoyo-lsm/patches/
 +S:    Maintained
 +
  TOSHIBA ACPI EXTRAS DRIVER
  P:    John Belmonte
  M:    toshiba_acpi@memebeam.org
index 9f102a6535c4976b6a7451a75bcdb19386d5d718,2ce536fcd2093463a2a2a6e90949cecc98b36646..f673253879024d18b90557be62b145feb7e99ec7
@@@ -196,7 -196,7 +196,7 @@@ static void rx_refill_timeout(unsigned 
  {
        struct net_device *dev = (struct net_device *)data;
        struct netfront_info *np = netdev_priv(dev);
 -      netif_rx_schedule(&np->napi);
 +      napi_schedule(&np->napi);
  }
  
  static int netfront_tx_slot_available(struct netfront_info *np)
@@@ -328,7 -328,7 +328,7 @@@ static int xennet_open(struct net_devic
                xennet_alloc_rx_buffers(dev);
                np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
                if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
 -                      netif_rx_schedule(&np->napi);
 +                      napi_schedule(&np->napi);
        }
        spin_unlock_bh(&np->rx_lock);
  
@@@ -979,7 -979,7 +979,7 @@@ err
  
                RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
                if (!more_to_do)
 -                      __netif_rx_complete(napi);
 +                      __napi_complete(napi);
  
                local_irq_restore(flags);
        }
@@@ -1317,7 -1317,7 +1317,7 @@@ static irqreturn_t xennet_interrupt(in
                xennet_tx_buf_gc(dev);
                /* Under tx_lock: protects access to rx shared-ring indexes. */
                if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
 -                      netif_rx_schedule(&np->napi);
 +                      napi_schedule(&np->napi);
        }
  
        spin_unlock_irqrestore(&np->tx_lock, flags);
@@@ -1511,7 -1511,7 +1511,7 @@@ static int xennet_set_tso(struct net_de
  static void xennet_set_features(struct net_device *dev)
  {
        /* Turn off all GSO bits except ROBUST. */
-       dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
+       dev->features &= ~NETIF_F_GSO_MASK;
        dev->features |= NETIF_F_GSO_ROBUST;
        xennet_set_sg(dev, 0);
  
index 3ee4eb40abcfa1c33a6f5a17e349182e63bf0a3b,2df75295921958fb24841d87255bf17819947fbb..a152f89ae51c86f45219dd4ffcc6d5fd94102966
@@@ -95,7 -95,7 +95,7 @@@ static struct 
        { FC_PORTTYPE_NPORT,    "NPort (fabric via point-to-point)" },
        { FC_PORTTYPE_NLPORT,   "NLPort (fabric via loop)" },
        { FC_PORTTYPE_LPORT,    "LPort (private loop)" },
-       { FC_PORTTYPE_PTP,      "Point-To-Point (direct nport connection" },
+       { FC_PORTTYPE_PTP,      "Point-To-Point (direct nport connection)" },
        { FC_PORTTYPE_NPIV,             "NPIV VPORT" },
  };
  fc_enum_name_search(port_type, fc_port_type, fc_port_type_names)
@@@ -533,8 -533,12 +533,8 @@@ fc_host_post_event(struct Scsi_Host *sh
        event->event_code = event_code;
        event->event_data = event_data;
  
 -      err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
 -                            GFP_KERNEL);
 -      if (err && (err != -ESRCH))     /* filter no recipient errors */
 -              /* nlmsg_multicast already kfree_skb'd */
 -              goto send_fail;
 -
 +      nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
 +                      GFP_KERNEL);
        return;
  
  send_fail_skb:
@@@ -603,8 -607,12 +603,8 @@@ fc_host_post_vendor_event(struct Scsi_H
        event->event_code = FCH_EVT_VENDOR_UNIQUE;
        memcpy(&event->event_data, data_buf, data_len);
  
 -      err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
 -                            GFP_KERNEL);
 -      if (err && (err != -ESRCH))     /* filter no recipient errors */
 -              /* nlmsg_multicast already kfree_skb'd */
 -              goto send_vendor_fail;
 -
 +      nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
 +                      GFP_KERNEL);
        return;
  
  send_vendor_fail_skb:
index 2adfab8c11c1bd541e840094aa6730823a5d18b5,2340e2c5c02178452ce79e4fe93ab76a6e86068e..094795455293eb93e3bd4b0fa275544d12ee322d
@@@ -246,30 -246,13 +246,13 @@@ static int iscsi_setup_host(struct tran
        memset(ihost, 0, sizeof(*ihost));
        atomic_set(&ihost->nr_scans, 0);
        mutex_init(&ihost->mutex);
-       snprintf(ihost->scan_workq_name, sizeof(ihost->scan_workq_name),
-                "iscsi_scan_%d", shost->host_no);
-       ihost->scan_workq = create_singlethread_workqueue(
-                                               ihost->scan_workq_name);
-       if (!ihost->scan_workq)
-               return -ENOMEM;
-       return 0;
- }
- static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
-                            struct device *cdev)
- {
-       struct Scsi_Host *shost = dev_to_shost(dev);
-       struct iscsi_cls_host *ihost = shost->shost_data;
-       destroy_workqueue(ihost->scan_workq);
        return 0;
  }
  
  static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
                               "iscsi_host",
                               iscsi_setup_host,
-                              iscsi_remove_host,
+                              NULL,
                               NULL);
  
  static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
@@@ -568,7 -551,7 +551,7 @@@ static void __iscsi_unblock_session(str
         * scanning from userspace).
         */
        if (shost->hostt->scan_finished) {
-               if (queue_work(ihost->scan_workq, &session->scan_work))
+               if (scsi_queue_work(shost, &session->scan_work))
                        atomic_inc(&ihost->nr_scans);
        }
  }
@@@ -636,14 -619,6 +619,6 @@@ static void __iscsi_unbind_session(stru
        iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
  }
  
- static int iscsi_unbind_session(struct iscsi_cls_session *session)
- {
-       struct Scsi_Host *shost = iscsi_session_to_shost(session);
-       struct iscsi_cls_host *ihost = shost->shost_data;
-       return queue_work(ihost->scan_workq, &session->unbind_work);
- }
  struct iscsi_cls_session *
  iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
                    int dd_size)
@@@ -796,7 -771,6 +771,6 @@@ static int iscsi_iter_destroy_conn_fn(s
  void iscsi_remove_session(struct iscsi_cls_session *session)
  {
        struct Scsi_Host *shost = iscsi_session_to_shost(session);
-       struct iscsi_cls_host *ihost = shost->shost_data;
        unsigned long flags;
        int err;
  
  
        scsi_target_unblock(&session->dev);
        /* flush running scans then delete devices */
-       flush_workqueue(ihost->scan_workq);
+       scsi_flush_work(shost);
        __iscsi_unbind_session(&session->unbind_work);
  
        /* hw iscsi may not have removed all connections from session */
@@@ -966,7 -940,15 +940,7 @@@ iscsi_if_transport_lookup(struct iscsi_
  static int
  iscsi_broadcast_skb(struct sk_buff *skb, gfp_t gfp)
  {
 -      int rc;
 -
 -      rc = netlink_broadcast(nls, skb, 0, 1, gfp);
 -      if (rc < 0) {
 -              printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc);
 -              return rc;
 -      }
 -
 -      return 0;
 +      return netlink_broadcast(nls, skb, 0, 1, gfp);
  }
  
  static int
@@@ -1199,7 -1181,7 +1173,7 @@@ int iscsi_session_event(struct iscsi_cl
         * the user and when the daemon is restarted it will handle it
         */
        rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
 -      if (rc < 0)
 +      if (rc == -ESRCH)
                iscsi_cls_session_printk(KERN_ERR, session,
                                         "Cannot notify userspace of session "
                                         "event %u. Check iscsi daemon\n",
@@@ -1215,14 -1197,15 +1189,15 @@@ iscsi_if_create_session(struct iscsi_in
  {
        struct iscsi_transport *transport = priv->iscsi_transport;
        struct iscsi_cls_session *session;
-       uint32_t host_no;
+       struct Scsi_Host *shost;
  
        session = transport->create_session(ep, cmds_max, queue_depth,
-                                           initial_cmdsn, &host_no);
+                                           initial_cmdsn);
        if (!session)
                return -ENOMEM;
  
-       ev->r.c_session_ret.host_no = host_no;
+       shost = iscsi_session_to_shost(session);
+       ev->r.c_session_ret.host_no = shost->host_no;
        ev->r.c_session_ret.sid = session->sid;
        return 0;
  }
@@@ -1439,7 -1422,8 +1414,8 @@@ iscsi_if_recv_msg(struct sk_buff *skb, 
        case ISCSI_UEVENT_UNBIND_SESSION:
                session = iscsi_session_lookup(ev->u.d_session.sid);
                if (session)
-                       iscsi_unbind_session(session);
+                       scsi_queue_work(iscsi_session_to_shost(session),
+                                       &session->unbind_work);
                else
                        err = -EINVAL;
                break;
@@@ -1801,8 -1785,7 +1777,7 @@@ iscsi_register_transport(struct iscsi_t
        priv->daemon_pid = -1;
        priv->iscsi_transport = tt;
        priv->t.user_scan = iscsi_user_scan;
-       if (!(tt->caps & CAP_DATA_PATH_OFFLOAD))
-               priv->t.create_work_queue = 1;
+       priv->t.create_work_queue = 1;
  
        priv->dev.class = &iscsi_transport_class;
        dev_set_name(&priv->dev, "%s", tt->name);
diff --combined drivers/scsi/sg.c
index b4ef2f84ea32ae6a5e3dca480da58ef486345ce2,7bf54c9a33bb9d958929c5e5cfca2fbd83d33c65..ffc87851f2e86e866616da6a6c0e39ca48dd1910
@@@ -98,7 -98,6 +98,6 @@@ static int scatter_elem_sz = SG_SCATTER
  static int scatter_elem_sz_prev = SG_SCATTER_SZ;
  
  #define SG_SECTOR_SZ 512
- #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
  
  static int sg_add(struct device *, struct class_interface *);
  static void sg_remove(struct device *, struct class_interface *);
@@@ -137,10 -136,11 +136,11 @@@ typedef struct sg_request {     /* SG_MAX_Q
        volatile char done;     /* 0->before bh, 1->before read, 2->read */
        struct request *rq;
        struct bio *bio;
+       struct execute_work ew;
  } Sg_request;
  
  typedef struct sg_fd {                /* holds the state of a file descriptor */
-       struct sg_fd *nextfp;   /* NULL when last opened fd on this device */
+       struct list_head sfd_siblings;
        struct sg_device *parentdp;     /* owning device */
        wait_queue_head_t read_wait;    /* queue read until command done */
        rwlock_t rq_list_lock;  /* protect access to list in req_arr */
        char next_cmd_len;      /* 0 -> automatic (def), >0 -> use on next write() */
        char keep_orphan;       /* 0 -> drop orphan (def), 1 -> keep for read() */
        char mmap_called;       /* 0 -> mmap() never called on this fd */
+       struct kref f_ref;
+       struct execute_work ew;
  } Sg_fd;
  
  typedef struct sg_device { /* holds the state of each scsi generic device */
        wait_queue_head_t o_excl_wait;  /* queue open() when O_EXCL in use */
        int sg_tablesize;       /* adapter's max scatter-gather table size */
        u32 index;              /* device index number */
-       Sg_fd *headfp;          /* first open fd belonging to this device */
+       struct list_head sfds;
        volatile char detached; /* 0->attached, 1->detached pending removal */
        volatile char exclude;  /* opened for exclusive access */
        char sgdebug;           /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
        struct gendisk *disk;
        struct cdev * cdev;     /* char_dev [sysfs: /sys/cdev/major/sg<n>] */
+       struct kref d_ref;
  } Sg_device;
  
- static int sg_fasync(int fd, struct file *filp, int mode);
  /* tasklet or soft irq callback */
  static void sg_rq_end_io(struct request *rq, int uptodate);
  static int sg_start_req(Sg_request *srp, unsigned char *cmd);
  static void sg_finish_rem_req(Sg_request * srp);
  static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
- static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
-                        int tablesize);
  static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
                           Sg_request * srp);
  static ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
                        const char __user *buf, size_t count, int blocking,
-                       int read_only, Sg_request **o_srp);
+                       int read_only, int sg_io_owned, Sg_request **o_srp);
  static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
                           unsigned char *cmnd, int timeout, int blocking);
  static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer);
@@@ -194,16 -194,13 +194,13 @@@ static void sg_build_reserve(Sg_fd * sf
  static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
  static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
  static Sg_fd *sg_add_sfp(Sg_device * sdp, int dev);
- static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
- static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
+ static void sg_remove_sfp(struct kref *);
  static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
  static Sg_request *sg_add_request(Sg_fd * sfp);
  static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
  static int sg_res_in_use(Sg_fd * sfp);
  static Sg_device *sg_get_dev(int dev);
- #ifdef CONFIG_SCSI_PROC_FS
- static int sg_last_dev(void);
- #endif
+ static void sg_put_dev(Sg_device *sdp);
  
  #define SZ_SG_HEADER sizeof(struct sg_header)
  #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
@@@ -237,22 -234,17 +234,17 @@@ sg_open(struct inode *inode, struct fil
        nonseekable_open(inode, filp);
        SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
        sdp = sg_get_dev(dev);
-       if ((!sdp) || (!sdp->device)) {
-               unlock_kernel();
-               return -ENXIO;
-       }
-       if (sdp->detached) {
-               unlock_kernel();
-               return -ENODEV;
+       if (IS_ERR(sdp)) {
+               retval = PTR_ERR(sdp);
+               sdp = NULL;
+               goto sg_put;
        }
  
        /* This driver's module count bumped by fops_get in <linux/fs.h> */
        /* Prevent the device driver from vanishing while we sleep */
        retval = scsi_device_get(sdp->device);
-       if (retval) {
-               unlock_kernel();
-               return retval;
-       }
+       if (retval)
+               goto sg_put;
  
        if (!((flags & O_NONBLOCK) ||
              scsi_block_when_processing_errors(sdp->device))) {
                        retval = -EPERM; /* Can't lock it with read only access */
                        goto error_out;
                }
-               if (sdp->headfp && (flags & O_NONBLOCK)) {
+               if (!list_empty(&sdp->sfds) && (flags & O_NONBLOCK)) {
                        retval = -EBUSY;
                        goto error_out;
                }
                res = 0;
                __wait_event_interruptible(sdp->o_excl_wait,
-                       ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), res);
+                                          ((!list_empty(&sdp->sfds) || sdp->exclude) ? 0 : (sdp->exclude = 1)), res);
                if (res) {
                        retval = res;   /* -ERESTARTSYS because signal hit process */
                        goto error_out;
                retval = -ENODEV;
                goto error_out;
        }
-       if (!sdp->headfp) {     /* no existing opens on this device */
+       if (list_empty(&sdp->sfds)) {   /* no existing opens on this device */
                sdp->sgdebug = 0;
                q = sdp->device->request_queue;
                sdp->sg_tablesize = min(q->max_hw_segments,
        if ((sfp = sg_add_sfp(sdp, dev)))
                filp->private_data = sfp;
        else {
-               if (flags & O_EXCL)
+               if (flags & O_EXCL) {
                        sdp->exclude = 0;       /* undo if error */
+                       wake_up_interruptible(&sdp->o_excl_wait);
+               }
                retval = -ENOMEM;
                goto error_out;
        }
-       unlock_kernel();
-       return 0;
-       error_out:
-       scsi_device_put(sdp->device);
+       retval = 0;
+ error_out:
+       if (retval)
+               scsi_device_put(sdp->device);
+ sg_put:
+       if (sdp)
+               sg_put_dev(sdp);
        unlock_kernel();
        return retval;
  }
@@@ -327,13 -323,13 +323,13 @@@ sg_release(struct inode *inode, struct 
        if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
                return -ENXIO;
        SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
-       if (0 == sg_remove_sfp(sdp, sfp)) {     /* Returns 1 when sdp gone */
-               if (!sdp->detached) {
-                       scsi_device_put(sdp->device);
-               }
-               sdp->exclude = 0;
-               wake_up_interruptible(&sdp->o_excl_wait);
-       }
+       sfp->closed = 1;
+       sdp->exclude = 0;
+       wake_up_interruptible(&sdp->o_excl_wait);
+       kref_put(&sfp->f_ref, sg_remove_sfp);
        return 0;
  }
  
@@@ -557,7 -553,8 +553,8 @@@ sg_write(struct file *filp, const char 
                return -EFAULT;
        blocking = !(filp->f_flags & O_NONBLOCK);
        if (old_hdr.reply_len < 0)
-               return sg_new_write(sfp, filp, buf, count, blocking, 0, NULL);
+               return sg_new_write(sfp, filp, buf, count,
+                                   blocking, 0, 0, NULL);
        if (count < (SZ_SG_HEADER + 6))
                return -EIO;    /* The minimum scsi command length is 6 bytes. */
  
  
  static ssize_t
  sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
-                size_t count, int blocking, int read_only,
+                size_t count, int blocking, int read_only, int sg_io_owned,
                 Sg_request **o_srp)
  {
        int k;
                SCSI_LOG_TIMEOUT(1, printk("sg_new_write: queue full\n"));
                return -EDOM;
        }
+       srp->sg_io_owned = sg_io_owned;
        hp = &srp->header;
        if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) {
                sg_remove_request(sfp, srp);
@@@ -755,23 -753,12 +753,12 @@@ sg_common_write(Sg_fd * sfp, Sg_reques
        hp->duration = jiffies_to_msecs(jiffies);
  
        srp->rq->timeout = timeout;
+       kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */
        blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk,
                              srp->rq, 1, sg_rq_end_io);
        return 0;
  }
  
- static int
- sg_srp_done(Sg_request *srp, Sg_fd *sfp)
- {
-       unsigned long iflags;
-       int done;
-       read_lock_irqsave(&sfp->rq_list_lock, iflags);
-       done = srp->done;
-       read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-       return done;
- }
  static int
  sg_ioctl(struct inode *inode, struct file *filp,
         unsigned int cmd_in, unsigned long arg)
                                return -EFAULT;
                        result =
                            sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
-                                        blocking, read_only, &srp);
+                                        blocking, read_only, 1, &srp);
                        if (result < 0)
                                return result;
-                       srp->sg_io_owned = 1;
                        while (1) {
                                result = 0;     /* following macro to beat race condition */
                                __wait_event_interruptible(sfp->read_wait,
-                                       (sdp->detached || sfp->closed || sg_srp_done(srp, sfp)),
-                                                          result);
+                                       (srp->done || sdp->detached),
+                                       result);
                                if (sdp->detached)
                                        return -ENODEV;
-                               if (sfp->closed)
-                                       return 0;       /* request packet dropped already */
-                               if (0 == result)
+                               write_lock_irq(&sfp->rq_list_lock);
+                               if (srp->done) {
+                                       srp->done = 2;
+                                       write_unlock_irq(&sfp->rq_list_lock);
                                        break;
+                               }
                                srp->orphan = 1;
+                               write_unlock_irq(&sfp->rq_list_lock);
                                return result;  /* -ERESTARTSYS because signal hit process */
                        }
-                       write_lock_irqsave(&sfp->rq_list_lock, iflags);
-                       srp->done = 2;
-                       write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
                        result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp);
                        return (result < 0) ? result : 0;
                }
@@@ -1154,6 -1140,7 +1140,6 @@@ sg_poll(struct file *filp, poll_table 
  static int
  sg_fasync(int fd, struct file *filp, int mode)
  {
 -      int retval;
        Sg_device *sdp;
        Sg_fd *sfp;
  
        SCSI_LOG_TIMEOUT(3, printk("sg_fasync: %s, mode=%d\n",
                                   sdp->disk->disk_name, mode));
  
 -      retval = fasync_helper(fd, filp, mode, &sfp->async_qp);
 -      return (retval < 0) ? retval : 0;
 +      return fasync_helper(fd, filp, mode, &sfp->async_qp);
  }
  
  static int
@@@ -1238,6 -1226,15 +1224,15 @@@ sg_mmap(struct file *filp, struct vm_ar
        return 0;
  }
  
+ static void sg_rq_end_io_usercontext(struct work_struct *work)
+ {
+       struct sg_request *srp = container_of(work, struct sg_request, ew.work);
+       struct sg_fd *sfp = srp->parentfp;
+       sg_finish_rem_req(srp);
+       kref_put(&sfp->f_ref, sg_remove_sfp);
+ }
  /*
   * This function is a "bottom half" handler that is called by the mid
   * level when a command is completed (or has failed).
  static void sg_rq_end_io(struct request *rq, int uptodate)
  {
        struct sg_request *srp = rq->end_io_data;
-       Sg_device *sdp = NULL;
+       Sg_device *sdp;
        Sg_fd *sfp;
        unsigned long iflags;
        unsigned int ms;
        char *sense;
-       int result, resid;
+       int result, resid, done = 1;
  
-       if (NULL == srp) {
-               printk(KERN_ERR "sg_cmd_done: NULL request\n");
+       if (WARN_ON(srp->done != 0))
                return;
-       }
        sfp = srp->parentfp;
-       if (sfp)
-               sdp = sfp->parentdp;
-       if ((NULL == sdp) || sdp->detached) {
-               printk(KERN_INFO "sg_cmd_done: device detached\n");
+       if (WARN_ON(sfp == NULL))
                return;
-       }
+       sdp = sfp->parentdp;
+       if (unlikely(sdp->detached))
+               printk(KERN_INFO "sg_rq_end_io: device detached\n");
  
        sense = rq->sense;
        result = rq->errors;
        }
        /* Rely on write phase to clean out srp status values, so no "else" */
  
-       if (sfp->closed) {      /* whoops this fd already released, cleanup */
-               SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, freeing ...\n"));
-               sg_finish_rem_req(srp);
-               srp = NULL;
-               if (NULL == sfp->headrp) {
-                       SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, final cleanup\n"));
-                       if (0 == sg_remove_sfp(sdp, sfp)) {     /* device still present */
-                               scsi_device_put(sdp->device);
-                       }
-                       sfp = NULL;
-               }
-       } else if (srp && srp->orphan) {
+       write_lock_irqsave(&sfp->rq_list_lock, iflags);
+       if (unlikely(srp->orphan)) {
                if (sfp->keep_orphan)
                        srp->sg_io_owned = 0;
-               else {
-                       sg_finish_rem_req(srp);
-                       srp = NULL;
-               }
+               else
+                       done = 0;
        }
-       if (sfp && srp) {
-               /* Now wake up any sg_read() that is waiting for this packet. */
-               kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
-               write_lock_irqsave(&sfp->rq_list_lock, iflags);
-               srp->done = 1;
+       srp->done = done;
+       write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+       if (likely(done)) {
+               /* Now wake up any sg_read() that is waiting for this
+                * packet.
+                */
                wake_up_interruptible(&sfp->read_wait);
-               write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-       }
+               kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
+               kref_put(&sfp->f_ref, sg_remove_sfp);
+       } else
+               execute_in_process_context(sg_rq_end_io_usercontext, &srp->ew);
  }
  
  static struct file_operations sg_fops = {
@@@ -1362,17 -1350,18 +1348,18 @@@ static Sg_device *sg_alloc(struct gendi
                printk(KERN_WARNING "kmalloc Sg_device failure\n");
                return ERR_PTR(-ENOMEM);
        }
-       error = -ENOMEM;
        if (!idr_pre_get(&sg_index_idr, GFP_KERNEL)) {
                printk(KERN_WARNING "idr expansion Sg_device failure\n");
+               error = -ENOMEM;
                goto out;
        }
  
        write_lock_irqsave(&sg_index_lock, iflags);
-       error = idr_get_new(&sg_index_idr, sdp, &k);
-       write_unlock_irqrestore(&sg_index_lock, iflags);
  
+       error = idr_get_new(&sg_index_idr, sdp, &k);
        if (error) {
+               write_unlock_irqrestore(&sg_index_lock, iflags);
                printk(KERN_WARNING "idr allocation Sg_device failure: %d\n",
                       error);
                goto out;
        disk->first_minor = k;
        sdp->disk = disk;
        sdp->device = scsidp;
+       INIT_LIST_HEAD(&sdp->sfds);
        init_waitqueue_head(&sdp->o_excl_wait);
        sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments);
        sdp->index = k;
+       kref_init(&sdp->d_ref);
+       write_unlock_irqrestore(&sg_index_lock, iflags);
  
        error = 0;
   out:
        return sdp;
  
   overflow:
+       idr_remove(&sg_index_idr, k);
+       write_unlock_irqrestore(&sg_index_lock, iflags);
        sdev_printk(KERN_WARNING, scsidp,
                    "Unable to attach sg device type=%d, minor "
                    "number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1);
        return error;
  }
  
- static void
- sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
+ static void sg_device_destroy(struct kref *kref)
+ {
+       struct sg_device *sdp = container_of(kref, struct sg_device, d_ref);
+       unsigned long flags;
+       /* CAUTION!  Note that the device can still be found via idr_find()
+        * even though the refcount is 0.  Therefore, do idr_remove() BEFORE
+        * any other cleanup.
+        */
+       write_lock_irqsave(&sg_index_lock, flags);
+       idr_remove(&sg_index_idr, sdp->index);
+       write_unlock_irqrestore(&sg_index_lock, flags);
+       SCSI_LOG_TIMEOUT(3,
+               printk("sg_device_destroy: %s\n",
+                       sdp->disk->disk_name));
+       put_disk(sdp->disk);
+       kfree(sdp);
+ }
+ static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf)
  {
        struct scsi_device *scsidp = to_scsi_device(cl_dev->parent);
        Sg_device *sdp = dev_get_drvdata(cl_dev);
        unsigned long iflags;
        Sg_fd *sfp;
-       Sg_fd *tsfp;
-       Sg_request *srp;
-       Sg_request *tsrp;
-       int delay;
  
-       if (!sdp)
+       if (!sdp || sdp->detached)
                return;
  
-       delay = 0;
+       SCSI_LOG_TIMEOUT(3, printk("sg_remove: %s\n", sdp->disk->disk_name));
+       /* Need a write lock to set sdp->detached. */
        write_lock_irqsave(&sg_index_lock, iflags);
-       if (sdp->headfp) {
-               sdp->detached = 1;
-               for (sfp = sdp->headfp; sfp; sfp = tsfp) {
-                       tsfp = sfp->nextfp;
-                       for (srp = sfp->headrp; srp; srp = tsrp) {
-                               tsrp = srp->nextrp;
-                               if (sfp->closed || (0 == sg_srp_done(srp, sfp)))
-                                       sg_finish_rem_req(srp);
-                       }
-                       if (sfp->closed) {
-                               scsi_device_put(sdp->device);
-                               __sg_remove_sfp(sdp, sfp);
-                       } else {
-                               delay = 1;
-                               wake_up_interruptible(&sfp->read_wait);
-                               kill_fasync(&sfp->async_qp, SIGPOLL,
-                                           POLL_HUP);
-                       }
-               }
-               SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", sdp->index));
-               if (NULL == sdp->headfp) {
-                       idr_remove(&sg_index_idr, sdp->index);
-               }
-       } else {        /* nothing active, simple case */
-               SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", sdp->index));
-               idr_remove(&sg_index_idr, sdp->index);
+       sdp->detached = 1;
+       list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) {
+               wake_up_interruptible(&sfp->read_wait);
+               kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP);
        }
        write_unlock_irqrestore(&sg_index_lock, iflags);
  
        device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index));
        cdev_del(sdp->cdev);
        sdp->cdev = NULL;
-       put_disk(sdp->disk);
-       sdp->disk = NULL;
-       if (NULL == sdp->headfp)
-               kfree(sdp);
  
-       if (delay)
-               msleep(10);     /* dirty detach so delay device destruction */
+       sg_put_dev(sdp);
  }
  
  module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
@@@ -1736,8 -1723,8 +1721,8 @@@ sg_build_indirect(Sg_scatter_hold * sch
                return -EFAULT;
        if (0 == blk_size)
                ++blk_size;     /* don't know why */
- /* round request up to next highest SG_SECTOR_SZ byte boundary */
-       blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
      /* round request up to next highest SG_SECTOR_SZ byte boundary */
+       blk_size = ALIGN(blk_size, SG_SECTOR_SZ);
        SCSI_LOG_TIMEOUT(4, printk("sg_build_indirect: buff_size=%d, blk_size=%d\n",
                                   buff_size, blk_size));
  
@@@ -1939,22 -1926,6 +1924,6 @@@ sg_get_rq_mark(Sg_fd * sfp, int pack_id
        return resp;
  }
  
- #ifdef CONFIG_SCSI_PROC_FS
- static Sg_request *
- sg_get_nth_request(Sg_fd * sfp, int nth)
- {
-       Sg_request *resp;
-       unsigned long iflags;
-       int k;
-       read_lock_irqsave(&sfp->rq_list_lock, iflags);
-       for (k = 0, resp = sfp->headrp; resp && (k < nth);
-            ++k, resp = resp->nextrp) ;
-       read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
-       return resp;
- }
- #endif
  /* always adds to end of list */
  static Sg_request *
  sg_add_request(Sg_fd * sfp)
@@@ -2030,22 -2001,6 +1999,6 @@@ sg_remove_request(Sg_fd * sfp, Sg_reque
        return res;
  }
  
- #ifdef CONFIG_SCSI_PROC_FS
- static Sg_fd *
- sg_get_nth_sfp(Sg_device * sdp, int nth)
- {
-       Sg_fd *resp;
-       unsigned long iflags;
-       int k;
-       read_lock_irqsave(&sg_index_lock, iflags);
-       for (k = 0, resp = sdp->headfp; resp && (k < nth);
-            ++k, resp = resp->nextfp) ;
-       read_unlock_irqrestore(&sg_index_lock, iflags);
-       return resp;
- }
- #endif
  static Sg_fd *
  sg_add_sfp(Sg_device * sdp, int dev)
  {
        init_waitqueue_head(&sfp->read_wait);
        rwlock_init(&sfp->rq_list_lock);
  
+       kref_init(&sfp->f_ref);
        sfp->timeout = SG_DEFAULT_TIMEOUT;
        sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
        sfp->force_packid = SG_DEF_FORCE_PACK_ID;
        sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
        sfp->parentdp = sdp;
        write_lock_irqsave(&sg_index_lock, iflags);
-       if (!sdp->headfp)
-               sdp->headfp = sfp;
-       else {                  /* add to tail of existing list */
-               Sg_fd *pfp = sdp->headfp;
-               while (pfp->nextfp)
-                       pfp = pfp->nextfp;
-               pfp->nextfp = sfp;
-       }
+       list_add_tail(&sfp->sfd_siblings, &sdp->sfds);
        write_unlock_irqrestore(&sg_index_lock, iflags);
        SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
        if (unlikely(sg_big_buff != def_reserved_size))
        sg_build_reserve(sfp, bufflen);
        SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   bufflen=%d, k_use_sg=%d\n",
                           sfp->reserve.bufflen, sfp->reserve.k_use_sg));
+       kref_get(&sdp->d_ref);
+       __module_get(THIS_MODULE);
        return sfp;
  }
  
- static void
- __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
+ static void sg_remove_sfp_usercontext(struct work_struct *work)
  {
-       Sg_fd *fp;
-       Sg_fd *prev_fp;
+       struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
+       struct sg_device *sdp = sfp->parentdp;
+       /* Cleanup any responses which were never read(). */
+       while (sfp->headrp)
+               sg_finish_rem_req(sfp->headrp);
  
-       prev_fp = sdp->headfp;
-       if (sfp == prev_fp)
-               sdp->headfp = prev_fp->nextfp;
-       else {
-               while ((fp = prev_fp->nextfp)) {
-                       if (sfp == fp) {
-                               prev_fp->nextfp = fp->nextfp;
-                               break;
-                       }
-                       prev_fp = fp;
-               }
-       }
        if (sfp->reserve.bufflen > 0) {
-               SCSI_LOG_TIMEOUT(6, 
-                       printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
-                       (int) sfp->reserve.bufflen, (int) sfp->reserve.k_use_sg));
+               SCSI_LOG_TIMEOUT(6,
+                       printk("sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
+                               (int) sfp->reserve.bufflen,
+                               (int) sfp->reserve.k_use_sg));
                sg_remove_scat(&sfp->reserve);
        }
-       sfp->parentdp = NULL;
-       SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    sfp=0x%p\n", sfp));
+       SCSI_LOG_TIMEOUT(6,
+               printk("sg_remove_sfp: %s, sfp=0x%p\n",
+                       sdp->disk->disk_name,
+                       sfp));
        kfree(sfp);
+       scsi_device_put(sdp->device);
+       sg_put_dev(sdp);
+       module_put(THIS_MODULE);
  }
  
- /* Returns 0 in normal case, 1 when detached and sdp object removed */
- static int
- sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
+ static void sg_remove_sfp(struct kref *kref)
  {
-       Sg_request *srp;
-       Sg_request *tsrp;
-       int dirty = 0;
-       int res = 0;
+       struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref);
+       struct sg_device *sdp = sfp->parentdp;
+       unsigned long iflags;
  
-       for (srp = sfp->headrp; srp; srp = tsrp) {
-               tsrp = srp->nextrp;
-               if (sg_srp_done(srp, sfp))
-                       sg_finish_rem_req(srp);
-               else
-                       ++dirty;
-       }
-       if (0 == dirty) {
-               unsigned long iflags;
-               write_lock_irqsave(&sg_index_lock, iflags);
-               __sg_remove_sfp(sdp, sfp);
-               if (sdp->detached && (NULL == sdp->headfp)) {
-                       idr_remove(&sg_index_idr, sdp->index);
-                       kfree(sdp);
-                       res = 1;
-               }
-               write_unlock_irqrestore(&sg_index_lock, iflags);
-       } else {
-               /* MOD_INC's to inhibit unloading sg and associated adapter driver */
-               /* only bump the access_count if we actually succeeded in
-                * throwing another counter on the host module */
-               scsi_device_get(sdp->device);   /* XXX: retval ignored? */      
-               sfp->closed = 1;        /* flag dirty state on this fd */
-               SCSI_LOG_TIMEOUT(1, printk("sg_remove_sfp: worrisome, %d writes pending\n",
-                                 dirty));
-       }
-       return res;
+       write_lock_irqsave(&sg_index_lock, iflags);
+       list_del(&sfp->sfd_siblings);
+       write_unlock_irqrestore(&sg_index_lock, iflags);
+       wake_up_interruptible(&sdp->o_excl_wait);
+       execute_in_process_context(sg_remove_sfp_usercontext, &sfp->ew);
  }
  
  static int
@@@ -2197,19 -2123,38 +2121,38 @@@ sg_last_dev(void
  }
  #endif
  
- static Sg_device *
- sg_get_dev(int dev)
+ /* must be called with sg_index_lock held */
+ static Sg_device *sg_lookup_dev(int dev)
  {
-       Sg_device *sdp;
-       unsigned long iflags;
+       return idr_find(&sg_index_idr, dev);
+ }
  
-       read_lock_irqsave(&sg_index_lock, iflags);
-       sdp = idr_find(&sg_index_idr, dev);
-       read_unlock_irqrestore(&sg_index_lock, iflags);
+ static Sg_device *sg_get_dev(int dev)
+ {
+       struct sg_device *sdp;
+       unsigned long flags;
+       read_lock_irqsave(&sg_index_lock, flags);
+       sdp = sg_lookup_dev(dev);
+       if (!sdp)
+               sdp = ERR_PTR(-ENXIO);
+       else if (sdp->detached) {
+               /* If sdp->detached, then the refcount may already be 0, in
+                * which case it would be a bug to do kref_get().
+                */
+               sdp = ERR_PTR(-ENODEV);
+       } else
+               kref_get(&sdp->d_ref);
+       read_unlock_irqrestore(&sg_index_lock, flags);
  
        return sdp;
  }
  
+ static void sg_put_dev(struct sg_device *sdp)
+ {
+       kref_put(&sdp->d_ref, sg_device_destroy);
+ }
  #ifdef CONFIG_SCSI_PROC_FS
  
  static struct proc_dir_entry *sg_proc_sgp = NULL;
@@@ -2466,8 -2411,10 +2409,10 @@@ static int sg_proc_seq_show_dev(struct 
        struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
        Sg_device *sdp;
        struct scsi_device *scsidp;
+       unsigned long iflags;
  
-       sdp = it ? sg_get_dev(it->index) : NULL;
+       read_lock_irqsave(&sg_index_lock, iflags);
+       sdp = it ? sg_lookup_dev(it->index) : NULL;
        if (sdp && (scsidp = sdp->device) && (!sdp->detached))
                seq_printf(s, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
                              scsidp->host->host_no, scsidp->channel,
                              (int) scsi_device_online(scsidp));
        else
                seq_printf(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
+       read_unlock_irqrestore(&sg_index_lock, iflags);
        return 0;
  }
  
@@@ -2491,16 -2439,20 +2437,20 @@@ static int sg_proc_seq_show_devstrs(str
        struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
        Sg_device *sdp;
        struct scsi_device *scsidp;
+       unsigned long iflags;
  
-       sdp = it ? sg_get_dev(it->index) : NULL;
+       read_lock_irqsave(&sg_index_lock, iflags);
+       sdp = it ? sg_lookup_dev(it->index) : NULL;
        if (sdp && (scsidp = sdp->device) && (!sdp->detached))
                seq_printf(s, "%8.8s\t%16.16s\t%4.4s\n",
                           scsidp->vendor, scsidp->model, scsidp->rev);
        else
                seq_printf(s, "<no active device>\n");
+       read_unlock_irqrestore(&sg_index_lock, iflags);
        return 0;
  }
  
+ /* must be called while holding sg_index_lock */
  static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
  {
        int k, m, new_interface, blen, usg;
        const char * cp;
        unsigned int ms;
  
-       for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) {
+       k = 0;
+       list_for_each_entry(fp, &sdp->sfds, sfd_siblings) {
+               k++;
+               read_lock(&fp->rq_list_lock); /* irqs already disabled */
                seq_printf(s, "   FD(%d): timeout=%dms bufflen=%d "
-                          "(res)sgat=%d low_dma=%d\n", k + 1,
+                          "(res)sgat=%d low_dma=%d\n", k,
                           jiffies_to_msecs(fp->timeout),
                           fp->reserve.bufflen,
                           (int) fp->reserve.k_use_sg,
                seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n",
                           (int) fp->cmd_q, (int) fp->force_packid,
                           (int) fp->keep_orphan, (int) fp->closed);
-               for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) {
+               for (m = 0, srp = fp->headrp;
+                               srp != NULL;
+                               ++m, srp = srp->nextrp) {
                        hp = &srp->header;
                        new_interface = (hp->interface_id == '\0') ? 0 : 1;
                        if (srp->res_used) {
                }
                if (0 == m)
                        seq_printf(s, "     No requests active\n");
+               read_unlock(&fp->rq_list_lock);
        }
  }
  
@@@ -2569,39 -2527,34 +2525,34 @@@ static int sg_proc_seq_show_debug(struc
  {
        struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
        Sg_device *sdp;
+       unsigned long iflags;
  
        if (it && (0 == it->index)) {
                seq_printf(s, "max_active_device=%d(origin 1)\n",
                           (int)it->max);
                seq_printf(s, " def_reserved_size=%d\n", sg_big_buff);
        }
-       sdp = it ? sg_get_dev(it->index) : NULL;
-       if (sdp) {
-               struct scsi_device *scsidp = sdp->device;
  
-               if (NULL == scsidp) {
-                       seq_printf(s, "device %d detached ??\n", 
-                                  (int)it->index);
-                       return 0;
-               }
+       read_lock_irqsave(&sg_index_lock, iflags);
+       sdp = it ? sg_lookup_dev(it->index) : NULL;
+       if (sdp && !list_empty(&sdp->sfds)) {
+               struct scsi_device *scsidp = sdp->device;
  
-               if (sg_get_nth_sfp(sdp, 0)) {
-                       seq_printf(s, " >>> device=%s ",
-                               sdp->disk->disk_name);
-                       if (sdp->detached)
-                               seq_printf(s, "detached pending close ");
-                       else
-                               seq_printf
-                                   (s, "scsi%d chan=%d id=%d lun=%d   em=%d",
-                                    scsidp->host->host_no,
-                                    scsidp->channel, scsidp->id,
-                                    scsidp->lun,
-                                    scsidp->host->hostt->emulated);
-                       seq_printf(s, " sg_tablesize=%d excl=%d\n",
-                                  sdp->sg_tablesize, sdp->exclude);
-               }
+               seq_printf(s, " >>> device=%s ", sdp->disk->disk_name);
+               if (sdp->detached)
+                       seq_printf(s, "detached pending close ");
+               else
+                       seq_printf
+                           (s, "scsi%d chan=%d id=%d lun=%d   em=%d",
+                            scsidp->host->host_no,
+                            scsidp->channel, scsidp->id,
+                            scsidp->lun,
+                            scsidp->host->hostt->emulated);
+               seq_printf(s, " sg_tablesize=%d excl=%d\n",
+                          sdp->sg_tablesize, sdp->exclude);
                sg_proc_debug_helper(s, sdp);
        }
+       read_unlock_irqrestore(&sg_index_lock, iflags);
        return 0;
  }
  
index d48c8553539dd6354acb6b3323304589aa19a8e1,02e30a3ce7bf563b669ce36ba9a84a4f07a5d42e..49aedb36dc19426fb7e3b34603dbab8aeedabfee
@@@ -220,7 -220,6 +220,7 @@@ int usb_stor_control_msg(struct us_dat
                status = us->current_urb->actual_length;
        return status;
  }
 +EXPORT_SYMBOL_GPL(usb_stor_control_msg);
  
  /* This is a version of usb_clear_halt() that allows early termination and
   * doesn't read the status from the device -- this is because some devices
@@@ -255,7 -254,6 +255,7 @@@ int usb_stor_clear_halt(struct us_data 
        US_DEBUGP("%s: result = %d\n", __func__, result);
        return result;
  }
 +EXPORT_SYMBOL_GPL(usb_stor_clear_halt);
  
  
  /*
@@@ -354,7 -352,6 +354,7 @@@ int usb_stor_ctrl_transfer(struct us_da
        return interpret_urb_result(us, pipe, size, result,
                        us->current_urb->actual_length);
  }
 +EXPORT_SYMBOL_GPL(usb_stor_ctrl_transfer);
  
  /*
   * Receive one interrupt buffer, without timeouts, but allowing early
@@@ -410,7 -407,6 +410,7 @@@ int usb_stor_bulk_transfer_buf(struct u
        return interpret_urb_result(us, pipe, length, result, 
                        us->current_urb->actual_length);
  }
 +EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf);
  
  /*
   * Transfer a scatter-gather list via bulk transfer
@@@ -478,7 -474,6 +478,7 @@@ int usb_stor_bulk_srb(struct us_data* u
        scsi_set_resid(srb, scsi_bufflen(srb) - partial);
        return result;
  }
 +EXPORT_SYMBOL_GPL(usb_stor_bulk_srb);
  
  /*
   * Transfer an entire SCSI command's worth of data payload over the bulk
@@@ -514,7 -509,6 +514,7 @@@ int usb_stor_bulk_transfer_sg(struct us
                *residual = length_left;
        return result;
  }
 +EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_sg);
  
  /***********************************************************************
   * Transport routines
@@@ -787,7 -781,7 +787,7 @@@ void usb_stor_invoke_transport(struct s
        /* Did we transfer less than the minimum amount required? */
        if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) &&
                        scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
-               srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
+               srb->result = DID_ERROR << 16;
  
        last_sector_hacks(us, srb);
        return;
@@@ -946,7 -940,6 +946,7 @@@ int usb_stor_CB_transport(struct scsi_c
                usb_stor_clear_halt(us, pipe);
        return USB_STOR_TRANSPORT_FAILED;
  }
 +EXPORT_SYMBOL_GPL(usb_stor_CB_transport);
  
  /*
   * Bulk only transport
@@@ -1163,7 -1156,6 +1163,7 @@@ int usb_stor_Bulk_transport(struct scsi
        /* we should never get here, but if we do, we're in trouble */
        return USB_STOR_TRANSPORT_ERROR;
  }
 +EXPORT_SYMBOL_GPL(usb_stor_Bulk_transport);
  
  /***********************************************************************
   * Reset routines
@@@ -1238,7 -1230,6 +1238,7 @@@ int usb_stor_CB_reset(struct us_data *u
                                 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                                 0, us->ifnum, us->iobuf, CB_RESET_CMD_SIZE);
  }
 +EXPORT_SYMBOL_GPL(usb_stor_CB_reset);
  
  /* This issues a Bulk-only Reset to the device in question, including
   * clearing the subsequent endpoint halts that may occur.
@@@ -1251,7 -1242,6 +1251,7 @@@ int usb_stor_Bulk_reset(struct us_data 
                                 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                                 0, us->ifnum, NULL, 0);
  }
 +EXPORT_SYMBOL_GPL(usb_stor_Bulk_reset);
  
  /* Issue a USB port reset to the device.  The caller must not hold
   * us->dev_mutex.
diff --combined include/linux/bsg.h
index 3f0c64ace4247eae6a13fe80f0e92cc298e51d4c,6c0a00dfa90c43a521968cc8b5d9e6ee6563c6d2..ecb4730d0868504d1ed9d0cb58a3522c38073695
@@@ -1,20 -1,14 +1,22 @@@
  #ifndef BSG_H
  #define BSG_H
  
+ #include <linux/types.h>
  #define BSG_PROTOCOL_SCSI             0
  
  #define BSG_SUB_PROTOCOL_SCSI_CMD     0
  #define BSG_SUB_PROTOCOL_SCSI_TMF     1
  #define BSG_SUB_PROTOCOL_SCSI_TRANSPORT       2
  
 +/*
 + * For flags member below
 + * sg.h sg_io_hdr also has bits defined for it's flags member. However
 + * none of these bits are implemented/used by bsg. The bits below are
 + * allocated to not conflict with sg.h ones anyway.
 + */
 +#define BSG_FLAG_Q_AT_TAIL 0x10 /* default, == 0 at this bit, is Q_AT_HEAD */
 +
  struct sg_io_v4 {
        __s32 guard;            /* [i] 'Q' to differentiate from v3 */
        __u32 protocol;         /* [i] 0 -> SCSI , .... */
diff --combined include/linux/if_ether.h
index 0216e1bdbc568c6dfb943267e620b2189c090c1c,59d197cb48519491ef69a84203d289db97a1553b..cfe4fe1b7132016c4a30f480895a27812c09c959
@@@ -17,7 -17,7 +17,7 @@@
   *            as published by the Free Software Foundation; either version
   *            2 of the License, or (at your option) any later version.
   */
 - 
 +
  #ifndef _LINUX_IF_ETHER_H
  #define _LINUX_IF_ETHER_H
  
@@@ -25,7 -25,7 +25,7 @@@
  
  /*
   *    IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
 - *    and FCS/CRC (frame check sequence). 
 + *    and FCS/CRC (frame check sequence).
   */
  
  #define ETH_ALEN      6               /* Octets in one ethernet addr   */
  #define ETH_P_PAE     0x888E          /* Port Access Entity (IEEE 802.1X) */
  #define ETH_P_AOE     0x88A2          /* ATA over Ethernet            */
  #define ETH_P_TIPC    0x88CA          /* TIPC                         */
+ #define ETH_P_FCOE    0x8906          /* Fibre Channel over Ethernet  */
  #define ETH_P_EDSA    0xDADA          /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
  
  /*
   *    Non DIX types. Won't clash for 1500 types.
   */
 - 
 +
  #define ETH_P_802_3   0x0001          /* Dummy type for 802.3 frames  */
  #define ETH_P_AX25    0x0002          /* Dummy protocol id for AX.25  */
  #define ETH_P_ALL     0x0003          /* Every packet (be careful!!!) */
  /*
   *    This is an Ethernet frame header.
   */
 - 
 +
  struct ethhdr {
        unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
        unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
index 1b55952a17f6f1d12d30c6fbcbcb52f5849855a6,7ed49f5335b18bd6850874718ab37a2bb8b52a12..2e7783f4a7558d73a075a8d39bf6a217ea1e811b
@@@ -32,7 -32,6 +32,7 @@@
  #ifdef __KERNEL__
  #include <linux/timer.h>
  #include <linux/delay.h>
 +#include <linux/mm.h>
  #include <asm/atomic.h>
  #include <asm/cache.h>
  #include <asm/byteorder.h>
@@@ -97,7 -96,7 +97,7 @@@ struct wireless_dev
   *    Compute the worst case header length according to the protocols
   *    used.
   */
 - 
 +
  #if defined(CONFIG_WLAN_80211) || defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
  # if defined(CONFIG_MAC80211_MESH)
  #  define LL_MAX_HEADER 128
   *    Network device statistics. Akin to the 2.0 ether stats but
   *    with byte counters.
   */
 - 
 +
  struct net_device_stats
  {
        unsigned long   rx_packets;             /* total packets received       */
@@@ -286,7 -285,7 +286,7 @@@ enum netdev_state_
  
  /*
   * This structure holds at boot time configured netdevice settings. They
 - * are then used in the device probing. 
 + * are then used in the device probing.
   */
  struct netdev_boot_setup {
        char name[IFNAMSIZ];
@@@ -315,9 -314,6 +315,9 @@@ struct napi_struct 
        spinlock_t              poll_lock;
        int                     poll_owner;
  #endif
 +
 +      unsigned int            gro_count;
 +
        struct net_device       *dev;
        struct list_head        dev_list;
        struct sk_buff          *gro_list;
@@@ -331,14 -327,6 +331,14 @@@ enu
        NAPI_STATE_NPSVC,       /* Netpoll - don't dequeue from poll_list */
  };
  
 +enum {
 +      GRO_MERGED,
 +      GRO_MERGED_FREE,
 +      GRO_HELD,
 +      GRO_NORMAL,
 +      GRO_DROP,
 +};
 +
  extern void __napi_schedule(struct napi_struct *n);
  
  static inline int napi_disable_pending(struct napi_struct *n)
@@@ -594,6 -582,14 +594,14 @@@ struct net_device_ops 
  #define HAVE_NETDEV_POLL
        void                    (*ndo_poll_controller)(struct net_device *dev);
  #endif
+ #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+       int                     (*ndo_fcoe_ddp_setup)(struct net_device *dev,
+                                                     u16 xid,
+                                                     struct scatterlist *sgl,
+                                                     unsigned int sgc);
+       int                     (*ndo_fcoe_ddp_done)(struct net_device *dev,
+                                                    u16 xid);
+ #endif
  };
  
  /*
@@@ -662,14 -658,17 +670,17 @@@ struct net_devic
  #define NETIF_F_GRO           16384   /* Generic receive offload */
  #define NETIF_F_LRO           32768   /* large receive offload */
  
+ #define NETIF_F_FCOE_CRC      (1 << 24) /* FCoE CRC32 */
        /* Segmentation offload features */
  #define NETIF_F_GSO_SHIFT     16
- #define NETIF_F_GSO_MASK      0xffff0000
+ #define NETIF_F_GSO_MASK      0x00ff0000
  #define NETIF_F_TSO           (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
  #define NETIF_F_UFO           (SKB_GSO_UDP << NETIF_F_GSO_SHIFT)
  #define NETIF_F_GSO_ROBUST    (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
  #define NETIF_F_TSO_ECN               (SKB_GSO_TCP_ECN << NETIF_F_GSO_SHIFT)
  #define NETIF_F_TSO6          (SKB_GSO_TCPV6 << NETIF_F_GSO_SHIFT)
+ #define NETIF_F_FSO           (SKB_GSO_FCOE << NETIF_F_GSO_SHIFT)
  
        /* List of features with software fallbacks. */
  #define NETIF_F_GSO_SOFTWARE  (NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6)
        void                    *dsa_ptr;       /* dsa specific data */
  #endif
        void                    *atalk_ptr;     /* AppleTalk link       */
 -      void                    *ip_ptr;        /* IPv4 specific data   */  
 +      void                    *ip_ptr;        /* IPv4 specific data   */
        void                    *dn_ptr;        /* DECnet specific data */
        void                    *ip6_ptr;       /* IPv6 specific data */
        void                    *ec_ptr;        /* Econet specific data */
   */
        unsigned long           last_rx;        /* Time of last Rx      */
        /* Interface address info used in eth_type_trans() */
 -      unsigned char           dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast 
 +      unsigned char           dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast
                                                           because most packets are unicast) */
  
        unsigned char           broadcast[MAX_ADDR_LEN];        /* hw bcast add */
        struct dcbnl_rtnl_ops *dcbnl_ops;
  #endif
  
+ #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+       /* max exchange id for FCoE LRO by ddp */
+       unsigned int            fcoe_ddp_xid;
+ #endif
  #ifdef CONFIG_COMPAT_NET_DEV_OPS
        struct {
                int                     (*init)(struct net_device *dev);
@@@ -996,9 -1000,6 +1012,9 @@@ void netif_napi_add(struct net_device *
  void netif_napi_del(struct napi_struct *napi);
  
  struct napi_gro_cb {
 +      /* This indicates where we are processing relative to skb->data. */
 +      int data_offset;
 +
        /* This is non-zero if the packet may be of the same flow. */
        int same_flow;
  
@@@ -1094,7 -1095,6 +1110,7 @@@ extern void             synchronize_net(void)
  extern int            register_netdevice_notifier(struct notifier_block *nb);
  extern int            unregister_netdevice_notifier(struct notifier_block *nb);
  extern int            init_dummy_netdev(struct net_device *dev);
 +extern void           netdev_resync_ops(struct net_device *dev);
  
  extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev);
  extern struct net_device      *dev_get_by_index(struct net *net, int ifindex);
@@@ -1103,36 -1103,6 +1119,36 @@@ extern int            dev_restart(struct net_devi
  #ifdef CONFIG_NETPOLL_TRAP
  extern int            netpoll_trap(void);
  #endif
 +extern void         *skb_gro_header(struct sk_buff *skb, unsigned int hlen);
 +extern int           skb_gro_receive(struct sk_buff **head,
 +                                     struct sk_buff *skb);
 +
 +static inline unsigned int skb_gro_offset(const struct sk_buff *skb)
 +{
 +      return NAPI_GRO_CB(skb)->data_offset;
 +}
 +
 +static inline unsigned int skb_gro_len(const struct sk_buff *skb)
 +{
 +      return skb->len - NAPI_GRO_CB(skb)->data_offset;
 +}
 +
 +static inline void skb_gro_pull(struct sk_buff *skb, unsigned int len)
 +{
 +      NAPI_GRO_CB(skb)->data_offset += len;
 +}
 +
 +static inline void skb_gro_reset_offset(struct sk_buff *skb)
 +{
 +      NAPI_GRO_CB(skb)->data_offset = 0;
 +}
 +
 +static inline void *skb_gro_mac_header(struct sk_buff *skb)
 +{
 +      return skb_mac_header(skb) < skb->data ? skb_mac_header(skb) :
 +             page_address(skb_shinfo(skb)->frags[0].page) +
 +             skb_shinfo(skb)->frags[0].page_offset;
 +}
  
  static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
                                  unsigned short type,
@@@ -1421,15 -1391,12 +1437,15 @@@ extern int           netif_receive_skb(struct sk
  extern void           napi_gro_flush(struct napi_struct *napi);
  extern int            dev_gro_receive(struct napi_struct *napi,
                                        struct sk_buff *skb);
 +extern int            napi_skb_finish(int ret, struct sk_buff *skb);
  extern int            napi_gro_receive(struct napi_struct *napi,
                                         struct sk_buff *skb);
  extern void           napi_reuse_skb(struct napi_struct *napi,
                                       struct sk_buff *skb);
  extern struct sk_buff *       napi_fraginfo_skb(struct napi_struct *napi,
                                          struct napi_gro_fraginfo *info);
 +extern int            napi_frags_finish(struct napi_struct *napi,
 +                                        struct sk_buff *skb, int ret);
  extern int            napi_gro_frags(struct napi_struct *napi,
                                       struct napi_gro_fraginfo *info);
  extern void           netif_nit_deliver(struct sk_buff *skb);
@@@ -1623,6 -1590,56 +1639,6 @@@ static inline u32 netif_msg_init(int de
        return (1 << debug_value) - 1;
  }
  
 -/* Test if receive needs to be scheduled but only if up */
 -static inline int netif_rx_schedule_prep(struct napi_struct *napi)
 -{
 -      return napi_schedule_prep(napi);
 -}
 -
 -/* Add interface to tail of rx poll list. This assumes that _prep has
 - * already been called and returned 1.
 - */
 -static inline void __netif_rx_schedule(struct napi_struct *napi)
 -{
 -      __napi_schedule(napi);
 -}
 -
 -/* Try to reschedule poll. Called by irq handler. */
 -
 -static inline void netif_rx_schedule(struct napi_struct *napi)
 -{
 -      if (netif_rx_schedule_prep(napi))
 -              __netif_rx_schedule(napi);
 -}
 -
 -/* Try to reschedule poll. Called by dev->poll() after netif_rx_complete().  */
 -static inline int netif_rx_reschedule(struct napi_struct *napi)
 -{
 -      if (napi_schedule_prep(napi)) {
 -              __netif_rx_schedule(napi);
 -              return 1;
 -      }
 -      return 0;
 -}
 -
 -/* same as netif_rx_complete, except that local_irq_save(flags)
 - * has already been issued
 - */
 -static inline void __netif_rx_complete(struct napi_struct *napi)
 -{
 -      __napi_complete(napi);
 -}
 -
 -/* Remove interface from poll list: it must be in the poll list
 - * on current cpu. This primitive is called by dev->poll(), when
 - * it completes the work. The device cannot be out of poll list at this
 - * moment, it is BUG().
 - */
 -static inline void netif_rx_complete(struct napi_struct *napi)
 -{
 -      napi_complete(napi);
 -}
 -
  static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu)
  {
        spin_lock(&txq->_xmit_lock);
@@@ -1873,7 -1890,7 +1889,7 @@@ static inline int skb_bond_should_drop(
  
                if (dev->priv_flags & IFF_SLAVE_INACTIVE) {
                        if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
 -                          skb->protocol == __constant_htons(ETH_P_ARP))
 +                          skb->protocol == __cpu_to_be16(ETH_P_ARP))
                                return 0;
  
                        if (master->priv_flags & IFF_MASTER_ALB) {
                                        return 0;
                        }
                        if (master->priv_flags & IFF_MASTER_8023AD &&
 -                          skb->protocol == __constant_htons(ETH_P_SLOW))
 +                          skb->protocol == __cpu_to_be16(ETH_P_SLOW))
                                return 0;
  
                        return 1;
diff --combined include/linux/skbuff.h
index bb1981fd60f3596f89a4c2a363f19583e3dac019,02adea2099a7673a3338785b9bce3faa67b91cd1..55d67300fa10d128fd4254adff8a78fc05100a78
@@@ -29,6 -29,9 +29,6 @@@
  #include <linux/dmaengine.h>
  #include <linux/hrtimer.h>
  
 -#define HAVE_ALLOC_SKB                /* For the drivers to know */
 -#define HAVE_ALIGNABLE_SKB    /* Ditto 8)                */
 -
  /* Don't change this without changing skb_csum_unnecessary! */
  #define CHECKSUM_NONE 0
  #define CHECKSUM_UNNECESSARY 1
@@@ -132,55 -135,6 +132,55 @@@ struct skb_frag_struct 
        __u32 size;
  };
  
 +#define HAVE_HW_TIME_STAMP
 +
 +/**
 + * struct skb_shared_hwtstamps - hardware time stamps
 + * @hwtstamp: hardware time stamp transformed into duration
 + *            since arbitrary point in time
 + * @syststamp:        hwtstamp transformed to system time base
 + *
 + * Software time stamps generated by ktime_get_real() are stored in
 + * skb->tstamp. The relation between the different kinds of time
 + * stamps is as follows:
 + *
 + * syststamp and tstamp can be compared against each other in
 + * arbitrary combinations.  The accuracy of a
 + * syststamp/tstamp/"syststamp from other device" comparison is
 + * limited by the accuracy of the transformation into system time
 + * base. This depends on the device driver and its underlying
 + * hardware.
 + *
 + * hwtstamps can only be compared against other hwtstamps from
 + * the same device.
 + *
 + * This structure is attached to packets as part of the
 + * &skb_shared_info. Use skb_hwtstamps() to get a pointer.
 + */
 +struct skb_shared_hwtstamps {
 +      ktime_t hwtstamp;
 +      ktime_t syststamp;
 +};
 +
 +/**
 + * struct skb_shared_tx - instructions for time stamping of outgoing packets
 + * @hardware:         generate hardware time stamp
 + * @software:         generate software time stamp
 + * @in_progress:      device driver is going to provide
 + *                    hardware time stamp
 + *
 + * These flags are attached to packets as part of the
 + * &skb_shared_info. Use skb_tx() to get a pointer.
 + */
 +union skb_shared_tx {
 +      struct {
 +              __u8    hardware:1,
 +                      software:1,
 +                      in_progress:1;
 +      };
 +      __u8 flags;
 +};
 +
  /* This data is invariant across clones and lives at
   * the end of the header data, ie. at skb->end.
   */
@@@ -192,12 -146,10 +192,12 @@@ struct skb_shared_info 
        unsigned short  gso_segs;
        unsigned short  gso_type;
        __be32          ip6_frag_id;
 +      union skb_shared_tx tx_flags;
  #ifdef CONFIG_HAS_DMA
        unsigned int    num_dma_maps;
  #endif
        struct sk_buff  *frag_list;
 +      struct skb_shared_hwtstamps hwtstamps;
        skb_frag_t      frags[MAX_SKB_FRAGS];
  #ifdef CONFIG_HAS_DMA
        dma_addr_t      dma_maps[MAX_SKB_FRAGS + 1];
@@@ -236,6 -188,8 +236,8 @@@ enum 
        SKB_GSO_TCP_ECN = 1 << 3,
  
        SKB_GSO_TCPV6 = 1 << 4,
+       SKB_GSO_FCOE = 1 << 5,
  };
  
  #if BITS_PER_LONG > 32
@@@ -421,7 -375,6 +423,7 @@@ extern void skb_dma_unmap(struct devic
  #endif
  
  extern void kfree_skb(struct sk_buff *skb);
 +extern void consume_skb(struct sk_buff *skb);
  extern void          __kfree_skb(struct sk_buff *skb);
  extern struct sk_buff *__alloc_skb(unsigned int size,
                                   gfp_t priority, int fclone, int node);
@@@ -460,8 -413,7 +462,8 @@@ extern int        skb_to_sgvec(struct s
  extern int           skb_cow_data(struct sk_buff *skb, int tailbits,
                                    struct sk_buff **trailer);
  extern int           skb_pad(struct sk_buff *skb, int pad);
 -#define dev_kfree_skb(a)      kfree_skb(a)
 +#define dev_kfree_skb(a)      consume_skb(a)
 +#define dev_consume_skb(a)    kfree_skb_clean(a)
  extern void         skb_over_panic(struct sk_buff *skb, int len,
                                     void *here);
  extern void         skb_under_panic(struct sk_buff *skb, int len,
@@@ -509,16 -461,6 +511,16 @@@ static inline unsigned char *skb_end_po
  /* Internal */
  #define skb_shinfo(SKB)       ((struct skb_shared_info *)(skb_end_pointer(SKB)))
  
 +static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb)
 +{
 +      return &skb_shinfo(skb)->hwtstamps;
 +}
 +
 +static inline union skb_shared_tx *skb_tx(struct sk_buff *skb)
 +{
 +      return &skb_shinfo(skb)->tx_flags;
 +}
 +
  /**
   *    skb_queue_empty - check if a queue is empty
   *    @list: queue head
@@@ -1338,7 -1280,7 +1340,7 @@@ static inline int skb_network_offset(co
   * The networking layer reserves some headroom in skb data (via
   * dev_alloc_skb). This is used to avoid having to reallocate skb data when
   * the header has to grow. In the default case, if the header has to grow
 - * 16 bytes or less we avoid the reallocation.
 + * 32 bytes or less we avoid the reallocation.
   *
   * Unfortunately this headroom changes the DMA alignment of the resulting
   * network packet. As for NET_IP_ALIGN, this unaligned DMA is expensive
   * perhaps setting it to a cacheline in size (since that will maintain
   * cacheline alignment of the DMA). It must be a power of 2.
   *
 - * Various parts of the networking layer expect at least 16 bytes of
 + * Various parts of the networking layer expect at least 32 bytes of
   * headroom, you should not reduce this.
   */
  #ifndef NET_SKB_PAD
 -#define NET_SKB_PAD   16
 +#define NET_SKB_PAD   32
  #endif
  
  extern int ___pskb_trim(struct sk_buff *skb, unsigned int len);
@@@ -1738,6 -1680,8 +1740,6 @@@ extern int             skb_shift(struct sk_b
                                 int shiftlen);
  
  extern struct sk_buff *skb_segment(struct sk_buff *skb, int features);
 -extern int           skb_gro_receive(struct sk_buff **head,
 -                                     struct sk_buff *skb);
  
  static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
                                       int len, void *buffer)
@@@ -1784,11 -1728,6 +1786,11 @@@ static inline void skb_copy_to_linear_d
  
  extern void skb_init(void);
  
 +static inline ktime_t skb_get_ktime(const struct sk_buff *skb)
 +{
 +      return skb->tstamp;
 +}
 +
  /**
   *    skb_get_timestamp - get timestamp from a skb
   *    @skb: skb to get stamp from
   *    This function converts the offset back to a struct timeval and stores
   *    it in stamp.
   */
 -static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *stamp)
 +static inline void skb_get_timestamp(const struct sk_buff *skb,
 +                                   struct timeval *stamp)
  {
        *stamp = ktime_to_timeval(skb->tstamp);
  }
  
 +static inline void skb_get_timestampns(const struct sk_buff *skb,
 +                                     struct timespec *stamp)
 +{
 +      *stamp = ktime_to_timespec(skb->tstamp);
 +}
 +
  static inline void __net_timestamp(struct sk_buff *skb)
  {
        skb->tstamp = ktime_get_real();
@@@ -1825,20 -1757,6 +1827,20 @@@ static inline ktime_t net_invalid_times
        return ktime_set(0, 0);
  }
  
 +/**
 + * skb_tstamp_tx - queue clone of skb with send time stamps
 + * @orig_skb: the original outgoing packet
 + * @hwtstamps:        hardware time stamps, may be NULL if not available
 + *
 + * If the skb has a socket associated, then this function clones the
 + * skb (thus sharing the actual data and optional structures), stores
 + * the optional hardware time stamping information (if non NULL) or
 + * generates a software time stamp (otherwise), then queues the clone
 + * to the error queue of the socket.  Errors are silently ignored.
 + */
 +extern void skb_tstamp_tx(struct sk_buff *orig_skb,
 +                      struct skb_shared_hwtstamps *hwtstamps);
 +
  extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
  extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
  
@@@ -1969,7 -1887,7 +1971,7 @@@ static inline void skb_set_queue_mappin
        skb->queue_mapping = queue_mapping;
  }
  
 -static inline u16 skb_get_queue_mapping(struct sk_buff *skb)
 +static inline u16 skb_get_queue_mapping(const struct sk_buff *skb)
  {
        return skb->queue_mapping;
  }
@@@ -1979,24 -1897,6 +1981,24 @@@ static inline void skb_copy_queue_mappi
        to->queue_mapping = from->queue_mapping;
  }
  
 +static inline void skb_record_rx_queue(struct sk_buff *skb, u16 rx_queue)
 +{
 +      skb->queue_mapping = rx_queue + 1;
 +}
 +
 +static inline u16 skb_get_rx_queue(const struct sk_buff *skb)
 +{
 +      return skb->queue_mapping - 1;
 +}
 +
 +static inline bool skb_rx_queue_recorded(const struct sk_buff *skb)
 +{
 +      return (skb->queue_mapping != 0);
 +}
 +
 +extern u16 skb_tx_hash(const struct net_device *dev,
 +                     const struct sk_buff *skb);
 +
  #ifdef CONFIG_XFRM
  static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
  {
diff --combined net/core/dev.c
index 63ec4bf89b2914a5a3a271c14b16d4833c7d53ce,3d3670640c2d59458b66f1af59605904eaf4b427..52fea5b28ca694ede44158117d631e093430c25c
@@@ -1457,7 -1457,9 +1457,9 @@@ static bool can_checksum_protocol(unsig
                ((features & NETIF_F_IP_CSUM) &&
                 protocol == htons(ETH_P_IP)) ||
                ((features & NETIF_F_IPV6_CSUM) &&
-                protocol == htons(ETH_P_IPV6)));
+                protocol == htons(ETH_P_IPV6)) ||
+               ((features & NETIF_F_FCOE_CRC) &&
+                protocol == htons(ETH_P_FCOE)));
  }
  
  static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)
@@@ -1668,8 -1670,8 +1670,8 @@@ int dev_hard_start_xmit(struct sk_buff 
                        struct netdev_queue *txq)
  {
        const struct net_device_ops *ops = dev->netdev_ops;
 +      int rc;
  
 -      prefetch(&dev->netdev_ops->ndo_start_xmit);
        if (likely(!skb->next)) {
                if (!list_empty(&ptype_all))
                        dev_queue_xmit_nit(skb, dev);
                                goto gso;
                }
  
 -              return ops->ndo_start_xmit(skb, dev);
 +              rc = ops->ndo_start_xmit(skb, dev);
 +              /*
 +               * TODO: if skb_orphan() was called by
 +               * dev->hard_start_xmit() (for example, the unmodified
 +               * igb driver does that; bnx2 doesn't), then
 +               * skb_tx_software_timestamp() will be unable to send
 +               * back the time stamp.
 +               *
 +               * How can this be prevented? Always create another
 +               * reference to the socket before calling
 +               * dev->hard_start_xmit()? Prevent that skb_orphan()
 +               * does anything in dev->hard_start_xmit() by clearing
 +               * the skb destructor before the call and restoring it
 +               * afterwards, then doing the skb_orphan() ourselves?
 +               */
 +              return rc;
        }
  
  gso:
        do {
                struct sk_buff *nskb = skb->next;
 -              int rc;
  
                skb->next = nskb->next;
                nskb->next = NULL;
@@@ -1722,24 -1710,59 +1724,24 @@@ out_kfree_skb
        return 0;
  }
  
 -static u32 simple_tx_hashrnd;
 -static int simple_tx_hashrnd_initialized = 0;
 +static u32 skb_tx_hashrnd;
  
 -static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb)
 +u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb)
  {
 -      u32 addr1, addr2, ports;
 -      u32 hash, ihl;
 -      u8 ip_proto = 0;
 -
 -      if (unlikely(!simple_tx_hashrnd_initialized)) {
 -              get_random_bytes(&simple_tx_hashrnd, 4);
 -              simple_tx_hashrnd_initialized = 1;
 -      }
 -
 -      switch (skb->protocol) {
 -      case htons(ETH_P_IP):
 -              if (!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)))
 -                      ip_proto = ip_hdr(skb)->protocol;
 -              addr1 = ip_hdr(skb)->saddr;
 -              addr2 = ip_hdr(skb)->daddr;
 -              ihl = ip_hdr(skb)->ihl;
 -              break;
 -      case htons(ETH_P_IPV6):
 -              ip_proto = ipv6_hdr(skb)->nexthdr;
 -              addr1 = ipv6_hdr(skb)->saddr.s6_addr32[3];
 -              addr2 = ipv6_hdr(skb)->daddr.s6_addr32[3];
 -              ihl = (40 >> 2);
 -              break;
 -      default:
 -              return 0;
 -      }
 -
 -
 -      switch (ip_proto) {
 -      case IPPROTO_TCP:
 -      case IPPROTO_UDP:
 -      case IPPROTO_DCCP:
 -      case IPPROTO_ESP:
 -      case IPPROTO_AH:
 -      case IPPROTO_SCTP:
 -      case IPPROTO_UDPLITE:
 -              ports = *((u32 *) (skb_network_header(skb) + (ihl * 4)));
 -              break;
 +      u32 hash;
  
 -      default:
 -              ports = 0;
 -              break;
 -      }
 +      if (skb_rx_queue_recorded(skb)) {
 +              hash = skb_get_rx_queue(skb);
 +      } else if (skb->sk && skb->sk->sk_hash) {
 +              hash = skb->sk->sk_hash;
 +      } else
 +              hash = skb->protocol;
  
 -      hash = jhash_3words(addr1, addr2, ports, simple_tx_hashrnd);
 +      hash = jhash_1word(hash, skb_tx_hashrnd);
  
        return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32);
  }
 +EXPORT_SYMBOL(skb_tx_hash);
  
  static struct netdev_queue *dev_pick_tx(struct net_device *dev,
                                        struct sk_buff *skb)
        if (ops->ndo_select_queue)
                queue_index = ops->ndo_select_queue(dev, skb);
        else if (dev->real_num_tx_queues > 1)
 -              queue_index = simple_tx_hash(dev, skb);
 +              queue_index = skb_tx_hash(dev, skb);
  
        skb_set_queue_mapping(skb, queue_index);
        return netdev_get_tx_queue(dev, queue_index);
@@@ -2246,6 -2269,12 +2248,6 @@@ int netif_receive_skb(struct sk_buff *s
  
        rcu_read_lock();
  
 -      /* Don't receive packets in an exiting network namespace */
 -      if (!net_alive(dev_net(skb->dev))) {
 -              kfree_skb(skb);
 -              goto out;
 -      }
 -
  #ifdef CONFIG_NET_CLS_ACT
        if (skb->tc_verd & TC_NCLS) {
                skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
@@@ -2276,8 -2305,6 +2278,8 @@@ ncls
        if (!skb)
                goto out;
  
 +      skb_orphan(skb);
 +
        type = skb->protocol;
        list_for_each_entry_rcu(ptype,
                        &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
@@@ -2347,6 -2374,7 +2349,6 @@@ static int napi_gro_complete(struct sk_
  
  out:
        skb_shinfo(skb)->gso_size = 0;
 -      __skb_push(skb, -skb_network_offset(skb));
        return netif_receive_skb(skb);
  }
  
@@@ -2360,40 -2388,20 +2362,40 @@@ void napi_gro_flush(struct napi_struct 
                napi_gro_complete(skb);
        }
  
 +      napi->gro_count = 0;
        napi->gro_list = NULL;
  }
  EXPORT_SYMBOL(napi_gro_flush);
  
 +void *skb_gro_header(struct sk_buff *skb, unsigned int hlen)
 +{
 +      unsigned int offset = skb_gro_offset(skb);
 +
 +      hlen += offset;
 +      if (hlen <= skb_headlen(skb))
 +              return skb->data + offset;
 +
 +      if (unlikely(!skb_shinfo(skb)->nr_frags ||
 +                   skb_shinfo(skb)->frags[0].size <=
 +                   hlen - skb_headlen(skb) ||
 +                   PageHighMem(skb_shinfo(skb)->frags[0].page)))
 +              return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
 +
 +      return page_address(skb_shinfo(skb)->frags[0].page) +
 +             skb_shinfo(skb)->frags[0].page_offset +
 +             offset - skb_headlen(skb);
 +}
 +EXPORT_SYMBOL(skb_gro_header);
 +
  int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
  {
        struct sk_buff **pp = NULL;
        struct packet_type *ptype;
        __be16 type = skb->protocol;
        struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
 -      int count = 0;
        int same_flow;
        int mac_len;
 -      int free;
 +      int ret;
  
        if (!(skb->dev->features & NETIF_F_GRO))
                goto normal;
  
        rcu_read_lock();
        list_for_each_entry_rcu(ptype, head, list) {
 -              struct sk_buff *p;
 -
                if (ptype->type != type || ptype->dev || !ptype->gro_receive)
                        continue;
  
 -              skb_reset_network_header(skb);
 +              skb_set_network_header(skb, skb_gro_offset(skb));
                mac_len = skb->network_header - skb->mac_header;
                skb->mac_len = mac_len;
                NAPI_GRO_CB(skb)->same_flow = 0;
                NAPI_GRO_CB(skb)->flush = 0;
                NAPI_GRO_CB(skb)->free = 0;
  
 -              for (p = napi->gro_list; p; p = p->next) {
 -                      count++;
 -
 -                      if (!NAPI_GRO_CB(p)->same_flow)
 -                              continue;
 -
 -                      if (p->mac_len != mac_len ||
 -                          memcmp(skb_mac_header(p), skb_mac_header(skb),
 -                                 mac_len))
 -                              NAPI_GRO_CB(p)->same_flow = 0;
 -              }
 -
                pp = ptype->gro_receive(&napi->gro_list, skb);
                break;
        }
                goto normal;
  
        same_flow = NAPI_GRO_CB(skb)->same_flow;
 -      free = NAPI_GRO_CB(skb)->free;
 +      ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED;
  
        if (pp) {
                struct sk_buff *nskb = *pp;
                *pp = nskb->next;
                nskb->next = NULL;
                napi_gro_complete(nskb);
 -              count--;
 +              napi->gro_count--;
        }
  
        if (same_flow)
                goto ok;
  
 -      if (NAPI_GRO_CB(skb)->flush || count >= MAX_GRO_SKBS) {
 -              __skb_push(skb, -skb_network_offset(skb));
 +      if (NAPI_GRO_CB(skb)->flush || napi->gro_count >= MAX_GRO_SKBS)
                goto normal;
 -      }
  
 +      napi->gro_count++;
        NAPI_GRO_CB(skb)->count = 1;
 -      skb_shinfo(skb)->gso_size = skb->len;
 +      skb_shinfo(skb)->gso_size = skb_gro_len(skb);
        skb->next = napi->gro_list;
        napi->gro_list = skb;
 +      ret = GRO_HELD;
 +
 +pull:
 +      if (unlikely(!pskb_may_pull(skb, skb_gro_offset(skb)))) {
 +              if (napi->gro_list == skb)
 +                      napi->gro_list = skb->next;
 +              ret = GRO_DROP;
 +      }
  
  ok:
 -      return free;
 +      return ret;
  
  normal:
 -      return -1;
 +      ret = GRO_NORMAL;
 +      goto pull;
  }
  EXPORT_SYMBOL(dev_gro_receive);
  
@@@ -2466,44 -2480,29 +2468,44 @@@ static int __napi_gro_receive(struct na
  {
        struct sk_buff *p;
  
 +      if (netpoll_rx_on(skb))
 +              return GRO_NORMAL;
 +
        for (p = napi->gro_list; p; p = p->next) {
 -              NAPI_GRO_CB(p)->same_flow = 1;
 +              NAPI_GRO_CB(p)->same_flow = !compare_ether_header(
 +                      skb_mac_header(p), skb_gro_mac_header(skb));
                NAPI_GRO_CB(p)->flush = 0;
        }
  
        return dev_gro_receive(napi, skb);
  }
  
 -int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 +int napi_skb_finish(int ret, struct sk_buff *skb)
  {
 -      if (netpoll_receive_skb(skb))
 -              return NET_RX_DROP;
 +      int err = NET_RX_SUCCESS;
  
 -      switch (__napi_gro_receive(napi, skb)) {
 -      case -1:
 +      switch (ret) {
 +      case GRO_NORMAL:
                return netif_receive_skb(skb);
  
 -      case 1:
 +      case GRO_DROP:
 +              err = NET_RX_DROP;
 +              /* fall through */
 +
 +      case GRO_MERGED_FREE:
                kfree_skb(skb);
                break;
        }
  
 -      return NET_RX_SUCCESS;
 +      return err;
 +}
 +EXPORT_SYMBOL(napi_skb_finish);
 +
 +int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 +{
 +      skb_gro_reset_offset(skb);
 +
 +      return napi_skb_finish(__napi_gro_receive(napi, skb), skb);
  }
  EXPORT_SYMBOL(napi_gro_receive);
  
@@@ -2521,9 -2520,6 +2523,9 @@@ struct sk_buff *napi_fraginfo_skb(struc
  {
        struct net_device *dev = napi->dev;
        struct sk_buff *skb = napi->skb;
 +      struct ethhdr *eth;
 +      skb_frag_t *frag;
 +      int i;
  
        napi->skb = NULL;
  
        }
  
        BUG_ON(info->nr_frags > MAX_SKB_FRAGS);
 +      frag = &info->frags[info->nr_frags - 1];
 +
 +      for (i = skb_shinfo(skb)->nr_frags; i < info->nr_frags; i++) {
 +              skb_fill_page_desc(skb, i, frag->page, frag->page_offset,
 +                                 frag->size);
 +              frag++;
 +      }
        skb_shinfo(skb)->nr_frags = info->nr_frags;
 -      memcpy(skb_shinfo(skb)->frags, info->frags, sizeof(info->frags));
  
        skb->data_len = info->len;
        skb->len += info->len;
        skb->truesize += info->len;
  
 -      if (!pskb_may_pull(skb, ETH_HLEN)) {
 +      skb_reset_mac_header(skb);
 +      skb_gro_reset_offset(skb);
 +
 +      eth = skb_gro_header(skb, sizeof(*eth));
 +      if (!eth) {
                napi_reuse_skb(napi, skb);
                skb = NULL;
                goto out;
        }
  
 -      skb->protocol = eth_type_trans(skb, dev);
 +      skb_gro_pull(skb, sizeof(*eth));
 +
 +      /*
 +       * This works because the only protocols we care about don't require
 +       * special handling.  We'll fix it up properly at the end.
 +       */
 +      skb->protocol = eth->h_proto;
  
        skb->ip_summed = info->ip_summed;
        skb->csum = info->csum;
  }
  EXPORT_SYMBOL(napi_fraginfo_skb);
  
 -int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
 +int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret)
  {
 -      struct sk_buff *skb = napi_fraginfo_skb(napi, info);
 -      int err = NET_RX_DROP;
 +      int err = NET_RX_SUCCESS;
  
 -      if (!skb)
 -              goto out;
 +      switch (ret) {
 +      case GRO_NORMAL:
 +      case GRO_HELD:
 +              skb->protocol = eth_type_trans(skb, napi->dev);
  
 -      if (netpoll_receive_skb(skb))
 -              goto out;
 +              if (ret == GRO_NORMAL)
 +                      return netif_receive_skb(skb);
  
 -      err = NET_RX_SUCCESS;
 +              skb_gro_pull(skb, -ETH_HLEN);
 +              break;
  
 -      switch (__napi_gro_receive(napi, skb)) {
 -      case -1:
 -              return netif_receive_skb(skb);
 +      case GRO_DROP:
 +              err = NET_RX_DROP;
 +              /* fall through */
  
 -      case 0:
 -              goto out;
 +      case GRO_MERGED_FREE:
 +              napi_reuse_skb(napi, skb);
 +              break;
        }
  
 -      napi_reuse_skb(napi, skb);
 -
 -out:
        return err;
  }
 +EXPORT_SYMBOL(napi_frags_finish);
 +
 +int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
 +{
 +      struct sk_buff *skb = napi_fraginfo_skb(napi, info);
 +
 +      if (!skb)
 +              return NET_RX_DROP;
 +
 +      return napi_frags_finish(napi, skb, __napi_gro_receive(napi, skb));
 +}
  EXPORT_SYMBOL(napi_gro_frags);
  
  static int process_backlog(struct napi_struct *napi, int quota)
                }
                local_irq_enable();
  
 -              napi_gro_receive(napi, skb);
 +              netif_receive_skb(skb);
        } while (++work < quota && jiffies == start_time);
  
 -      napi_gro_flush(napi);
 -
        return work;
  }
  
@@@ -2689,7 -2660,6 +2691,7 @@@ void netif_napi_add(struct net_device *
                    int (*poll)(struct napi_struct *, int), int weight)
  {
        INIT_LIST_HEAD(&napi->poll_list);
 +      napi->gro_count = 0;
        napi->gro_list = NULL;
        napi->skb = NULL;
        napi->poll = poll;
@@@ -2709,7 -2679,7 +2711,7 @@@ void netif_napi_del(struct napi_struct 
        struct sk_buff *skb, *next;
  
        list_del_init(&napi->dev_list);
 -      kfree(napi->skb);
 +      kfree_skb(napi->skb);
  
        for (skb = napi->gro_list; skb; skb = next) {
                next = skb->next;
        }
  
        napi->gro_list = NULL;
 +      napi->gro_count = 0;
  }
  EXPORT_SYMBOL(netif_napi_del);
  
@@@ -3987,7 -3956,6 +3989,7 @@@ static int dev_ifsioc(struct net *net, 
                            cmd == SIOCSMIIREG ||
                            cmd == SIOCBRADDIF ||
                            cmd == SIOCBRDELIF ||
 +                          cmd == SIOCSHWTSTAMP ||
                            cmd == SIOCWANDEV) {
                                err = -EOPNOTSUPP;
                                if (ops->ndo_do_ioctl) {
@@@ -4142,7 -4110,6 +4144,7 @@@ int dev_ioctl(struct net *net, unsigne
                case SIOCBONDCHANGEACTIVE:
                case SIOCBRADDIF:
                case SIOCBRDELIF:
 +              case SIOCSHWTSTAMP:
                        if (!capable(CAP_NET_ADMIN))
                                return -EPERM;
                        /* fall through */
@@@ -4323,39 -4290,6 +4325,39 @@@ unsigned long netdev_fix_features(unsig
  }
  EXPORT_SYMBOL(netdev_fix_features);
  
 +/* Some devices need to (re-)set their netdev_ops inside
 + * ->init() or similar.  If that happens, we have to setup
 + * the compat pointers again.
 + */
 +void netdev_resync_ops(struct net_device *dev)
 +{
 +#ifdef CONFIG_COMPAT_NET_DEV_OPS
 +      const struct net_device_ops *ops = dev->netdev_ops;
 +
 +      dev->init = ops->ndo_init;
 +      dev->uninit = ops->ndo_uninit;
 +      dev->open = ops->ndo_open;
 +      dev->change_rx_flags = ops->ndo_change_rx_flags;
 +      dev->set_rx_mode = ops->ndo_set_rx_mode;
 +      dev->set_multicast_list = ops->ndo_set_multicast_list;
 +      dev->set_mac_address = ops->ndo_set_mac_address;
 +      dev->validate_addr = ops->ndo_validate_addr;
 +      dev->do_ioctl = ops->ndo_do_ioctl;
 +      dev->set_config = ops->ndo_set_config;
 +      dev->change_mtu = ops->ndo_change_mtu;
 +      dev->neigh_setup = ops->ndo_neigh_setup;
 +      dev->tx_timeout = ops->ndo_tx_timeout;
 +      dev->get_stats = ops->ndo_get_stats;
 +      dev->vlan_rx_register = ops->ndo_vlan_rx_register;
 +      dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
 +      dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
 +#ifdef CONFIG_NET_POLL_CONTROLLER
 +      dev->poll_controller = ops->ndo_poll_controller;
 +#endif
 +#endif
 +}
 +EXPORT_SYMBOL(netdev_resync_ops);
 +
  /**
   *    register_netdevice      - register a network device
   *    @dev: device to register
@@@ -4400,7 -4334,27 +4402,7 @@@ int register_netdevice(struct net_devic
         * This is temporary until all network devices are converted.
         */
        if (dev->netdev_ops) {
 -              const struct net_device_ops *ops = dev->netdev_ops;
 -
 -              dev->init = ops->ndo_init;
 -              dev->uninit = ops->ndo_uninit;
 -              dev->open = ops->ndo_open;
 -              dev->change_rx_flags = ops->ndo_change_rx_flags;
 -              dev->set_rx_mode = ops->ndo_set_rx_mode;
 -              dev->set_multicast_list = ops->ndo_set_multicast_list;
 -              dev->set_mac_address = ops->ndo_set_mac_address;
 -              dev->validate_addr = ops->ndo_validate_addr;
 -              dev->do_ioctl = ops->ndo_do_ioctl;
 -              dev->set_config = ops->ndo_set_config;
 -              dev->change_mtu = ops->ndo_change_mtu;
 -              dev->tx_timeout = ops->ndo_tx_timeout;
 -              dev->get_stats = ops->ndo_get_stats;
 -              dev->vlan_rx_register = ops->ndo_vlan_rx_register;
 -              dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
 -              dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
 -#ifdef CONFIG_NET_POLL_CONTROLLER
 -              dev->poll_controller = ops->ndo_poll_controller;
 -#endif
 +              netdev_resync_ops(dev);
        } else {
                char drivername[64];
                pr_info("%s (%s): not using net_device_ops yet\n",
@@@ -5239,7 -5193,6 +5241,7 @@@ static int __init net_dev_init(void
                queue->backlog.poll = process_backlog;
                queue->backlog.weight = weight_p;
                queue->backlog.gro_list = NULL;
 +              queue->backlog.gro_count = 0;
        }
  
        dev_boot_phase = 0;
  
  subsys_initcall(net_dev_init);
  
 +static int __init initialize_hashrnd(void)
 +{
 +      get_random_bytes(&skb_tx_hashrnd, sizeof(skb_tx_hashrnd));
 +      return 0;
 +}
 +
 +late_initcall_sync(initialize_hashrnd);
 +
  EXPORT_SYMBOL(__dev_get_by_index);
  EXPORT_SYMBOL(__dev_get_by_name);
  EXPORT_SYMBOL(__dev_remove_pack);