]> Pileus Git - ~andy/linux/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Jul 2008 01:58:04 +0000 (18:58 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Jul 2008 01:58:04 +0000 (18:58 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (102 commits)
  [SCSI] scsi_dh: fix kconfig related build errors
  [SCSI] sym53c8xx: Fix bogus sym_que_entry re-implementation of container_of
  [SCSI] scsi_cmnd.h: remove double inclusion of linux/blkdev.h
  [SCSI] make struct scsi_{host,target}_type static
  [SCSI] fix locking in host use of blk_plug_device()
  [SCSI] zfcp: Cleanup external header file
  [SCSI] zfcp: Cleanup code in zfcp_erp.c
  [SCSI] zfcp: zfcp_fsf cleanup.
  [SCSI] zfcp: consolidate sysfs things into one file.
  [SCSI] zfcp: Cleanup of code in zfcp_aux.c
  [SCSI] zfcp: Cleanup of code in zfcp_scsi.c
  [SCSI] zfcp: Move status accessors from zfcp to SCSI include file.
  [SCSI] zfcp: Small QDIO cleanups
  [SCSI] zfcp: Adapter reopen for large number of unsolicited status
  [SCSI] zfcp: Fix error checking for ELS ADISC requests
  [SCSI] zfcp: wait until adapter is finished with ERP during auto-port
  [SCSI] ibmvfc: IBM Power Virtual Fibre Channel Adapter Client Driver
  [SCSI] sg: Add target reset support
  [SCSI] lib: Add support for the T10 (SCSI) Data Integrity Field CRC
  [SCSI] sd: Move scsi_disk() accessor function to sd.h
  ...

17 files changed:
1  2 
block/bsg.c
drivers/infiniband/ulp/iser/iscsi_iser.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/infiniband/ulp/iser/iser_memory.c
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptspi.c
drivers/scsi/aacraid/linit.c
drivers/scsi/esp_scsi.c
drivers/scsi/hosts.c
drivers/scsi/scsi_lib.c
drivers/scsi/sd.c
drivers/scsi/sg.c
include/scsi/scsi_device.h
lib/Makefile

diff --combined block/bsg.c
index 0b3b282f0384f81c11b1f2deb551d79a5c5ae527,7cdec32205d829abe4be66ec7121d203d1547257..5fb9b0bdbe85b60776eb60bd6486f8f86c629587
@@@ -19,7 -19,6 +19,7 @@@
  #include <linux/uio.h>
  #include <linux/idr.h>
  #include <linux/bsg.h>
 +#include <linux/smp_lock.h>
  
  #include <scsi/scsi.h>
  #include <scsi/scsi_ioctl.h>
@@@ -45,12 -44,11 +45,12 @@@ struct bsg_device 
        char name[BUS_ID_SIZE];
        int max_queue;
        unsigned long flags;
 +      struct blk_scsi_cmd_filter *cmd_filter;
 +      mode_t *f_mode;
  };
  
  enum {
        BSG_F_BLOCK             = 1,
 -      BSG_F_WRITE_PERM        = 2,
  };
  
  #define BSG_DEFAULT_CMDS      64
@@@ -174,7 -172,7 +174,7 @@@ unlock
  }
  
  static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
 -                              struct sg_io_v4 *hdr, int has_write_perm)
 +                              struct sg_io_v4 *hdr, struct bsg_device *bd)
  {
        if (hdr->request_len > BLK_MAX_CDB) {
                rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
                return -EFAULT;
  
        if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) {
 -              if (blk_verify_command(rq->cmd, has_write_perm))
 +              if (blk_cmd_filter_verify_command(bd->cmd_filter, rq->cmd,
 +                                               bd->f_mode))
                        return -EPERM;
        } else if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
@@@ -266,7 -263,8 +266,7 @@@ bsg_map_hdr(struct bsg_device *bd, stru
        rq = blk_get_request(q, rw, GFP_KERNEL);
        if (!rq)
                return ERR_PTR(-ENOMEM);
 -      ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM,
 -                                                     &bd->flags));
 +      ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd);
        if (ret)
                goto out;
  
@@@ -568,23 -566,12 +568,23 @@@ static inline void bsg_set_block(struc
                set_bit(BSG_F_BLOCK, &bd->flags);
  }
  
 -static inline void bsg_set_write_perm(struct bsg_device *bd, struct file *file)
 +static void bsg_set_cmd_filter(struct bsg_device *bd,
 +                         struct file *file)
  {
 -      if (file->f_mode & FMODE_WRITE)
 -              set_bit(BSG_F_WRITE_PERM, &bd->flags);
 -      else
 -              clear_bit(BSG_F_WRITE_PERM, &bd->flags);
 +      struct inode *inode;
 +      struct gendisk *disk;
 +
 +      if (!file)
 +              return;
 +
 +      inode = file->f_dentry->d_inode;
 +      if (!inode)
 +              return;
 +
 +      disk = inode->i_bdev->bd_disk;
 +
 +      bd->cmd_filter = &disk->cmd_filter;
 +      bd->f_mode = &file->f_mode;
  }
  
  /*
@@@ -608,8 -595,6 +608,8 @@@ bsg_read(struct file *file, char __use
        dprintk("%s: read %Zd bytes\n", bd->name, count);
  
        bsg_set_block(bd, file);
 +      bsg_set_cmd_filter(bd, file);
 +
        bytes_read = 0;
        ret = __bsg_read(buf, count, bd, NULL, &bytes_read);
        *ppos = bytes_read;
@@@ -683,7 -668,7 +683,7 @@@ bsg_write(struct file *file, const cha
        dprintk("%s: write %Zd bytes\n", bd->name, count);
  
        bsg_set_block(bd, file);
 -      bsg_set_write_perm(bd, file);
 +      bsg_set_cmd_filter(bd, file);
  
        bytes_written = 0;
        ret = __bsg_write(bd, buf, count, &bytes_written);
@@@ -724,12 -709,11 +724,12 @@@ static void bsg_kref_release_function(s
  {
        struct bsg_class_device *bcd =
                container_of(kref, struct bsg_class_device, ref);
 +      struct device *parent = bcd->parent;
  
        if (bcd->release)
                bcd->release(bcd->parent);
  
 -      put_device(bcd->parent);
 +      put_device(parent);
  }
  
  static int bsg_put_device(struct bsg_device *bd)
        mutex_lock(&bsg_mutex);
  
        do_free = atomic_dec_and_test(&bd->ref_count);
-       if (!do_free)
+       if (!do_free) {
+               mutex_unlock(&bsg_mutex);
                goto out;
+       }
+       hlist_del(&bd->dev_list);
+       mutex_unlock(&bsg_mutex);
  
        dprintk("%s: tearing down\n", bd->name);
  
         */
        ret = bsg_complete_all_commands(bd);
  
-       hlist_del(&bd->dev_list);
        kfree(bd);
  out:
-       mutex_unlock(&bsg_mutex);
        kref_put(&q->bsg_dev.ref, bsg_kref_release_function);
        if (do_free)
                blk_put_queue(q);
@@@ -787,9 -774,7 +790,9 @@@ static struct bsg_device *bsg_add_devic
        }
  
        bd->queue = rq;
 +
        bsg_set_block(bd, file);
 +      bsg_set_cmd_filter(bd, file);
  
        atomic_set(&bd->ref_count, 1);
        mutex_lock(&bsg_mutex);
@@@ -852,11 -837,7 +855,11 @@@ static struct bsg_device *bsg_get_devic
  
  static int bsg_open(struct inode *inode, struct file *file)
  {
 -      struct bsg_device *bd = bsg_get_device(inode, file);
 +      struct bsg_device *bd;
 +
 +      lock_kernel();
 +      bd = bsg_get_device(inode, file);
 +      unlock_kernel();
  
        if (IS_ERR(bd))
                return PTR_ERR(bd);
index 356fac6d105abbf7c842ad56f99f2e6d716d4a48,a56931e03976939b06bc853888776cd11f854e6a..5a1cf2580e16a3dd45517d9484986709e75bafeb
@@@ -42,6 -42,9 +42,6 @@@
   *    Zhenyu Wang
   * Modified by:
   *      Erez Zilber
 - *
 - *
 - * $Id: iscsi_iser.c 6965 2006-05-07 11:36:20Z ogerlitz $
   */
  
  #include <linux/types.h>
  
  #include "iscsi_iser.h"
  
+ static struct scsi_host_template iscsi_iser_sht;
+ static struct iscsi_transport iscsi_iser_transport;
+ static struct scsi_transport_template *iscsi_iser_scsi_transport;
  static unsigned int iscsi_max_lun = 512;
  module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
  
@@@ -91,7 -98,6 +95,6 @@@ iscsi_iser_recv(struct iscsi_conn *conn
                struct iscsi_hdr *hdr, char *rx_data, int rx_data_len)
  {
        int rc = 0;
-       uint32_t ret_itt;
        int datalen;
        int ahslen;
  
        /* read AHS */
        ahslen = hdr->hlength * 4;
  
-       /* verify itt (itt encoding: age+cid+itt) */
-       rc = iscsi_verify_itt(conn, hdr, &ret_itt);
-       if (!rc)
-               rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len);
+       rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len);
        if (rc && rc != ISCSI_ERR_NO_SCSI_CMD)
                goto error;
  
@@@ -123,25 -124,33 +121,33 @@@ error
  
  
  /**
-  * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
+  * iscsi_iser_task_init - Initialize task
+  * @task: iscsi task
   *
-  **/
+  * Initialize the task for the scsi command or mgmt command.
+  */
  static int
- iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
+ iscsi_iser_task_init(struct iscsi_task *task)
  {
-       struct iscsi_iser_conn     *iser_conn  = ctask->conn->dd_data;
-       struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+       struct iscsi_iser_conn *iser_conn  = task->conn->dd_data;
+       struct iscsi_iser_task *iser_task = task->dd_data;
+       /* mgmt task */
+       if (!task->sc) {
+               iser_task->desc.data = task->data;
+               return 0;
+       }
  
-       iser_ctask->command_sent = 0;
-       iser_ctask->iser_conn    = iser_conn;
-       iser_ctask_rdma_init(iser_ctask);
+       iser_task->command_sent = 0;
+       iser_task->iser_conn    = iser_conn;
+       iser_task_rdma_init(iser_task);
        return 0;
  }
  
  /**
-  * iscsi_mtask_xmit - xmit management(immediate) task
+  * iscsi_iser_mtask_xmit - xmit management(immediate) task
   * @conn: iscsi connection
-  * @mtask: task management task
+  * @task: task management task
   *
   * Notes:
   *    The function can return -EAGAIN in which case caller must
   *
   **/
  static int
- iscsi_iser_mtask_xmit(struct iscsi_conn *conn,
-                     struct iscsi_mgmt_task *mtask)
+ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
  {
        int error = 0;
  
-       debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
+       debug_scsi("task deq [cid %d itt 0x%x]\n", conn->id, task->itt);
  
-       error = iser_send_control(conn, mtask);
+       error = iser_send_control(conn, task);
  
-       /* since iser xmits control with zero copy, mtasks can not be recycled
+       /* since iser xmits control with zero copy, tasks can not be recycled
         * right after sending them.
         * The recycling scheme is based on whether a response is expected
-        * - if yes, the mtask is recycled at iscsi_complete_pdu
-        * - if no,  the mtask is recycled at iser_snd_completion
+        * - if yes, the task is recycled at iscsi_complete_pdu
+        * - if no,  the task is recycled at iser_snd_completion
         */
        if (error && error != -ENOBUFS)
                iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
  }
  
  static int
- iscsi_iser_ctask_xmit_unsol_data(struct iscsi_conn *conn,
-                                struct iscsi_cmd_task *ctask)
+ iscsi_iser_task_xmit_unsol_data(struct iscsi_conn *conn,
+                                struct iscsi_task *task)
  {
        struct iscsi_data  hdr;
        int error = 0;
  
        /* Send data-out PDUs while there's still unsolicited data to send */
-       while (ctask->unsol_count > 0) {
-               iscsi_prep_unsolicit_data_pdu(ctask, &hdr);
+       while (task->unsol_count > 0) {
+               iscsi_prep_unsolicit_data_pdu(task, &hdr);
                debug_scsi("Sending data-out: itt 0x%x, data count %d\n",
-                          hdr.itt, ctask->data_count);
+                          hdr.itt, task->data_count);
  
                /* the buffer description has been passed with the command */
                /* Send the command */
-               error = iser_send_data_out(conn, ctask, &hdr);
+               error = iser_send_data_out(conn, task, &hdr);
                if (error) {
-                       ctask->unsol_datasn--;
-                       goto iscsi_iser_ctask_xmit_unsol_data_exit;
+                       task->unsol_datasn--;
+                       goto iscsi_iser_task_xmit_unsol_data_exit;
                }
-               ctask->unsol_count -= ctask->data_count;
+               task->unsol_count -= task->data_count;
                debug_scsi("Need to send %d more as data-out PDUs\n",
-                          ctask->unsol_count);
+                          task->unsol_count);
        }
  
- iscsi_iser_ctask_xmit_unsol_data_exit:
+ iscsi_iser_task_xmit_unsol_data_exit:
        return error;
  }
  
  static int
- iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
-                     struct iscsi_cmd_task *ctask)
+ iscsi_iser_task_xmit(struct iscsi_task *task)
  {
-       struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+       struct iscsi_conn *conn = task->conn;
+       struct iscsi_iser_task *iser_task = task->dd_data;
        int error = 0;
  
-       if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) {
-               BUG_ON(scsi_bufflen(ctask->sc) == 0);
+       if (!task->sc)
+               return iscsi_iser_mtask_xmit(conn, task);
+       if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
+               BUG_ON(scsi_bufflen(task->sc) == 0);
  
                debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
-                          ctask->itt, scsi_bufflen(ctask->sc),
-                          ctask->imm_count, ctask->unsol_count);
+                          task->itt, scsi_bufflen(task->sc),
+                          task->imm_count, task->unsol_count);
        }
  
-       debug_scsi("ctask deq [cid %d itt 0x%x]\n",
-                  conn->id, ctask->itt);
+       debug_scsi("task deq [cid %d itt 0x%x]\n",
+                  conn->id, task->itt);
  
        /* Send the cmd PDU */
-       if (!iser_ctask->command_sent) {
-               error = iser_send_command(conn, ctask);
+       if (!iser_task->command_sent) {
+               error = iser_send_command(conn, task);
                if (error)
-                       goto iscsi_iser_ctask_xmit_exit;
-               iser_ctask->command_sent = 1;
+                       goto iscsi_iser_task_xmit_exit;
+               iser_task->command_sent = 1;
        }
  
        /* Send unsolicited data-out PDU(s) if necessary */
-       if (ctask->unsol_count)
-               error = iscsi_iser_ctask_xmit_unsol_data(conn, ctask);
+       if (task->unsol_count)
+               error = iscsi_iser_task_xmit_unsol_data(conn, task);
  
-  iscsi_iser_ctask_xmit_exit:
+  iscsi_iser_task_xmit_exit:
        if (error && error != -ENOBUFS)
                iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
        return error;
  }
  
  static void
- iscsi_iser_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ iscsi_iser_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task)
  {
-       struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+       struct iscsi_iser_task *iser_task = task->dd_data;
  
-       if (iser_ctask->status == ISER_TASK_STATUS_STARTED) {
-               iser_ctask->status = ISER_TASK_STATUS_COMPLETED;
-               iser_ctask_rdma_finalize(iser_ctask);
-       }
- }
- static struct iser_conn *
- iscsi_iser_ib_conn_lookup(__u64 ep_handle)
- {
-       struct iser_conn *ib_conn;
-       struct iser_conn *uib_conn = (struct iser_conn *)(unsigned long)ep_handle;
+       /* mgmt tasks do not need special cleanup */
+       if (!task->sc)
+               return;
  
-       mutex_lock(&ig.connlist_mutex);
-       list_for_each_entry(ib_conn, &ig.connlist, conn_list) {
-               if (ib_conn == uib_conn) {
-                       mutex_unlock(&ig.connlist_mutex);
-                       return ib_conn;
-               }
+       if (iser_task->status == ISER_TASK_STATUS_STARTED) {
+               iser_task->status = ISER_TASK_STATUS_COMPLETED;
+               iser_task_rdma_finalize(iser_task);
        }
-       mutex_unlock(&ig.connlist_mutex);
-       iser_err("no conn exists for eph %llx\n",(unsigned long long)ep_handle);
-       return NULL;
  }
  
  static struct iscsi_cls_conn *
@@@ -272,7 -269,7 +266,7 @@@ iscsi_iser_conn_create(struct iscsi_cls
        struct iscsi_cls_conn *cls_conn;
        struct iscsi_iser_conn *iser_conn;
  
-       cls_conn = iscsi_conn_setup(cls_session, conn_idx);
+       cls_conn = iscsi_conn_setup(cls_session, sizeof(*iser_conn), conn_idx);
        if (!cls_conn)
                return NULL;
        conn = cls_conn->dd_data;
         */
        conn->max_recv_dlength = 128;
  
-       iser_conn = kzalloc(sizeof(*iser_conn), GFP_KERNEL);
-       if (!iser_conn)
-               goto conn_alloc_fail;
-       /* currently this is the only field which need to be initiated */
-       rwlock_init(&iser_conn->lock);
+       iser_conn = conn->dd_data;
        conn->dd_data = iser_conn;
        iser_conn->iscsi_conn = conn;
  
        return cls_conn;
- conn_alloc_fail:
-       iscsi_conn_teardown(cls_conn);
-       return NULL;
  }
  
  static void
@@@ -305,11 -292,18 +289,18 @@@ iscsi_iser_conn_destroy(struct iscsi_cl
  {
        struct iscsi_conn *conn = cls_conn->dd_data;
        struct iscsi_iser_conn *iser_conn = conn->dd_data;
+       struct iser_conn *ib_conn = iser_conn->ib_conn;
  
        iscsi_conn_teardown(cls_conn);
-       if (iser_conn->ib_conn)
-               iser_conn->ib_conn->iser_conn = NULL;
-       kfree(iser_conn);
+       /*
+        * Userspace will normally call the stop callback and
+        * already have freed the ib_conn, but if it goofed up then
+        * we free it here.
+        */
+       if (ib_conn) {
+               ib_conn->iser_conn = NULL;
+               iser_conn_put(ib_conn);
+       }
  }
  
  static int
@@@ -320,6 -314,7 +311,7 @@@ iscsi_iser_conn_bind(struct iscsi_cls_s
        struct iscsi_conn *conn = cls_conn->dd_data;
        struct iscsi_iser_conn *iser_conn;
        struct iser_conn *ib_conn;
+       struct iscsi_endpoint *ep;
        int error;
  
        error = iscsi_conn_bind(cls_session, cls_conn, is_leading);
  
        /* the transport ep handle comes from user space so it must be
         * verified against the global ib connections list */
-       ib_conn = iscsi_iser_ib_conn_lookup(transport_eph);
-       if (!ib_conn) {
+       ep = iscsi_lookup_endpoint(transport_eph);
+       if (!ep) {
                iser_err("can't bind eph %llx\n",
                         (unsigned long long)transport_eph);
                return -EINVAL;
        }
+       ib_conn = ep->dd_data;
        /* binds the iSER connection retrieved from the previously
         * connected ep_handle to the iSCSI layer connection. exchanges
         * connection pointers */
        iser_conn = conn->dd_data;
        ib_conn->iser_conn = iser_conn;
        iser_conn->ib_conn  = ib_conn;
+       iser_conn_get(ib_conn);
+       return 0;
+ }
  
-       conn->recv_lock = &iser_conn->lock;
+ static void
+ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+ {
+       struct iscsi_conn *conn = cls_conn->dd_data;
+       struct iscsi_iser_conn *iser_conn = conn->dd_data;
+       struct iser_conn *ib_conn = iser_conn->ib_conn;
  
-       return 0;
+       /*
+        * Userspace may have goofed up and not bound the connection or
+        * might have only partially setup the connection.
+        */
+       if (ib_conn) {
+               iscsi_conn_stop(cls_conn, flag);
+               /*
+                * There is no unbind event so the stop callback
+                * must release the ref from the bind.
+                */
+               iser_conn_put(ib_conn);
+       }
+       iser_conn->ib_conn = NULL;
  }
  
  static int
@@@ -360,55 -377,75 +374,75 @@@ iscsi_iser_conn_start(struct iscsi_cls_
        return iscsi_conn_start(cls_conn);
  }
  
- static struct iscsi_transport iscsi_iser_transport;
+ static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
+ {
+       struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+       iscsi_host_remove(shost);
+       iscsi_host_free(shost);
+ }
  
  static struct iscsi_cls_session *
- iscsi_iser_session_create(struct iscsi_transport *iscsit,
-                        struct scsi_transport_template *scsit,
-                        uint16_t cmds_max, uint16_t qdepth,
-                        uint32_t initial_cmdsn, uint32_t *hostno)
+ iscsi_iser_session_create(struct iscsi_endpoint *ep,
+                         uint16_t cmds_max, uint16_t qdepth,
+                         uint32_t initial_cmdsn, uint32_t *hostno)
  {
        struct iscsi_cls_session *cls_session;
        struct iscsi_session *session;
+       struct Scsi_Host *shost;
        int i;
-       uint32_t hn;
-       struct iscsi_cmd_task  *ctask;
-       struct iscsi_mgmt_task *mtask;
-       struct iscsi_iser_cmd_task *iser_ctask;
-       struct iser_desc *desc;
+       struct iscsi_task *task;
+       struct iscsi_iser_task *iser_task;
+       struct iser_conn *ib_conn;
+       shost = iscsi_host_alloc(&iscsi_iser_sht, 0, ISCSI_MAX_CMD_PER_LUN);
+       if (!shost)
+               return NULL;
+       shost->transportt = iscsi_iser_scsi_transport;
+       shost->max_lun = iscsi_max_lun;
+       shost->max_id = 0;
+       shost->max_channel = 0;
+       shost->max_cmd_len = 16;
+       /*
+        * older userspace tools (before 2.0-870) did not pass us
+        * the leading conn's ep so this will be NULL;
+        */
+       if (ep)
+               ib_conn = ep->dd_data;
+       if (iscsi_host_add(shost,
+                          ep ? ib_conn->device->ib_device->dma_device : NULL))
+               goto free_host;
+       *hostno = shost->host_no;
  
        /*
         * we do not support setting can_queue cmd_per_lun from userspace yet
         * because we preallocate so many resources
         */
-       cls_session = iscsi_session_setup(iscsit, scsit,
+       cls_session = iscsi_session_setup(&iscsi_iser_transport, shost,
                                          ISCSI_DEF_XMIT_CMDS_MAX,
-                                         ISCSI_MAX_CMD_PER_LUN,
-                                         sizeof(struct iscsi_iser_cmd_task),
-                                         sizeof(struct iser_desc),
-                                         initial_cmdsn, &hn);
+                                         sizeof(struct iscsi_iser_task),
+                                         initial_cmdsn, 0);
        if (!cls_session)
-       return NULL;
-       *hostno = hn;
-       session = class_to_transport_session(cls_session);
+               goto remove_host;
+       session = cls_session->dd_data;
  
+       shost->can_queue = session->scsi_cmds_max;
        /* libiscsi setup itts, data and pool so just set desc fields */
        for (i = 0; i < session->cmds_max; i++) {
-               ctask      = session->cmds[i];
-               iser_ctask = ctask->dd_data;
-               ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header;
-               ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header);
-       }
-       for (i = 0; i < session->mgmtpool_max; i++) {
-               mtask      = session->mgmt_cmds[i];
-               desc       = mtask->dd_data;
-               mtask->hdr = &desc->iscsi_header;
-               desc->data = mtask->data;
+               task = session->cmds[i];
+               iser_task = task->dd_data;
+               task->hdr = (struct iscsi_cmd *)&iser_task->desc.iscsi_header;
+               task->hdr_max = sizeof(iser_task->desc.iscsi_header);
        }
        return cls_session;
+ remove_host:
+       iscsi_host_remove(shost);
+ free_host:
+       iscsi_host_free(shost);
+       return NULL;
  }
  
  static int
@@@ -481,34 -518,37 +515,37 @@@ iscsi_iser_conn_get_stats(struct iscsi_
        stats->custom[3].value = conn->fmr_unalign_cnt;
  }
  
- static int
- iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking,
-                     __u64 *ep_handle)
+ static struct iscsi_endpoint *
+ iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking)
  {
        int err;
        struct iser_conn *ib_conn;
+       struct iscsi_endpoint *ep;
  
-       err = iser_conn_init(&ib_conn);
-       if (err)
-               goto out;
+       ep = iscsi_create_endpoint(sizeof(*ib_conn));
+       if (!ep)
+               return ERR_PTR(-ENOMEM);
  
-       err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr, non_blocking);
-       if (!err)
-               *ep_handle = (__u64)(unsigned long)ib_conn;
+       ib_conn = ep->dd_data;
+       ib_conn->ep = ep;
+       iser_conn_init(ib_conn);
  
- out:
-       return err;
+       err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr,
+                          non_blocking);
+       if (err) {
+               iscsi_destroy_endpoint(ep);
+               return ERR_PTR(err);
+       }
+       return ep;
  }
  
  static int
- iscsi_iser_ep_poll(__u64 ep_handle, int timeout_ms)
+ iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
  {
-       struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
+       struct iser_conn *ib_conn;
        int rc;
  
-       if (!ib_conn)
-               return -EINVAL;
+       ib_conn = ep->dd_data;
        rc = wait_event_interruptible_timeout(ib_conn->wait,
                             ib_conn->state == ISER_CONN_UP,
                             msecs_to_jiffies(timeout_ms));
  }
  
  static void
- iscsi_iser_ep_disconnect(__u64 ep_handle)
+ iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep)
  {
        struct iser_conn *ib_conn;
  
-       ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
-       if (!ib_conn)
-               return;
+       ib_conn = ep->dd_data;
+       if (ib_conn->iser_conn)
+               /*
+                * Must suspend xmit path if the ep is bound to the
+                * iscsi_conn, so we know we are not accessing the ib_conn
+                * when we free it.
+                *
+                * This may not be bound if the ep poll failed.
+                */
+               iscsi_suspend_tx(ib_conn->iser_conn->iscsi_conn);
  
        iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
        iser_conn_terminate(ib_conn);
@@@ -547,7 -595,6 +592,6 @@@ static struct scsi_host_template iscsi_
        .name                   = "iSCSI Initiator over iSER, v." DRV_VER,
        .queuecommand           = iscsi_queuecommand,
        .change_queue_depth     = iscsi_change_queue_depth,
-       .can_queue              = ISCSI_DEF_XMIT_CMDS_MAX - 1,
        .sg_tablesize           = ISCSI_ISER_SG_TABLESIZE,
        .max_sectors            = 1024,
        .cmd_per_lun            = ISCSI_MAX_CMD_PER_LUN,
@@@ -581,17 -628,14 +625,14 @@@ static struct iscsi_transport iscsi_ise
                                  ISCSI_USERNAME | ISCSI_PASSWORD |
                                  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
                                  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
-                                 ISCSI_PING_TMO | ISCSI_RECV_TMO,
+                                 ISCSI_PING_TMO | ISCSI_RECV_TMO |
+                                 ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
        .host_param_mask        = ISCSI_HOST_HWADDRESS |
                                  ISCSI_HOST_NETDEV_NAME |
                                  ISCSI_HOST_INITIATOR_NAME,
-       .host_template          = &iscsi_iser_sht,
-       .conndata_size          = sizeof(struct iscsi_conn),
-       .max_lun                = ISCSI_ISER_MAX_LUN,
-       .max_cmd_len            = ISCSI_ISER_MAX_CMD_LEN,
        /* session management */
        .create_session         = iscsi_iser_session_create,
-       .destroy_session        = iscsi_session_teardown,
+       .destroy_session        = iscsi_iser_session_destroy,
        /* connection management */
        .create_conn            = iscsi_iser_conn_create,
        .bind_conn              = iscsi_iser_conn_bind,
        .get_conn_param         = iscsi_conn_get_param,
        .get_session_param      = iscsi_session_get_param,
        .start_conn             = iscsi_iser_conn_start,
-       .stop_conn              = iscsi_conn_stop,
+       .stop_conn              = iscsi_iser_conn_stop,
        /* iscsi host params */
        .get_host_param         = iscsi_host_get_param,
        .set_host_param         = iscsi_host_set_param,
        /* IO */
        .send_pdu               = iscsi_conn_send_pdu,
        .get_stats              = iscsi_iser_conn_get_stats,
-       .init_cmd_task          = iscsi_iser_cmd_init,
-       .xmit_cmd_task          = iscsi_iser_ctask_xmit,
-       .xmit_mgmt_task         = iscsi_iser_mtask_xmit,
-       .cleanup_cmd_task       = iscsi_iser_cleanup_ctask,
+       .init_task              = iscsi_iser_task_init,
+       .xmit_task              = iscsi_iser_task_xmit,
+       .cleanup_task           = iscsi_iser_cleanup_task,
        /* recovery */
        .session_recovery_timedout = iscsi_session_recovery_timedout,
  
@@@ -630,8 -673,6 +670,6 @@@ static int __init iser_init(void
                return -EINVAL;
        }
  
-       iscsi_iser_transport.max_lun = iscsi_max_lun;
        memset(&ig, 0, sizeof(struct iser_global));
  
        ig.desc_cache = kmem_cache_create("iser_descriptors",
        mutex_init(&ig.connlist_mutex);
        INIT_LIST_HEAD(&ig.connlist);
  
-       if (!iscsi_register_transport(&iscsi_iser_transport)) {
+       iscsi_iser_scsi_transport = iscsi_register_transport(
+                                                       &iscsi_iser_transport);
+       if (!iscsi_iser_scsi_transport) {
                iser_err("iscsi_register_transport failed\n");
                err = -EINVAL;
                goto register_transport_failure;
index 0e10703cf59e5942dbe003bd9d894e7c3af4f048,a547edeea96937e822e31fb4a1f4aa8fa9f691bc..81a82628a5f1ebba68217ca6d20a5d5fd48bacbd
@@@ -36,6 -36,8 +36,6 @@@
   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
 - *
 - * $Id: iscsi_iser.h 7051 2006-05-10 12:29:11Z ogerlitz $
   */
  #ifndef __ISCSI_ISER_H__
  #define __ISCSI_ISER_H__
@@@ -94,7 -96,6 +94,6 @@@
                                        /* support upto 512KB in one RDMA */
  #define ISCSI_ISER_SG_TABLESIZE         (0x80000 >> SHIFT_4K)
  #define ISCSI_ISER_MAX_LUN            256
- #define ISCSI_ISER_MAX_CMD_LEN                16
  
  /* QP settings */
  /* Maximal bounds on received asynchronous PDUs */
@@@ -172,7 -173,8 +171,8 @@@ struct iser_data_buf 
  /* fwd declarations */
  struct iser_device;
  struct iscsi_iser_conn;
- struct iscsi_iser_cmd_task;
+ struct iscsi_iser_task;
+ struct iscsi_endpoint;
  
  struct iser_mem_reg {
        u32  lkey;
@@@ -196,7 -198,7 +196,7 @@@ struct iser_regd_buf 
  #define MAX_REGD_BUF_VECTOR_LEN       2
  
  struct iser_dto {
-       struct iscsi_iser_cmd_task *ctask;
+       struct iscsi_iser_task *task;
        struct iser_conn *ib_conn;
        int                        notify_enable;
  
@@@ -240,7 -242,9 +240,9 @@@ struct iser_device 
  
  struct iser_conn {
        struct iscsi_iser_conn       *iser_conn; /* iser conn for upcalls  */
+       struct iscsi_endpoint        *ep;
        enum iser_ib_conn_state      state;         /* rdma connection state   */
+       atomic_t                     refcount;
        spinlock_t                   lock;          /* used for state changes  */
        struct iser_device           *device;       /* device context          */
        struct rdma_cm_id            *cma_id;       /* CMA ID                  */
  struct iscsi_iser_conn {
        struct iscsi_conn            *iscsi_conn;/* ptr to iscsi conn */
        struct iser_conn             *ib_conn;   /* iSER IB conn      */
-       rwlock_t                     lock;
  };
  
- struct iscsi_iser_cmd_task {
+ struct iscsi_iser_task {
        struct iser_desc             desc;
        struct iscsi_iser_conn       *iser_conn;
        enum iser_task_status        status;
@@@ -296,22 -298,26 +296,26 @@@ extern int iser_debug_level
  /* allocate connection resources needed for rdma functionality */
  int iser_conn_set_full_featured_mode(struct iscsi_conn *conn);
  
- int iser_send_control(struct iscsi_conn      *conn,
-                     struct iscsi_mgmt_task *mtask);
+ int iser_send_control(struct iscsi_conn *conn,
+                     struct iscsi_task *task);
  
- int iser_send_command(struct iscsi_conn      *conn,
-                     struct iscsi_cmd_task  *ctask);
+ int iser_send_command(struct iscsi_conn *conn,
+                     struct iscsi_task *task);
  
- int iser_send_data_out(struct iscsi_conn     *conn,
-                      struct iscsi_cmd_task *ctask,
-                      struct iscsi_data          *hdr);
+ int iser_send_data_out(struct iscsi_conn *conn,
+                      struct iscsi_task *task,
+                      struct iscsi_data *hdr);
  
  void iscsi_iser_recv(struct iscsi_conn *conn,
                     struct iscsi_hdr       *hdr,
                     char                   *rx_data,
                     int                    rx_data_len);
  
- int  iser_conn_init(struct iser_conn **ib_conn);
+ void iser_conn_init(struct iser_conn *ib_conn);
+ void iser_conn_get(struct iser_conn *ib_conn);
+ void iser_conn_put(struct iser_conn *ib_conn);
  
  void iser_conn_terminate(struct iser_conn *ib_conn);
  
@@@ -320,9 -326,9 +324,9 @@@ void iser_rcv_completion(struct iser_de
  
  void iser_snd_completion(struct iser_desc *desc);
  
- void iser_ctask_rdma_init(struct iscsi_iser_cmd_task     *ctask);
+ void iser_task_rdma_init(struct iscsi_iser_task *task);
  
- void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *ctask);
+ void iser_task_rdma_finalize(struct iscsi_iser_task *task);
  
  void iser_dto_buffs_release(struct iser_dto *dto);
  
@@@ -332,10 -338,10 +336,10 @@@ void iser_reg_single(struct iser_devic
                     struct iser_regd_buf    *regd_buf,
                     enum dma_data_direction direction);
  
- void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
+ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task,
                                     enum iser_data_dir         cmd_dir);
  
- int  iser_reg_rdma_mem(struct iscsi_iser_cmd_task *ctask,
+ int  iser_reg_rdma_mem(struct iscsi_iser_task *task,
                       enum   iser_data_dir        cmd_dir);
  
  int  iser_connect(struct iser_conn   *ib_conn,
@@@ -355,10 -361,10 +359,10 @@@ int  iser_post_send(struct iser_desc *t
  int iser_conn_state_comp(struct iser_conn *ib_conn,
                         enum iser_ib_conn_state comp);
  
- int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
+ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
                            struct iser_data_buf       *data,
                            enum   iser_data_dir       iser_dir,
                            enum   dma_data_direction  dma_dir);
  
- void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask);
+ void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task);
  #endif
index 31ad498bdc51118f0418349c974e3018ccc6f1fb,c36083922134b41ffa6cb1804f9e417fd41962d4..cdd28318904732091be64ed22688109984e032a0
@@@ -28,6 -28,8 +28,6 @@@
   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
 - *
 - * $Id: iser_initiator.c 6964 2006-05-07 11:11:43Z ogerlitz $
   */
  #include <linux/kernel.h>
  #include <linux/slab.h>
@@@ -64,46 -66,46 +64,46 @@@ static void iser_dto_add_regd_buff(stru
  
  /* Register user buffer memory and initialize passive rdma
   *  dto descriptor. Total data size is stored in
-  *  iser_ctask->data[ISER_DIR_IN].data_len
+  *  iser_task->data[ISER_DIR_IN].data_len
   */
- static int iser_prepare_read_cmd(struct iscsi_cmd_task *ctask,
+ static int iser_prepare_read_cmd(struct iscsi_task *task,
                                 unsigned int edtl)
  
  {
-       struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+       struct iscsi_iser_task *iser_task = task->dd_data;
        struct iser_regd_buf *regd_buf;
        int err;
-       struct iser_hdr *hdr = &iser_ctask->desc.iser_header;
-       struct iser_data_buf *buf_in = &iser_ctask->data[ISER_DIR_IN];
+       struct iser_hdr *hdr = &iser_task->desc.iser_header;
+       struct iser_data_buf *buf_in = &iser_task->data[ISER_DIR_IN];
  
-       err = iser_dma_map_task_data(iser_ctask,
+       err = iser_dma_map_task_data(iser_task,
                                     buf_in,
                                     ISER_DIR_IN,
                                     DMA_FROM_DEVICE);
        if (err)
                return err;
  
-       if (edtl > iser_ctask->data[ISER_DIR_IN].data_len) {
+       if (edtl > iser_task->data[ISER_DIR_IN].data_len) {
                iser_err("Total data length: %ld, less than EDTL: "
                         "%d, in READ cmd BHS itt: %d, conn: 0x%p\n",
-                        iser_ctask->data[ISER_DIR_IN].data_len, edtl,
-                        ctask->itt, iser_ctask->iser_conn);
+                        iser_task->data[ISER_DIR_IN].data_len, edtl,
+                        task->itt, iser_task->iser_conn);
                return -EINVAL;
        }
  
-       err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_IN);
+       err = iser_reg_rdma_mem(iser_task,ISER_DIR_IN);
        if (err) {
                iser_err("Failed to set up Data-IN RDMA\n");
                return err;
        }
-       regd_buf = &iser_ctask->rdma_regd[ISER_DIR_IN];
+       regd_buf = &iser_task->rdma_regd[ISER_DIR_IN];
  
        hdr->flags    |= ISER_RSV;
        hdr->read_stag = cpu_to_be32(regd_buf->reg.rkey);
        hdr->read_va   = cpu_to_be64(regd_buf->reg.va);
  
        iser_dbg("Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX\n",
-                ctask->itt, regd_buf->reg.rkey,
+                task->itt, regd_buf->reg.rkey,
                 (unsigned long long)regd_buf->reg.va);
  
        return 0;
  
  /* Register user buffer memory and initialize passive rdma
   *  dto descriptor. Total data size is stored in
-  *  ctask->data[ISER_DIR_OUT].data_len
+  *  task->data[ISER_DIR_OUT].data_len
   */
  static int
- iser_prepare_write_cmd(struct iscsi_cmd_task *ctask,
+ iser_prepare_write_cmd(struct iscsi_task *task,
                       unsigned int imm_sz,
                       unsigned int unsol_sz,
                       unsigned int edtl)
  {
-       struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+       struct iscsi_iser_task *iser_task = task->dd_data;
        struct iser_regd_buf *regd_buf;
        int err;
-       struct iser_dto *send_dto = &iser_ctask->desc.dto;
-       struct iser_hdr *hdr = &iser_ctask->desc.iser_header;
-       struct iser_data_buf *buf_out = &iser_ctask->data[ISER_DIR_OUT];
+       struct iser_dto *send_dto = &iser_task->desc.dto;
+       struct iser_hdr *hdr = &iser_task->desc.iser_header;
+       struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT];
  
-       err = iser_dma_map_task_data(iser_ctask,
+       err = iser_dma_map_task_data(iser_task,
                                     buf_out,
                                     ISER_DIR_OUT,
                                     DMA_TO_DEVICE);
        if (err)
                return err;
  
-       if (edtl > iser_ctask->data[ISER_DIR_OUT].data_len) {
+       if (edtl > iser_task->data[ISER_DIR_OUT].data_len) {
                iser_err("Total data length: %ld, less than EDTL: %d, "
                         "in WRITE cmd BHS itt: %d, conn: 0x%p\n",
-                        iser_ctask->data[ISER_DIR_OUT].data_len,
-                        edtl, ctask->itt, ctask->conn);
+                        iser_task->data[ISER_DIR_OUT].data_len,
+                        edtl, task->itt, task->conn);
                return -EINVAL;
        }
  
-       err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_OUT);
+       err = iser_reg_rdma_mem(iser_task,ISER_DIR_OUT);
        if (err != 0) {
                iser_err("Failed to register write cmd RDMA mem\n");
                return err;
        }
  
-       regd_buf = &iser_ctask->rdma_regd[ISER_DIR_OUT];
+       regd_buf = &iser_task->rdma_regd[ISER_DIR_OUT];
  
        if (unsol_sz < edtl) {
                hdr->flags     |= ISER_WSV;
  
                iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X "
                         "VA:%#llX + unsol:%d\n",
-                        ctask->itt, regd_buf->reg.rkey,
+                        task->itt, regd_buf->reg.rkey,
                         (unsigned long long)regd_buf->reg.va, unsol_sz);
        }
  
        if (imm_sz > 0) {
                iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n",
-                        ctask->itt, imm_sz);
+                        task->itt, imm_sz);
                iser_dto_add_regd_buff(send_dto,
                                       regd_buf,
                                       0,
@@@ -314,38 -316,38 +314,38 @@@ iser_check_xmit(struct iscsi_conn *conn
  /**
   * iser_send_command - send command PDU
   */
- int iser_send_command(struct iscsi_conn     *conn,
-                     struct iscsi_cmd_task *ctask)
+ int iser_send_command(struct iscsi_conn *conn,
+                     struct iscsi_task *task)
  {
        struct iscsi_iser_conn *iser_conn = conn->dd_data;
-       struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+       struct iscsi_iser_task *iser_task = task->dd_data;
        struct iser_dto *send_dto = NULL;
        unsigned long edtl;
        int err = 0;
        struct iser_data_buf *data_buf;
  
-       struct iscsi_cmd *hdr =  ctask->hdr;
-       struct scsi_cmnd *sc  =  ctask->sc;
+       struct iscsi_cmd *hdr =  task->hdr;
+       struct scsi_cmnd *sc  =  task->sc;
  
        if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
                iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
                return -EPERM;
        }
-       if (iser_check_xmit(conn, ctask))
+       if (iser_check_xmit(conn, task))
                return -ENOBUFS;
  
        edtl = ntohl(hdr->data_length);
  
        /* build the tx desc regd header and add it to the tx desc dto */
-       iser_ctask->desc.type = ISCSI_TX_SCSI_COMMAND;
-       send_dto = &iser_ctask->desc.dto;
-       send_dto->ctask = iser_ctask;
-       iser_create_send_desc(iser_conn, &iser_ctask->desc);
+       iser_task->desc.type = ISCSI_TX_SCSI_COMMAND;
+       send_dto = &iser_task->desc.dto;
+       send_dto->task = iser_task;
+       iser_create_send_desc(iser_conn, &iser_task->desc);
  
        if (hdr->flags & ISCSI_FLAG_CMD_READ)
-               data_buf = &iser_ctask->data[ISER_DIR_IN];
+               data_buf = &iser_task->data[ISER_DIR_IN];
        else
-               data_buf = &iser_ctask->data[ISER_DIR_OUT];
+               data_buf = &iser_task->data[ISER_DIR_OUT];
  
        if (scsi_sg_count(sc)) { /* using a scatter list */
                data_buf->buf  = scsi_sglist(sc);
        data_buf->data_len = scsi_bufflen(sc);
  
        if (hdr->flags & ISCSI_FLAG_CMD_READ) {
-               err = iser_prepare_read_cmd(ctask, edtl);
+               err = iser_prepare_read_cmd(task, edtl);
                if (err)
                        goto send_command_error;
        }
        if (hdr->flags & ISCSI_FLAG_CMD_WRITE) {
-               err = iser_prepare_write_cmd(ctask,
-                                            ctask->imm_count,
-                                            ctask->imm_count +
-                                            ctask->unsol_count,
+               err = iser_prepare_write_cmd(task,
+                                            task->imm_count,
+                                            task->imm_count +
+                                            task->unsol_count,
                                             edtl);
                if (err)
                        goto send_command_error;
                goto send_command_error;
        }
  
-       iser_ctask->status = ISER_TASK_STATUS_STARTED;
+       iser_task->status = ISER_TASK_STATUS_STARTED;
  
-       err = iser_post_send(&iser_ctask->desc);
+       err = iser_post_send(&iser_task->desc);
        if (!err)
                return 0;
  
  send_command_error:
        iser_dto_buffs_release(send_dto);
-       iser_err("conn %p failed ctask->itt %d err %d\n",conn, ctask->itt, err);
+       iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err);
        return err;
  }
  
  /**
   * iser_send_data_out - send data out PDU
   */
- int iser_send_data_out(struct iscsi_conn     *conn,
-                      struct iscsi_cmd_task *ctask,
+ int iser_send_data_out(struct iscsi_conn *conn,
+                      struct iscsi_task *task,
                       struct iscsi_data *hdr)
  {
        struct iscsi_iser_conn *iser_conn = conn->dd_data;
-       struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+       struct iscsi_iser_task *iser_task = task->dd_data;
        struct iser_desc *tx_desc = NULL;
        struct iser_dto *send_dto = NULL;
        unsigned long buf_offset;
                return -EPERM;
        }
  
-       if (iser_check_xmit(conn, ctask))
+       if (iser_check_xmit(conn, task))
                return -ENOBUFS;
  
        itt = (__force uint32_t)hdr->itt;
  
        /* build the tx desc regd header and add it to the tx desc dto */
        send_dto = &tx_desc->dto;
-       send_dto->ctask = iser_ctask;
+       send_dto->task = iser_task;
        iser_create_send_desc(iser_conn, tx_desc);
  
        iser_reg_single(iser_conn->ib_conn->device,
  
        /* all data was registered for RDMA, we can use the lkey */
        iser_dto_add_regd_buff(send_dto,
-                              &iser_ctask->rdma_regd[ISER_DIR_OUT],
+                              &iser_task->rdma_regd[ISER_DIR_OUT],
                               buf_offset,
                               data_seg_len);
  
-       if (buf_offset + data_seg_len > iser_ctask->data[ISER_DIR_OUT].data_len) {
+       if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) {
                iser_err("Offset:%ld & DSL:%ld in Data-Out "
                         "inconsistent with total len:%ld, itt:%d\n",
                         buf_offset, data_seg_len,
-                        iser_ctask->data[ISER_DIR_OUT].data_len, itt);
+                        iser_task->data[ISER_DIR_OUT].data_len, itt);
                err = -EINVAL;
                goto send_data_out_error;
        }
@@@ -468,10 -470,11 +468,11 @@@ send_data_out_error
  }
  
  int iser_send_control(struct iscsi_conn *conn,
-                     struct iscsi_mgmt_task *mtask)
+                     struct iscsi_task *task)
  {
        struct iscsi_iser_conn *iser_conn = conn->dd_data;
-       struct iser_desc *mdesc = mtask->dd_data;
+       struct iscsi_iser_task *iser_task = task->dd_data;
+       struct iser_desc *mdesc = &iser_task->desc;
        struct iser_dto *send_dto = NULL;
        unsigned long data_seg_len;
        int err = 0;
                return -EPERM;
        }
  
-       if (iser_check_xmit(conn,mtask))
+       if (iser_check_xmit(conn, task))
                return -ENOBUFS;
  
        /* build the tx desc regd header and add it to the tx desc dto */
        mdesc->type = ISCSI_TX_CONTROL;
        send_dto = &mdesc->dto;
-       send_dto->ctask = NULL;
+       send_dto->task = NULL;
        iser_create_send_desc(iser_conn, mdesc);
  
        device = iser_conn->ib_conn->device;
  
        iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE);
  
-       data_seg_len = ntoh24(mtask->hdr->dlength);
+       data_seg_len = ntoh24(task->hdr->dlength);
  
        if (data_seg_len > 0) {
                regd_buf = &mdesc->data_regd_buf;
                memset(regd_buf, 0, sizeof(struct iser_regd_buf));
                regd_buf->device = device;
-               regd_buf->virt_addr = mtask->data;
-               regd_buf->data_size = mtask->data_count;
+               regd_buf->virt_addr = task->data;
+               regd_buf->data_size = task->data_count;
                iser_reg_single(device, regd_buf,
                                DMA_TO_DEVICE);
                iser_dto_add_regd_buff(send_dto, regd_buf,
@@@ -533,15 -536,13 +534,13 @@@ send_control_error
  void iser_rcv_completion(struct iser_desc *rx_desc,
                         unsigned long dto_xfer_len)
  {
-       struct iser_dto        *dto = &rx_desc->dto;
+       struct iser_dto *dto = &rx_desc->dto;
        struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn;
-       struct iscsi_session *session = conn->iscsi_conn->session;
-       struct iscsi_cmd_task *ctask;
-       struct iscsi_iser_cmd_task *iser_ctask;
+       struct iscsi_task *task;
+       struct iscsi_iser_task *iser_task;
        struct iscsi_hdr *hdr;
        char   *rx_data = NULL;
        int     rx_data_len = 0;
-       unsigned int itt;
        unsigned char opcode;
  
        hdr = &rx_desc->iscsi_header;
        opcode = hdr->opcode & ISCSI_OPCODE_MASK;
  
        if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
-               itt = get_itt(hdr->itt); /* mask out cid and age bits */
-               if (!(itt < session->cmds_max))
+               spin_lock(&conn->iscsi_conn->session->lock);
+               task = iscsi_itt_to_ctask(conn->iscsi_conn, hdr->itt);
+               if (task)
+                       __iscsi_get_task(task);
+               spin_unlock(&conn->iscsi_conn->session->lock);
+               if (!task)
                        iser_err("itt can't be matched to task!!! "
-                                "conn %p opcode %d cmds_max %d itt %d\n",
-                                conn->iscsi_conn,opcode,session->cmds_max,itt);
-               /* use the mapping given with the cmds array indexed by itt */
-               ctask = (struct iscsi_cmd_task *)session->cmds[itt];
-               iser_ctask = ctask->dd_data;
-               iser_dbg("itt %d ctask %p\n",itt,ctask);
-               iser_ctask->status = ISER_TASK_STATUS_COMPLETED;
-               iser_ctask_rdma_finalize(iser_ctask);
+                                "conn %p opcode %d itt %d\n",
+                                conn->iscsi_conn, opcode, hdr->itt);
+               else {
+                       iser_task = task->dd_data;
+                       iser_dbg("itt %d task %p\n",hdr->itt, task);
+                       iser_task->status = ISER_TASK_STATUS_COMPLETED;
+                       iser_task_rdma_finalize(iser_task);
+                       iscsi_put_task(task);
+               }
        }
        iser_dto_buffs_release(dto);
  
        iscsi_iser_recv(conn->iscsi_conn, hdr, rx_data, rx_data_len);
@@@ -590,7 -596,7 +594,7 @@@ void iser_snd_completion(struct iser_de
        struct iser_conn       *ib_conn = dto->ib_conn;
        struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn;
        struct iscsi_conn      *conn = iser_conn->iscsi_conn;
-       struct iscsi_mgmt_task *mtask;
+       struct iscsi_task *task;
        int resume_tx = 0;
  
        iser_dbg("Initiator, Data sent dto=0x%p\n", dto);
  
        if (tx_desc->type == ISCSI_TX_CONTROL) {
                /* this arithmetic is legal by libiscsi dd_data allocation */
-               mtask = (void *) ((long)(void *)tx_desc -
-                                 sizeof(struct iscsi_mgmt_task));
-               if (mtask->hdr->itt == RESERVED_ITT) {
-                       struct iscsi_session *session = conn->session;
-                       spin_lock(&conn->session->lock);
-                       iscsi_free_mgmt_task(conn, mtask);
-                       spin_unlock(&session->lock);
-               }
+               task = (void *) ((long)(void *)tx_desc -
+                                 sizeof(struct iscsi_task));
+               if (task->hdr->itt == RESERVED_ITT)
+                       iscsi_put_task(task);
        }
  }
  
- void iser_ctask_rdma_init(struct iscsi_iser_cmd_task *iser_ctask)
+ void iser_task_rdma_init(struct iscsi_iser_task *iser_task)
  
  {
-       iser_ctask->status = ISER_TASK_STATUS_INIT;
+       iser_task->status = ISER_TASK_STATUS_INIT;
  
-       iser_ctask->dir[ISER_DIR_IN] = 0;
-       iser_ctask->dir[ISER_DIR_OUT] = 0;
+       iser_task->dir[ISER_DIR_IN] = 0;
+       iser_task->dir[ISER_DIR_OUT] = 0;
  
-       iser_ctask->data[ISER_DIR_IN].data_len  = 0;
-       iser_ctask->data[ISER_DIR_OUT].data_len = 0;
+       iser_task->data[ISER_DIR_IN].data_len  = 0;
+       iser_task->data[ISER_DIR_OUT].data_len = 0;
  
-       memset(&iser_ctask->rdma_regd[ISER_DIR_IN], 0,
+       memset(&iser_task->rdma_regd[ISER_DIR_IN], 0,
               sizeof(struct iser_regd_buf));
-       memset(&iser_ctask->rdma_regd[ISER_DIR_OUT], 0,
+       memset(&iser_task->rdma_regd[ISER_DIR_OUT], 0,
               sizeof(struct iser_regd_buf));
  }
  
- void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask)
+ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
  {
        int deferred;
        int is_rdma_aligned = 1;
        /* if we were reading, copy back to unaligned sglist,
         * anyway dma_unmap and free the copy
         */
-       if (iser_ctask->data_copy[ISER_DIR_IN].copy_buf != NULL) {
+       if (iser_task->data_copy[ISER_DIR_IN].copy_buf != NULL) {
                is_rdma_aligned = 0;
-               iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_IN);
+               iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_IN);
        }
-       if (iser_ctask->data_copy[ISER_DIR_OUT].copy_buf != NULL) {
+       if (iser_task->data_copy[ISER_DIR_OUT].copy_buf != NULL) {
                is_rdma_aligned = 0;
-               iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_OUT);
+               iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_OUT);
        }
  
-       if (iser_ctask->dir[ISER_DIR_IN]) {
-               regd = &iser_ctask->rdma_regd[ISER_DIR_IN];
+       if (iser_task->dir[ISER_DIR_IN]) {
+               regd = &iser_task->rdma_regd[ISER_DIR_IN];
                deferred = iser_regd_buff_release(regd);
                if (deferred) {
                        iser_err("%d references remain for BUF-IN rdma reg\n",
                }
        }
  
-       if (iser_ctask->dir[ISER_DIR_OUT]) {
-               regd = &iser_ctask->rdma_regd[ISER_DIR_OUT];
+       if (iser_task->dir[ISER_DIR_OUT]) {
+               regd = &iser_task->rdma_regd[ISER_DIR_OUT];
                deferred = iser_regd_buff_release(regd);
                if (deferred) {
                        iser_err("%d references remain for BUF-OUT rdma reg\n",
  
         /* if the data was unaligned, it was already unmapped and then copied */
         if (is_rdma_aligned)
-               iser_dma_unmap_task_data(iser_ctask);
+               iser_dma_unmap_task_data(iser_task);
  }
  
  void iser_dto_buffs_release(struct iser_dto *dto)
index 81e49cb10ed36b517f1636c408bc86f5ec211261,48f2a601fc27d429bbaef53d77447aa3d77ef4a3..b9453d068e9d81922568daa82f733649c5b623f2
@@@ -28,6 -28,8 +28,6 @@@
   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
 - *
 - * $Id: iser_memory.c 6964 2006-05-07 11:11:43Z ogerlitz $
   */
  #include <linux/module.h>
  #include <linux/kernel.h>
@@@ -99,13 -101,13 +99,13 @@@ void iser_reg_single(struct iser_devic
  /**
   * iser_start_rdma_unaligned_sg
   */
- static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
                                        enum iser_data_dir cmd_dir)
  {
        int dma_nents;
        struct ib_device *dev;
        char *mem = NULL;
-       struct iser_data_buf *data = &iser_ctask->data[cmd_dir];
+       struct iser_data_buf *data = &iser_task->data[cmd_dir];
        unsigned long  cmd_data_len = data->data_len;
  
        if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
                }
        }
  
-       sg_init_one(&iser_ctask->data_copy[cmd_dir].sg_single, mem, cmd_data_len);
-       iser_ctask->data_copy[cmd_dir].buf  =
-               &iser_ctask->data_copy[cmd_dir].sg_single;
-       iser_ctask->data_copy[cmd_dir].size = 1;
+       sg_init_one(&iser_task->data_copy[cmd_dir].sg_single, mem, cmd_data_len);
+       iser_task->data_copy[cmd_dir].buf  =
+               &iser_task->data_copy[cmd_dir].sg_single;
+       iser_task->data_copy[cmd_dir].size = 1;
  
-       iser_ctask->data_copy[cmd_dir].copy_buf  = mem;
+       iser_task->data_copy[cmd_dir].copy_buf  = mem;
  
-       dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
+       dev = iser_task->iser_conn->ib_conn->device->ib_device;
        dma_nents = ib_dma_map_sg(dev,
-                                 &iser_ctask->data_copy[cmd_dir].sg_single,
+                                 &iser_task->data_copy[cmd_dir].sg_single,
                                  1,
                                  (cmd_dir == ISER_DIR_OUT) ?
                                  DMA_TO_DEVICE : DMA_FROM_DEVICE);
        BUG_ON(dma_nents == 0);
  
-       iser_ctask->data_copy[cmd_dir].dma_nents = dma_nents;
+       iser_task->data_copy[cmd_dir].dma_nents = dma_nents;
        return 0;
  }
  
  /**
   * iser_finalize_rdma_unaligned_sg
   */
- void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
                                     enum iser_data_dir         cmd_dir)
  {
        struct ib_device *dev;
        struct iser_data_buf *mem_copy;
        unsigned long  cmd_data_len;
  
-       dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
-       mem_copy = &iser_ctask->data_copy[cmd_dir];
+       dev = iser_task->iser_conn->ib_conn->device->ib_device;
+       mem_copy = &iser_task->data_copy[cmd_dir];
  
        ib_dma_unmap_sg(dev, &mem_copy->sg_single, 1,
                        (cmd_dir == ISER_DIR_OUT) ?
                /* copy back read RDMA to unaligned sg */
                mem     = mem_copy->copy_buf;
  
-               sgl     = (struct scatterlist *)iser_ctask->data[ISER_DIR_IN].buf;
-               sg_size = iser_ctask->data[ISER_DIR_IN].size;
+               sgl     = (struct scatterlist *)iser_task->data[ISER_DIR_IN].buf;
+               sg_size = iser_task->data[ISER_DIR_IN].size;
  
                p = mem;
                for_each_sg(sgl, sg, sg_size, i) {
                }
        }
  
-       cmd_data_len = iser_ctask->data[cmd_dir].data_len;
+       cmd_data_len = iser_task->data[cmd_dir].data_len;
  
        if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
                free_pages((unsigned long)mem_copy->copy_buf,
@@@ -376,15 -378,15 +376,15 @@@ static void iser_page_vec_build(struct 
        }
  }
  
- int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
-                           struct iser_data_buf       *data,
-                           enum   iser_data_dir       iser_dir,
-                           enum   dma_data_direction  dma_dir)
+ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
+                           struct iser_data_buf *data,
+                           enum iser_data_dir iser_dir,
+                           enum dma_data_direction dma_dir)
  {
        struct ib_device *dev;
  
-       iser_ctask->dir[iser_dir] = 1;
-       dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
+       iser_task->dir[iser_dir] = 1;
+       dev = iser_task->iser_conn->ib_conn->device->ib_device;
  
        data->dma_nents = ib_dma_map_sg(dev, data->buf, data->size, dma_dir);
        if (data->dma_nents == 0) {
        return 0;
  }
  
- void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
+ void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task)
  {
        struct ib_device *dev;
        struct iser_data_buf *data;
  
-       dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
+       dev = iser_task->iser_conn->ib_conn->device->ib_device;
  
-       if (iser_ctask->dir[ISER_DIR_IN]) {
-               data = &iser_ctask->data[ISER_DIR_IN];
+       if (iser_task->dir[ISER_DIR_IN]) {
+               data = &iser_task->data[ISER_DIR_IN];
                ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE);
        }
  
-       if (iser_ctask->dir[ISER_DIR_OUT]) {
-               data = &iser_ctask->data[ISER_DIR_OUT];
+       if (iser_task->dir[ISER_DIR_OUT]) {
+               data = &iser_task->data[ISER_DIR_OUT];
                ib_dma_unmap_sg(dev, data->buf, data->size, DMA_TO_DEVICE);
        }
  }
   *
   * returns 0 on success, errno code on failure
   */
- int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
+ int iser_reg_rdma_mem(struct iscsi_iser_task *iser_task,
                      enum   iser_data_dir        cmd_dir)
  {
-       struct iscsi_conn    *iscsi_conn = iser_ctask->iser_conn->iscsi_conn;
-       struct iser_conn     *ib_conn = iser_ctask->iser_conn->ib_conn;
+       struct iscsi_conn    *iscsi_conn = iser_task->iser_conn->iscsi_conn;
+       struct iser_conn     *ib_conn = iser_task->iser_conn->ib_conn;
        struct iser_device   *device = ib_conn->device;
        struct ib_device     *ibdev = device->ib_device;
-       struct iser_data_buf *mem = &iser_ctask->data[cmd_dir];
+       struct iser_data_buf *mem = &iser_task->data[cmd_dir];
        struct iser_regd_buf *regd_buf;
        int aligned_len;
        int err;
        int i;
        struct scatterlist *sg;
  
-       regd_buf = &iser_ctask->rdma_regd[cmd_dir];
+       regd_buf = &iser_task->rdma_regd[cmd_dir];
  
        aligned_len = iser_data_buf_aligned_len(mem, ibdev);
        if (aligned_len != mem->dma_nents) {
                iser_data_buf_dump(mem, ibdev);
  
                /* unmap the command data before accessing it */
-               iser_dma_unmap_task_data(iser_ctask);
+               iser_dma_unmap_task_data(iser_task);
  
                /* allocate copy buf, if we are writing, copy the */
                /* unaligned scatterlist, dma map the copy        */
-               if (iser_start_rdma_unaligned_sg(iser_ctask, cmd_dir) != 0)
+               if (iser_start_rdma_unaligned_sg(iser_task, cmd_dir) != 0)
                                return -ENOMEM;
-               mem = &iser_ctask->data_copy[cmd_dir];
+               mem = &iser_task->data_copy[cmd_dir];
        }
  
        /* if there a single dma entry, FMR is not needed */
                err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, &regd_buf->reg);
                if (err) {
                        iser_data_buf_dump(mem, ibdev);
-                       iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents,
-                                ntoh24(iser_ctask->desc.iscsi_header.dlength));
+                       iser_err("mem->dma_nents = %d (dlength = 0x%x)\n",
+                                mem->dma_nents,
+                                ntoh24(iser_task->desc.iscsi_header.dlength));
                        iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n",
                                 ib_conn->page_vec->data_size, ib_conn->page_vec->length,
                                 ib_conn->page_vec->offset);
index 77cabee7cc088002a8d3b3f02d6f2b3ed441bb1d,81b45d4d9aa9ca4dddd30e4e2153b1eab414721f..3a917c1f796fe7d3931f43dec8e15c4716042ccf
@@@ -29,6 -29,8 +29,6 @@@
   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
 - *
 - * $Id: iser_verbs.c 7051 2006-05-10 12:29:11Z ogerlitz $
   */
  #include <linux/kernel.h>
  #include <linux/module.h>
@@@ -323,7 -325,18 +323,18 @@@ static void iser_conn_release(struct is
                iser_device_try_release(device);
        if (ib_conn->iser_conn)
                ib_conn->iser_conn->ib_conn = NULL;
-       kfree(ib_conn);
+       iscsi_destroy_endpoint(ib_conn->ep);
+ }
+ void iser_conn_get(struct iser_conn *ib_conn)
+ {
+       atomic_inc(&ib_conn->refcount);
+ }
+ void iser_conn_put(struct iser_conn *ib_conn)
+ {
+       if (atomic_dec_and_test(&ib_conn->refcount))
+               iser_conn_release(ib_conn);
  }
  
  /**
@@@ -347,7 -360,7 +358,7 @@@ void iser_conn_terminate(struct iser_co
        wait_event_interruptible(ib_conn->wait,
                                 ib_conn->state == ISER_CONN_DOWN);
  
-       iser_conn_release(ib_conn);
+       iser_conn_put(ib_conn);
  }
  
  static void iser_connect_error(struct rdma_cm_id *cma_id)
@@@ -481,24 -494,15 +492,15 @@@ static int iser_cma_handler(struct rdma
        return ret;
  }
  
int iser_conn_init(struct iser_conn **ibconn)
void iser_conn_init(struct iser_conn *ib_conn)
  {
-       struct iser_conn *ib_conn;
-       ib_conn = kzalloc(sizeof *ib_conn, GFP_KERNEL);
-       if (!ib_conn) {
-               iser_err("can't alloc memory for struct iser_conn\n");
-               return -ENOMEM;
-       }
        ib_conn->state = ISER_CONN_INIT;
        init_waitqueue_head(&ib_conn->wait);
        atomic_set(&ib_conn->post_recv_buf_count, 0);
        atomic_set(&ib_conn->post_send_buf_count, 0);
+       atomic_set(&ib_conn->refcount, 1);
        INIT_LIST_HEAD(&ib_conn->conn_list);
        spin_lock_init(&ib_conn->lock);
-       *ibconn = ib_conn;
-       return 0;
  }
  
   /**
index d40d6d15ae20f62d158d5456f857689e051cdf5a,9bc35617b8719beb84b8acf542fd79754c4eca98..75e599b85b645aba6d4de501f7f6c22e01dfa825
@@@ -5,7 -5,7 +5,7 @@@
   *      For use with LSI PCI chip/adapter(s)
   *      running LSI Fusion MPT (Message Passing Technology) firmware.
   *
-  *  Copyright (c) 1999-2007 LSI Corporation
+  *  Copyright (c) 1999-2008 LSI Corporation
   *  (mailto:DL-MPTFusionLinux@lsi.com)
   *
   */
@@@ -103,7 -103,7 +103,7 @@@ static int mfcounter = 0
   *  Public data...
   */
  
- struct proc_dir_entry *mpt_proc_root_dir;
+ static struct proc_dir_entry *mpt_proc_root_dir;
  
  #define WHOINIT_UNKNOWN               0xAA
  
@@@ -253,6 -253,55 +253,55 @@@ mpt_get_cb_idx(MPT_DRIVER_CLASS dclass
        return 0;
  }
  
+ /**
+  *    mpt_fault_reset_work - work performed on workq after ioc fault
+  *    @work: input argument, used to derive ioc
+  *
+ **/
+ static void
+ mpt_fault_reset_work(struct work_struct *work)
+ {
+       MPT_ADAPTER     *ioc =
+           container_of(work, MPT_ADAPTER, fault_reset_work.work);
+       u32              ioc_raw_state;
+       int              rc;
+       unsigned long    flags;
+       if (ioc->diagPending || !ioc->active)
+               goto out;
+       ioc_raw_state = mpt_GetIocState(ioc, 0);
+       if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+               printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
+                   ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+               printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
+                   ioc->name, __FUNCTION__);
+               rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
+               printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
+                   __FUNCTION__, (rc == 0) ? "success" : "failed");
+               ioc_raw_state = mpt_GetIocState(ioc, 0);
+               if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
+                       printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
+                           "reset (%04xh)\n", ioc->name, ioc_raw_state &
+                           MPI_DOORBELL_DATA_MASK);
+       }
+  out:
+       /*
+        * Take turns polling alternate controller
+        */
+       if (ioc->alt_ioc)
+               ioc = ioc->alt_ioc;
+       /* rearm the timer */
+       spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+       if (ioc->reset_work_q)
+               queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+                       msecs_to_jiffies(MPT_POLLING_INTERVAL));
+       spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+ }
  /*
   *  Process turbo (context) reply...
   */
@@@ -1616,6 -1665,22 +1665,22 @@@ mpt_attach(struct pci_dev *pdev, const 
        /* Find lookup slot. */
        INIT_LIST_HEAD(&ioc->list);
  
+       /* Initialize workqueue */
+       INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
+       spin_lock_init(&ioc->fault_reset_work_lock);
+       snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id);
+       ioc->reset_work_q =
+               create_singlethread_workqueue(ioc->reset_work_q_name);
+       if (!ioc->reset_work_q) {
+               printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
+                   ioc->name);
+               pci_release_selected_regions(pdev, ioc->bars);
+               kfree(ioc);
+               return -ENOMEM;
+       }
        dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
            ioc->name, &ioc->facts, &ioc->pfacts[0]));
  
                ioc->bus_type = SAS;
        }
  
 -      if (ioc->bus_type == SAS && mpt_msi_enable == -1)
 -              ioc->msi_enable = 1;
 -      else
 +      if (mpt_msi_enable == -1) {
 +              /* Enable on SAS, disable on FC and SPI */
 +              if (ioc->bus_type == SAS)
 +                      ioc->msi_enable = 1;
 +              else
 +                      ioc->msi_enable = 0;
 +      } else
 +              /* follow flag: 0 - disable; 1 - enable */
                ioc->msi_enable = mpt_msi_enable;
  
        if (ioc->errata_flag_1064)
                iounmap(ioc->memmap);
                if (r != -5)
                        pci_release_selected_regions(pdev, ioc->bars);
+               destroy_workqueue(ioc->reset_work_q);
+               ioc->reset_work_q = NULL;
                kfree(ioc);
                pci_set_drvdata(pdev, NULL);
                return r;
        }
  #endif
  
+       if (!ioc->alt_ioc)
+               queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+                       msecs_to_jiffies(MPT_POLLING_INTERVAL));
        return 0;
  }
  
@@@ -1774,6 -1842,19 +1847,19 @@@ mpt_detach(struct pci_dev *pdev
        MPT_ADAPTER     *ioc = pci_get_drvdata(pdev);
        char pname[32];
        u8 cb_idx;
+       unsigned long flags;
+       struct workqueue_struct *wq;
+       /*
+        * Stop polling ioc for fault condition
+        */
+       spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+       wq = ioc->reset_work_q;
+       ioc->reset_work_q = NULL;
+       spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+       cancel_delayed_work(&ioc->fault_reset_work);
+       destroy_workqueue(wq);
  
        sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
        remove_proc_entry(pname, NULL);
@@@ -7456,7 -7537,6 +7542,6 @@@ EXPORT_SYMBOL(mpt_resume)
  EXPORT_SYMBOL(mpt_suspend);
  #endif
  EXPORT_SYMBOL(ioc_list);
- EXPORT_SYMBOL(mpt_proc_root_dir);
  EXPORT_SYMBOL(mpt_register);
  EXPORT_SYMBOL(mpt_deregister);
  EXPORT_SYMBOL(mpt_event_register);
index c5946560c4e222a48b26e23cc275d78691cee1eb,68c844b2859de4ccd259804c99ac6129e146c5d1..a5920423e2b23ac75ac4913ee9d142ebb755527c
@@@ -4,7 -4,7 +4,7 @@@
   *      For use with LSI PCI chip/adapters
   *      running LSI Fusion MPT (Message Passing Technology) firmware.
   *
-  *  Copyright (c) 1999-2007 LSI Corporation
+  *  Copyright (c) 1999-2008 LSI Corporation
   *  (mailto:DL-MPTFusionLinux@lsi.com)
   *
   */
@@@ -66,7 -66,7 +66,7 @@@
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_tcq.h>
  
- #define COPYRIGHT     "Copyright (c) 1999-2007 LSI Corporation"
+ #define COPYRIGHT     "Copyright (c) 1999-2008 LSI Corporation"
  #define MODULEAUTHOR  "LSI Corporation"
  #include "mptbase.h"
  #include "mptctl.h"
@@@ -548,15 -548,11 +548,15 @@@ static in
  mptctl_fasync(int fd, struct file *filep, int mode)
  {
        MPT_ADAPTER     *ioc;
 +      int ret;
  
 +      lock_kernel();
        list_for_each_entry(ioc, &ioc_list, list)
                ioc->aen_event_read_flag=0;
  
 -      return fasync_helper(fd, filep, mode, &async_queue);
 +      ret = fasync_helper(fd, filep, mode, &async_queue);
 +      unlock_kernel();
 +      return ret;
  }
  
  static int
index 1effca4e40e119d28f5ae3b9ed681f60eaa026f0,9b49516cf5a099cf6ee8308b911e2923007a1623..61620144e49c32c82a834e9911035dc675691f1e
@@@ -3,7 -3,7 +3,7 @@@
   *      For use with LSI PCI chip/adapter(s)
   *      running LSI Fusion MPT (Message Passing Technology) firmware.
   *
-  *  Copyright (c) 1999-2007 LSI Corporation
+  *  Copyright (c) 1999-2008 LSI Corporation
   *  (mailto:DL-MPTFusionLinux@lsi.com)
   *
   */
@@@ -447,6 -447,7 +447,7 @@@ static int mptspi_target_alloc(struct s
        spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
  
        spi_offset(starget) = 0;
+       spi_period(starget) = 0xFF;
        mptspi_write_width(starget, 0);
  
        return 0;
@@@ -1266,18 -1267,13 +1267,18 @@@ mptspi_dv_renegotiate(struct _MPT_SCSI_
  static int
  mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
  {
 -      struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
        int rc;
  
        rc = mptscsih_ioc_reset(ioc, reset_phase);
  
 -      if (reset_phase == MPT_IOC_POST_RESET)
 +      /* only try to do a renegotiation if we're properly set up
 +       * if we get an ioc fault on bringup, ioc->sh will be NULL */
 +      if (reset_phase == MPT_IOC_POST_RESET &&
 +          ioc->sh) {
 +              struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
 +
                mptspi_dv_renegotiate(hd);
 +      }
  
        return rc;
  }
index 68c140e826735287f007f91da091de3e17899a48,5797b2c42f0859e1f4fbb4481a901651b8ba7706..9aa301c1ed07ac5275ceae2635bdbf8c4ecb650e
@@@ -38,7 -38,6 +38,7 @@@
  #include <linux/moduleparam.h>
  #include <linux/pci.h>
  #include <linux/slab.h>
 +#include <linux/smp_lock.h>
  #include <linux/spinlock.h>
  #include <linux/syscalls.h>
  #include <linux/delay.h>
@@@ -668,7 -667,6 +668,7 @@@ static int aac_cfg_open(struct inode *i
        unsigned minor_number = iminor(inode);
        int err = -ENODEV;
  
 +      lock_kernel();  /* BKL pushdown: nothing else protects this list */
        list_for_each_entry(aac, &aac_devices, entry) {
                if (aac->id == minor_number) {
                        file->private_data = aac;
                        break;
                }
        }
 +      unlock_kernel();
  
        return err;
  }
@@@ -865,7 -862,7 +865,7 @@@ static ssize_t aac_show_bios_version(st
        return len;
  }
  
- ssize_t aac_show_serial_number(struct device *device,
+ static ssize_t aac_show_serial_number(struct device *device,
                               struct device_attribute *attr, char *buf)
  {
        struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata;
diff --combined drivers/scsi/esp_scsi.c
index 59fbef08d690763920af4b7fac52752f30be0570,3d5ad243e77fcb5927c99571c810fc843988e656..62a4618530d02fc703c2f571447e39fc93a20992
@@@ -219,19 -219,10 +219,10 @@@ static void esp_reset_esp(struct esp *e
        /* Now reset the ESP chip */
        scsi_esp_cmd(esp, ESP_CMD_RC);
        scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+       if (esp->rev == FAST)
+               esp_write8(ESP_CONFIG2_FENAB, ESP_CFG2);
        scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
  
-       /* Reload the configuration registers */
-       esp_write8(esp->cfact, ESP_CFACT);
-       esp->prev_stp = 0;
-       esp_write8(esp->prev_stp, ESP_STP);
-       esp->prev_soff = 0;
-       esp_write8(esp->prev_soff, ESP_SOFF);
-       esp_write8(esp->neg_defp, ESP_TIMEO);
        /* This is the only point at which it is reliable to read
         * the ID-code for a fast ESP chip variants.
         */
                break;
        }
  
+       /* Reload the configuration registers */
+       esp_write8(esp->cfact, ESP_CFACT);
+       esp->prev_stp = 0;
+       esp_write8(esp->prev_stp, ESP_STP);
+       esp->prev_soff = 0;
+       esp_write8(esp->prev_soff, ESP_SOFF);
+       esp_write8(esp->neg_defp, ESP_TIMEO);
        /* Eat any bitrot in the chip */
        esp_read8(ESP_INTRPT);
        udelay(100);
@@@ -2359,24 -2361,6 +2361,24 @@@ void scsi_esp_unregister(struct esp *es
  }
  EXPORT_SYMBOL(scsi_esp_unregister);
  
 +static int esp_target_alloc(struct scsi_target *starget)
 +{
 +      struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
 +      struct esp_target_data *tp = &esp->target[starget->id];
 +
 +      tp->starget = starget;
 +
 +      return 0;
 +}
 +
 +static void esp_target_destroy(struct scsi_target *starget)
 +{
 +      struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
 +      struct esp_target_data *tp = &esp->target[starget->id];
 +
 +      tp->starget = NULL;
 +}
 +
  static int esp_slave_alloc(struct scsi_device *dev)
  {
        struct esp *esp = shost_priv(dev->host);
                return -ENOMEM;
        dev->hostdata = lp;
  
 -      tp->starget = dev->sdev_target;
 -
        spi_min_period(tp->starget) = esp->min_period;
        spi_max_offset(tp->starget) = 15;
  
@@@ -2624,8 -2610,6 +2626,8 @@@ struct scsi_host_template scsi_esp_temp
        .name                   = "esp",
        .info                   = esp_info,
        .queuecommand           = esp_queuecommand,
 +      .target_alloc           = esp_target_alloc,
 +      .target_destroy         = esp_target_destroy,
        .slave_alloc            = esp_slave_alloc,
        .slave_configure        = esp_slave_configure,
        .slave_destroy          = esp_slave_destroy,
diff --combined drivers/scsi/hosts.c
index c6457bfc8a49039b8c7e6e187945905c6d71f706,497ca68d1ffcadd7f42ad58aac04d5ed886f31eb..35cd892dce04f899336a49c21228fe36984b5155
@@@ -290,7 -290,7 +290,7 @@@ static void scsi_host_dev_release(struc
        kfree(shost);
  }
  
- struct device_type scsi_host_type = {
+ static struct device_type scsi_host_type = {
        .name =         "scsi_host",
        .release =      scsi_host_dev_release,
  };
@@@ -456,10 -456,6 +456,10 @@@ static int __scsi_host_match(struct dev
   *
   * Return value:
   *    A pointer to located Scsi_Host or NULL.
 + *
 + *    The caller must do a scsi_host_put() to drop the reference
 + *    that scsi_host_get() took. The put_device() below dropped
 + *    the reference from class_find_device().
   **/
  struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
  {
        struct Scsi_Host *shost = ERR_PTR(-ENXIO);
  
        cdev = class_find_device(&shost_class, &hostnum, __scsi_host_match);
 -      if (cdev)
 +      if (cdev) {
                shost = scsi_host_get(class_to_shost(cdev));
 -
 +              put_device(cdev);
 +      }
        return shost;
  }
  EXPORT_SYMBOL(scsi_host_lookup);
diff --combined drivers/scsi/scsi_lib.c
index cbf55d59a54ce4f289c4aeb28948df583aaf445d,0451903452e6d950b87fa813855b49ca2d01db4c..88d1b5f44e59f2847bfca483a035b686e57de051
@@@ -65,7 -65,7 +65,7 @@@ static struct scsi_host_sg_pool scsi_sg
  };
  #undef SP
  
- static struct kmem_cache *scsi_bidi_sdb_cache;
+ static struct kmem_cache *scsi_sdb_cache;
  
  static void scsi_run_queue(struct request_queue *q);
  
@@@ -207,15 -207,6 +207,15 @@@ int scsi_execute(struct scsi_device *sd
         */
        blk_execute_rq(req->q, NULL, req, 1);
  
 +      /*
 +       * Some devices (USB mass-storage in particular) may transfer
 +       * garbage data together with a residue indicating that the data
 +       * is invalid.  Prevent the garbage from being misinterpreted
 +       * and prevent security leaks by zeroing out the excess data.
 +       */
 +      if (unlikely(req->data_len > 0 && req->data_len <= bufflen))
 +              memset(buffer + (bufflen - req->data_len), 0, req->data_len);
 +
        ret = req->errors;
   out:
        blk_put_request(req);
@@@ -784,7 -775,7 +784,7 @@@ void scsi_release_buffers(struct scsi_c
                struct scsi_data_buffer *bidi_sdb =
                        cmd->request->next_rq->special;
                scsi_free_sgtable(bidi_sdb);
-               kmem_cache_free(scsi_bidi_sdb_cache, bidi_sdb);
+               kmem_cache_free(scsi_sdb_cache, bidi_sdb);
                cmd->request->next_rq->special = NULL;
        }
  }
@@@ -1059,7 -1050,7 +1059,7 @@@ int scsi_init_io(struct scsi_cmnd *cmd
  
        if (blk_bidi_rq(cmd->request)) {
                struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc(
-                       scsi_bidi_sdb_cache, GFP_ATOMIC);
+                       scsi_sdb_cache, GFP_ATOMIC);
                if (!bidi_sdb) {
                        error = BLKPREP_DEFER;
                        goto err_exit;
@@@ -1169,6 -1160,14 +1169,14 @@@ int scsi_setup_fs_cmnd(struct scsi_devi
  
        if (ret != BLKPREP_OK)
                return ret;
+       if (unlikely(sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh
+                        && sdev->scsi_dh_data->scsi_dh->prep_fn)) {
+               ret = sdev->scsi_dh_data->scsi_dh->prep_fn(sdev, req);
+               if (ret != BLKPREP_OK)
+                       return ret;
+       }
        /*
         * Filesystem requests must transfer data.
         */
@@@ -1329,7 -1328,6 +1337,6 @@@ static inline int scsi_host_queue_ready
                                printk("scsi%d unblocking host at zero depth\n",
                                        shost->host_no));
                } else {
-                       blk_plug_device(q);
                        return 0;
                }
        }
@@@ -1693,11 -1691,11 +1700,11 @@@ int __init scsi_init_queue(void
                return -ENOMEM;
        }
  
-       scsi_bidi_sdb_cache = kmem_cache_create("scsi_bidi_sdb",
-                                       sizeof(struct scsi_data_buffer),
-                                       0, 0, NULL);
-       if (!scsi_bidi_sdb_cache) {
-               printk(KERN_ERR "SCSI: can't init scsi bidi sdb cache\n");
+       scsi_sdb_cache = kmem_cache_create("scsi_data_buffer",
+                                          sizeof(struct scsi_data_buffer),
+                                          0, 0, NULL);
+       if (!scsi_sdb_cache) {
+               printk(KERN_ERR "SCSI: can't init scsi sdb cache\n");
                goto cleanup_io_context;
        }
  
                if (!sgp->slab) {
                        printk(KERN_ERR "SCSI: can't init sg slab %s\n",
                                        sgp->name);
-                       goto cleanup_bidi_sdb;
+                       goto cleanup_sdb;
                }
  
                sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE,
                if (!sgp->pool) {
                        printk(KERN_ERR "SCSI: can't init sg mempool %s\n",
                                        sgp->name);
-                       goto cleanup_bidi_sdb;
+                       goto cleanup_sdb;
                }
        }
  
        return 0;
  
- cleanup_bidi_sdb:
+ cleanup_sdb:
        for (i = 0; i < SG_MEMPOOL_NR; i++) {
                struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
                if (sgp->pool)
                if (sgp->slab)
                        kmem_cache_destroy(sgp->slab);
        }
-       kmem_cache_destroy(scsi_bidi_sdb_cache);
+       kmem_cache_destroy(scsi_sdb_cache);
  cleanup_io_context:
        kmem_cache_destroy(scsi_io_context_cache);
  
@@@ -1744,7 -1742,7 +1751,7 @@@ void scsi_exit_queue(void
        int i;
  
        kmem_cache_destroy(scsi_io_context_cache);
-       kmem_cache_destroy(scsi_bidi_sdb_cache);
+       kmem_cache_destroy(scsi_sdb_cache);
  
        for (i = 0; i < SG_MEMPOOL_NR; i++) {
                struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
diff --combined drivers/scsi/sd.c
index d53312c4254708116a01f9e6552e3b210d809d7c,71069d952dc76f8510ff6cf9e40bf8e422c63427..0c63947d8a9d8fce2b4fa6240d9847036289f3b2
@@@ -58,8 -58,8 +58,8 @@@
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_ioctl.h>
  #include <scsi/scsicam.h>
- #include <scsi/sd.h>
  
+ #include "sd.h"
  #include "scsi_logging.h"
  
  MODULE_AUTHOR("Eric Youngdale");
@@@ -295,11 -295,6 +295,6 @@@ static int sd_major(int major_idx
        }
  }
  
- static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
- {
-       return container_of(disk->private_data, struct scsi_disk, driver);
- }
  static struct scsi_disk *__scsi_disk_get(struct gendisk *disk)
  {
        struct scsi_disk *sdkp = NULL;
@@@ -1124,8 -1119,6 +1119,8 @@@ sd_spinup_disk(struct scsi_disk *sdkp
                                cmd[1] = 1;     /* Return immediately */
                                memset((void *) &cmd[2], 0, 8);
                                cmd[4] = 1;     /* Start spin cycle */
 +                              if (sdkp->device->start_stop_pwr_cond)
 +                                      cmd[4] |= 1 << 4;
                                scsi_execute_req(sdkp->device, cmd, DMA_NONE,
                                                 NULL, 0, &sshdr,
                                                 SD_TIMEOUT, SD_MAX_RETRIES);
@@@ -1792,9 -1785,6 +1787,9 @@@ static int sd_start_stop_device(struct 
        if (start)
                cmd[4] |= 1;    /* START */
  
 +      if (sdp->start_stop_pwr_cond)
 +              cmd[4] |= start ? 1 << 4 : 3 << 4;      /* Active or Standby */
 +
        if (!scsi_device_online(sdp))
                return -ENODEV;
  
diff --combined drivers/scsi/sg.c
index fccd2e88d6000292d8494f1d4b1ccd688497958f,2010fa039cfee678a32e4dd0c387dc98abc501b7..d3b8ebb8377639c92e8e44503aa828554734c055
@@@ -49,7 -49,6 +49,7 @@@ static int sg_version_num = 30534;    /* 
  #include <linux/delay.h>
  #include <linux/scatterlist.h>
  #include <linux/blktrace_api.h>
 +#include <linux/smp_lock.h>
  
  #include "scsi.h"
  #include <scsi/scsi_dbg.h>
@@@ -183,9 -182,8 +183,9 @@@ static int sg_build_sgat(Sg_scatter_hol
                         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, const char __user *buf, size_t count,
 -                          int blocking, int read_only, Sg_request ** o_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);
  static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
                           unsigned char *cmnd, int timeout, int blocking);
  static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
@@@ -206,6 -204,7 +206,6 @@@ static Sg_request *sg_get_rq_mark(Sg_f
  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 int sg_allow_access(unsigned char opcode, char dev_type);
  static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
  static Sg_device *sg_get_dev(int dev);
  #ifdef CONFIG_SCSI_PROC_FS
@@@ -228,26 -227,19 +228,26 @@@ sg_open(struct inode *inode, struct fil
        int res;
        int retval;
  
 +      lock_kernel();
        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))
 +      if ((!sdp) || (!sdp->device)) {
 +              unlock_kernel();
                return -ENXIO;
 -      if (sdp->detached)
 +      }
 +      if (sdp->detached) {
 +              unlock_kernel();
                return -ENODEV;
 +      }
  
        /* 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)
 +      if (retval) {
 +              unlock_kernel();
                return retval;
 +      }
  
        if (!((flags & O_NONBLOCK) ||
              scsi_block_when_processing_errors(sdp->device))) {
                retval = -ENOMEM;
                goto error_out;
        }
 +      unlock_kernel();
        return 0;
  
        error_out:
        scsi_device_put(sdp->device);
 +      unlock_kernel();
        return retval;
  }
  
@@@ -554,7 -544,7 +554,7 @@@ 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, buf, count, blocking, 0, NULL);
 +              return sg_new_write(sfp, filp, buf, count, blocking, 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, const char __user *buf, size_t count,
 -           int blocking, int read_only, Sg_request ** o_srp)
 +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 k;
        Sg_request *srp;
                sg_remove_request(sfp, srp);
                return -EFAULT;
        }
 -      if (read_only &&
 -          (!sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
 +      if (read_only && !blk_verify_command(file, cmnd)) {
                sg_remove_request(sfp, srp);
                return -EPERM;
        }
@@@ -809,7 -799,7 +809,7 @@@ sg_ioctl(struct inode *inode, struct fi
                        if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
                                return -EFAULT;
                        result =
 -                          sg_new_write(sfp, p, SZ_SG_IO_HDR,
 +                          sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
                                         blocking, read_only, &srp);
                        if (result < 0)
                                return result;
                case SG_SCSI_RESET_DEVICE:
                        val = SCSI_TRY_RESET_DEVICE;
                        break;
+               case SG_SCSI_RESET_TARGET:
+                       val = SCSI_TRY_RESET_TARGET;
+                       break;
                case SG_SCSI_RESET_BUS:
                        val = SCSI_TRY_RESET_BUS;
                        break;
  
                        if (copy_from_user(&opcode, siocp->data, 1))
                                return -EFAULT;
 -                      if (!sg_allow_access(opcode, sdp->device->type))
 +                      if (!blk_verify_command(filp, &opcode))
                                return -EPERM;
                }
                return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p);
@@@ -2512,6 -2505,30 +2515,6 @@@ sg_page_free(struct page *page, int siz
        __free_pages(page, order);
  }
  
 -#ifndef MAINTENANCE_IN_CMD
 -#define MAINTENANCE_IN_CMD 0xa3
 -#endif
 -
 -static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE,
 -      INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
 -      READ_16, MODE_SENSE, MODE_SENSE_10, LOG_SENSE, REPORT_LUNS,
 -      SERVICE_ACTION_IN, RECEIVE_DIAGNOSTIC, READ_LONG, MAINTENANCE_IN_CMD
 -};
 -
 -static int
 -sg_allow_access(unsigned char opcode, char dev_type)
 -{
 -      int k;
 -
 -      if (TYPE_SCANNER == dev_type)   /* TYPE_ROM maybe burner */
 -              return 1;
 -      for (k = 0; k < sizeof (allow_ops); ++k) {
 -              if (opcode == allow_ops[k])
 -                      return 1;
 -      }
 -      return 0;
 -}
 -
  #ifdef CONFIG_SCSI_PROC_FS
  static int
  sg_idr_max_id(int id, void *p, void *data)
index 00b78763a1bfa56abf761855a2529f67825c77b9,06b979f105b790e7988ed99b54583ef575db32ed..6467f78b191fdf3334d714341c01c78044871175
@@@ -134,7 -134,6 +134,7 @@@ struct scsi_device 
        unsigned no_start_on_add:1;     /* do not issue start on add */
        unsigned allow_restart:1; /* issue START_UNIT in error handler */
        unsigned manage_start_stop:1;   /* Let HLD (sd) manage start/stop */
 +      unsigned start_stop_pwr_cond:1; /* Set power cond. in START_STOP_UNIT */
        unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
        unsigned select_no_atn:1;
        unsigned fix_capacity:1;        /* READ_CAPACITY is too high by 1 */
  
        struct execute_work     ew; /* used to get process context on put */
  
+       struct scsi_dh_data     *scsi_dh_data;
        enum scsi_device_state sdev_state;
        unsigned long           sdev_data[0];
  } __attribute__((aligned(sizeof(unsigned long))));
+ struct scsi_device_handler {
+       /* Used by the infrastructure */
+       struct list_head list; /* list of scsi_device_handlers */
+       struct notifier_block nb;
+       /* Filled by the hardware handler */
+       struct module *module;
+       const char *name;
+       int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
+       int (*activate)(struct scsi_device *);
+       int (*prep_fn)(struct scsi_device *, struct request *);
+ };
+ struct scsi_dh_data {
+       struct scsi_device_handler *scsi_dh;
+       char buf[0];
+ };
  #define       to_scsi_device(d)       \
        container_of(d, struct scsi_device, sdev_gendev)
  #define       class_to_sdev(d)        \
@@@ -231,7 -250,9 +251,9 @@@ extern struct scsi_device *__scsi_add_d
                uint, uint, uint, void *hostdata);
  extern int scsi_add_device(struct Scsi_Host *host, uint channel,
                           uint target, uint lun);
+ extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh);
  extern void scsi_remove_device(struct scsi_device *);
+ extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
  
  extern int scsi_device_get(struct scsi_device *);
  extern void scsi_device_put(struct scsi_device *);
diff --combined lib/Makefile
index 4b836a53c08f1dcf84b060c3480f6a9155c3960f,237a8298f8cb7bbeee31105b25602f099950a977..2c62a9c06fbe5adf638ec304dda3d13546fdb036
@@@ -8,15 -8,6 +8,15 @@@ lib-y := ctype.o string.o vsprintf.o cm
         sha1.o irq_regs.o reciprocal_div.o argv_split.o \
         proportions.o prio_heap.o ratelimit.o
  
 +ifdef CONFIG_FTRACE
 +# Do not profile string.o, since it may be used in early boot or vdso
 +CFLAGS_REMOVE_string.o = -pg
 +# Also do not profile any debug utilities
 +CFLAGS_REMOVE_spinlock_debug.o = -pg
 +CFLAGS_REMOVE_list_debug.o = -pg
 +CFLAGS_REMOVE_debugobjects.o = -pg
 +endif
 +
  lib-$(CONFIG_MMU) += ioremap.o
  lib-$(CONFIG_SMP) += cpumask.o
  
@@@ -54,6 -45,7 +54,7 @@@ endi
  obj-$(CONFIG_BITREVERSE) += bitrev.o
  obj-$(CONFIG_CRC_CCITT)       += crc-ccitt.o
  obj-$(CONFIG_CRC16)   += crc16.o
+ obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o
  obj-$(CONFIG_CRC_ITU_T)       += crc-itu-t.o
  obj-$(CONFIG_CRC32)   += crc32.o
  obj-$(CONFIG_CRC7)    += crc7.o