IB: Add CQ comp_vector support
[safe/jmp/linux-2.6] / drivers / infiniband / ulp / srp / ib_srp.c
index f1401e1..39bf057 100644 (file)
@@ -77,6 +77,14 @@ MODULE_PARM_DESC(topspin_workarounds,
 
 static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
 
+static int mellanox_workarounds = 1;
+
+module_param(mellanox_workarounds, int, 0444);
+MODULE_PARM_DESC(mellanox_workarounds,
+                "Enable workarounds for Mellanox SRP target bugs if != 0");
+
+static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 };
+
 static void srp_add_one(struct ib_device *device);
 static void srp_remove_one(struct ib_device *device);
 static void srp_completion(struct ib_cq *cq, void *target_ptr);
@@ -88,6 +96,8 @@ static struct ib_client srp_client = {
        .remove = srp_remove_one
 };
 
+static struct ib_sa_client srp_sa_client;
+
 static inline struct srp_target_port *host_to_target(struct Scsi_Host *host)
 {
        return (struct srp_target_port *) host->hostdata;
@@ -112,9 +122,8 @@ static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size,
        if (!iu->buf)
                goto out_free_iu;
 
-       iu->dma = dma_map_single(host->dev->dev->dma_device,
-                                iu->buf, size, direction);
-       if (dma_mapping_error(iu->dma))
+       iu->dma = ib_dma_map_single(host->dev->dev, iu->buf, size, direction);
+       if (ib_dma_mapping_error(host->dev->dev, iu->dma))
                goto out_free_buf;
 
        iu->size      = size;
@@ -135,8 +144,7 @@ static void srp_free_iu(struct srp_host *host, struct srp_iu *iu)
        if (!iu)
                return;
 
-       dma_unmap_single(host->dev->dev->dma_device,
-                        iu->dma, iu->size, iu->direction);
+       ib_dma_unmap_single(host->dev->dev, iu->dma, iu->size, iu->direction);
        kfree(iu->buf);
        kfree(iu);
 }
@@ -189,7 +197,7 @@ static int srp_create_target_ib(struct srp_target_port *target)
                return -ENOMEM;
 
        target->cq = ib_create_cq(target->srp_host->dev->dev, srp_completion,
-                                 NULL, target, SRP_CQ_SIZE);
+                                 NULL, target, SRP_CQ_SIZE, 0);
        if (IS_ERR(target->cq)) {
                ret = PTR_ERR(target->cq);
                goto out;
@@ -259,7 +267,8 @@ static int srp_lookup_path(struct srp_target_port *target)
 
        init_completion(&target->done);
 
-       target->path_query_id = ib_sa_path_rec_get(target->srp_host->dev->dev,
+       target->path_query_id = ib_sa_path_rec_get(&srp_sa_client,
+                                                  target->srp_host->dev->dev,
                                                   target->srp_host->port,
                                                   &target->path,
                                                   IB_SA_PATH_REC_DGID          |
@@ -321,21 +330,44 @@ static int srp_send_req(struct srp_target_port *target)
        req->priv.req_it_iu_len = cpu_to_be32(srp_max_iu_len);
        req->priv.req_buf_fmt   = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
                                              SRP_BUF_FORMAT_INDIRECT);
-       memcpy(req->priv.initiator_port_id, target->srp_host->initiator_port_id, 16);
+       /*
+        * In the published SRP specification (draft rev. 16a), the
+        * port identifier format is 8 bytes of ID extension followed
+        * by 8 bytes of GUID.  Older drafts put the two halves in the
+        * opposite order, so that the GUID comes first.
+        *
+        * Targets conforming to these obsolete drafts can be
+        * recognized by the I/O Class they report.
+        */
+       if (target->io_class == SRP_REV10_IB_IO_CLASS) {
+               memcpy(req->priv.initiator_port_id,
+                      &target->path.sgid.global.interface_id, 8);
+               memcpy(req->priv.initiator_port_id + 8,
+                      &target->initiator_ext, 8);
+               memcpy(req->priv.target_port_id,     &target->ioc_guid, 8);
+               memcpy(req->priv.target_port_id + 8, &target->id_ext, 8);
+       } else {
+               memcpy(req->priv.initiator_port_id,
+                      &target->initiator_ext, 8);
+               memcpy(req->priv.initiator_port_id + 8,
+                      &target->path.sgid.global.interface_id, 8);
+               memcpy(req->priv.target_port_id,     &target->id_ext, 8);
+               memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8);
+       }
+
        /*
         * Topspin/Cisco SRP targets will reject our login unless we
-        * zero out the first 8 bytes of our initiator port ID.  The
-        * second 8 bytes must be our local node GUID, but we always
-        * use that anyway.
+        * zero out the first 8 bytes of our initiator port ID and set
+        * the second 8 bytes to the local node GUID.
         */
        if (topspin_workarounds && !memcmp(&target->ioc_guid, topspin_oui, 3)) {
                printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround "
                       "activated for target GUID %016llx\n",
                       (unsigned long long) be64_to_cpu(target->ioc_guid));
                memset(req->priv.initiator_port_id, 0, 8);
+               memcpy(req->priv.initiator_port_id + 8,
+                      &target->srp_host->dev->dev->node_guid, 8);
        }
-       memcpy(req->priv.target_port_id,     &target->id_ext, 8);
-       memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8);
 
        status = ib_send_cm_req(target->cm_id, &req->param);
 
@@ -356,9 +388,10 @@ static void srp_disconnect_target(struct srp_target_port *target)
        wait_for_completion(&target->done);
 }
 
-static void srp_remove_work(void *target_ptr)
+static void srp_remove_work(struct work_struct *work)
 {
-       struct srp_target_port *target = target_ptr;
+       struct srp_target_port *target =
+               container_of(work, struct srp_target_port, work);
 
        spin_lock_irq(target->scsi_host->host_lock);
        if (target->state != SRP_TARGET_DEAD) {
@@ -447,18 +480,30 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
                scat  = &req->fake_sg;
        }
 
-       dma_unmap_sg(target->srp_host->dev->dev->dma_device, scat, nents,
-                    scmnd->sc_data_direction);
+       ib_dma_unmap_sg(target->srp_host->dev->dev, scat, nents,
+                       scmnd->sc_data_direction);
+}
+
+static void srp_remove_req(struct srp_target_port *target, struct srp_request *req)
+{
+       srp_unmap_data(req->scmnd, target, req);
+       list_move_tail(&req->list, &target->free_reqs);
+}
+
+static void srp_reset_req(struct srp_target_port *target, struct srp_request *req)
+{
+       req->scmnd->result = DID_RESET << 16;
+       req->scmnd->scsi_done(req->scmnd);
+       srp_remove_req(target, req);
 }
 
 static int srp_reconnect_target(struct srp_target_port *target)
 {
        struct ib_cm_id *new_cm_id;
        struct ib_qp_attr qp_attr;
-       struct srp_request *req;
+       struct srp_request *req, *tmp;
        struct ib_wc wc;
        int ret;
-       int i;
 
        spin_lock_irq(target->scsi_host->host_lock);
        if (target->state != SRP_TARGET_LIVE) {
@@ -494,20 +539,16 @@ static int srp_reconnect_target(struct srp_target_port *target)
        while (ib_poll_cq(target->cq, 1, &wc) > 0)
                ; /* nothing */
 
-       list_for_each_entry(req, &target->req_queue, list) {
-               req->scmnd->result = DID_RESET << 16;
-               req->scmnd->scsi_done(req->scmnd);
-               srp_unmap_data(req->scmnd, target, req);
-       }
+       spin_lock_irq(target->scsi_host->host_lock);
+       list_for_each_entry_safe(req, tmp, &target->req_queue, list)
+               srp_reset_req(target, req);
+       spin_unlock_irq(target->scsi_host->host_lock);
 
        target->rx_head  = 0;
        target->tx_head  = 0;
        target->tx_tail  = 0;
-       INIT_LIST_HEAD(&target->free_reqs);
-       INIT_LIST_HEAD(&target->req_queue);
-       for (i = 0; i < SRP_SQ_SIZE; ++i)
-               list_add_tail(&target->req_ring[i].list, &target->free_reqs);
 
+       target->qp_in_error = 0;
        ret = srp_connect_target(target);
        if (ret)
                goto err;
@@ -534,7 +575,7 @@ err:
        spin_lock_irq(target->scsi_host->host_lock);
        if (target->state == SRP_TARGET_CONNECTING) {
                target->state = SRP_TARGET_DEAD;
-               INIT_WORK(&target->work, srp_remove_work, target);
+               INIT_WORK(&target->work, srp_remove_work);
                schedule_work(&target->work);
        }
        spin_unlock_irq(target->scsi_host->host_lock);
@@ -542,7 +583,7 @@ err:
        return ret;
 }
 
-static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
+static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
                       int sg_cnt, struct srp_request *req,
                       struct srp_direct_buf *buf)
 {
@@ -552,19 +593,27 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
        int page_cnt;
        int i, j;
        int ret;
+       struct srp_device *dev = target->srp_host->dev;
+       struct ib_device *ibdev = dev->dev;
 
        if (!dev->fmr_pool)
                return -ENODEV;
 
+       if ((ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask) &&
+           mellanox_workarounds && !memcmp(&target->ioc_guid, mellanox_oui, 3))
+               return -EINVAL;
+
        len = page_cnt = 0;
        for (i = 0; i < sg_cnt; ++i) {
-               if (sg_dma_address(&scat[i]) & ~dev->fmr_page_mask) {
+               unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+
+               if (ib_sg_dma_address(ibdev, &scat[i]) & ~dev->fmr_page_mask) {
                        if (i > 0)
                                return -EINVAL;
                        else
                                ++page_cnt;
                }
-               if ((sg_dma_address(&scat[i]) + sg_dma_len(&scat[i])) &
+               if ((ib_sg_dma_address(ibdev, &scat[i]) + dma_len) &
                    ~dev->fmr_page_mask) {
                        if (i < sg_cnt - 1)
                                return -EINVAL;
@@ -572,7 +621,7 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
                                ++page_cnt;
                }
 
-               len += sg_dma_len(&scat[i]);
+               len += dma_len;
        }
 
        page_cnt += len >> dev->fmr_page_shift;
@@ -584,19 +633,25 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
                return -ENOMEM;
 
        page_cnt = 0;
-       for (i = 0; i < sg_cnt; ++i)
-               for (j = 0; j < sg_dma_len(&scat[i]); j += dev->fmr_page_size)
+       for (i = 0; i < sg_cnt; ++i) {
+               unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+
+               for (j = 0; j < dma_len; j += dev->fmr_page_size)
                        dma_pages[page_cnt++] =
-                               (sg_dma_address(&scat[i]) & dev->fmr_page_mask) + j;
+                               (ib_sg_dma_address(ibdev, &scat[i]) &
+                                dev->fmr_page_mask) + j;
+       }
 
        req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool,
-                                       dma_pages, page_cnt, &io_addr);
+                                       dma_pages, page_cnt, io_addr);
        if (IS_ERR(req->fmr)) {
                ret = PTR_ERR(req->fmr);
+               req->fmr = NULL;
                goto out;
        }
 
-       buf->va  = cpu_to_be64(sg_dma_address(&scat[0]) & ~dev->fmr_page_mask);
+       buf->va  = cpu_to_be64(ib_sg_dma_address(ibdev, &scat[0]) &
+                              ~dev->fmr_page_mask);
        buf->key = cpu_to_be32(req->fmr->fmr->rkey);
        buf->len = cpu_to_be32(len);
 
@@ -615,6 +670,8 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
        struct srp_cmd *cmd = req->cmd->buf;
        int len, nents, count;
        u8 fmt = SRP_DATA_DESC_DIRECT;
+       struct srp_device *dev;
+       struct ib_device *ibdev;
 
        if (!scmnd->request_buffer || scmnd->sc_data_direction == DMA_NONE)
                return sizeof (struct srp_cmd);
@@ -639,8 +696,10 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
                sg_init_one(scat, scmnd->request_buffer, scmnd->request_bufflen);
        }
 
-       count = dma_map_sg(target->srp_host->dev->dev->dma_device,
-                          scat, nents, scmnd->sc_data_direction);
+       dev = target->srp_host->dev;
+       ibdev = dev->dev;
+
+       count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction);
 
        fmt = SRP_DATA_DESC_DIRECT;
        len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf);
@@ -654,10 +713,10 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
                 */
                struct srp_direct_buf *buf = (void *) cmd->add_data;
 
-               buf->va  = cpu_to_be64(sg_dma_address(scat));
-               buf->key = cpu_to_be32(target->srp_host->dev->mr->rkey);
-               buf->len = cpu_to_be32(sg_dma_len(scat));
-       } else if (srp_map_fmr(target->srp_host->dev, scat, count, req,
+               buf->va  = cpu_to_be64(ib_sg_dma_address(ibdev, scat));
+               buf->key = cpu_to_be32(dev->mr->rkey);
+               buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat));
+       } else if (srp_map_fmr(target, scat, count, req,
                               (void *) cmd->add_data)) {
                /*
                 * FMR mapping failed, and the scatterlist has more
@@ -674,13 +733,14 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
                        count * sizeof (struct srp_direct_buf);
 
                for (i = 0; i < count; ++i) {
+                       unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+
                        buf->desc_list[i].va  =
-                               cpu_to_be64(sg_dma_address(&scat[i]));
+                               cpu_to_be64(ib_sg_dma_address(ibdev, &scat[i]));
                        buf->desc_list[i].key =
-                               cpu_to_be32(target->srp_host->dev->mr->rkey);
-                       buf->desc_list[i].len =
-                               cpu_to_be32(sg_dma_len(&scat[i]));
-                       datalen += sg_dma_len(&scat[i]);
+                               cpu_to_be32(dev->mr->rkey);
+                       buf->desc_list[i].len = cpu_to_be32(dma_len);
+                       datalen += dma_len;
                }
 
                if (scmnd->sc_data_direction == DMA_TO_DEVICE)
@@ -706,12 +766,6 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
        return len;
 }
 
-static void srp_remove_req(struct srp_target_port *target, struct srp_request *req)
-{
-       srp_unmap_data(req->scmnd, target, req);
-       list_move_tail(&req->list, &target->free_reqs);
-}
-
 static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
 {
        struct srp_request *req;
@@ -764,22 +818,17 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
        spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
 }
 
-static void srp_reconnect_work(void *target_ptr)
-{
-       struct srp_target_port *target = target_ptr;
-
-       srp_reconnect_target(target);
-}
-
 static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
 {
+       struct ib_device *dev;
        struct srp_iu *iu;
        u8 opcode;
 
        iu = target->rx_ring[wc->wr_id & ~SRP_OP_RECV];
 
-       dma_sync_single_for_cpu(target->srp_host->dev->dev->dma_device, iu->dma,
-                               target->max_ti_iu_len, DMA_FROM_DEVICE);
+       dev = target->srp_host->dev->dev;
+       ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len,
+                                  DMA_FROM_DEVICE);
 
        opcode = *(u8 *) iu->buf;
 
@@ -815,15 +864,14 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
                break;
        }
 
-       dma_sync_single_for_device(target->srp_host->dev->dev->dma_device, iu->dma,
-                                  target->max_ti_iu_len, DMA_FROM_DEVICE);
+       ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len,
+                                     DMA_FROM_DEVICE);
 }
 
 static void srp_completion(struct ib_cq *cq, void *target_ptr)
 {
        struct srp_target_port *target = target_ptr;
        struct ib_wc wc;
-       unsigned long flags;
 
        ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
        while (ib_poll_cq(cq, 1, &wc) > 0) {
@@ -831,10 +879,7 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
                        printk(KERN_ERR PFX "failed %s status %d\n",
                               wc.wr_id & SRP_OP_RECV ? "receive" : "send",
                               wc.status);
-                       spin_lock_irqsave(target->scsi_host->host_lock, flags);
-                       if (target->state == SRP_TARGET_LIVE)
-                               schedule_work(&target->work);
-                       spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
+                       target->qp_in_error = 1;
                        break;
                }
 
@@ -939,6 +984,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
        struct srp_request *req;
        struct srp_iu *iu;
        struct srp_cmd *cmd;
+       struct ib_device *dev;
        int len;
 
        if (target->state == SRP_TARGET_CONNECTING)
@@ -955,8 +1001,9 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
        if (!iu)
                goto err;
 
-       dma_sync_single_for_cpu(target->srp_host->dev->dev->dma_device, iu->dma,
-                               srp_max_iu_len, DMA_TO_DEVICE);
+       dev = target->srp_host->dev->dev;
+       ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len,
+                                  DMA_TO_DEVICE);
 
        req = list_entry(target->free_reqs.next, struct srp_request, list);
 
@@ -988,8 +1035,8 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
                goto err_unmap;
        }
 
-       dma_sync_single_for_device(target->srp_host->dev->dev->dma_device, iu->dma,
-                                  srp_max_iu_len, DMA_TO_DEVICE);
+       ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len,
+                                     DMA_TO_DEVICE);
 
        if (__srp_post_send(target, iu, len)) {
                printk(KERN_ERR PFX "Send failed\n");
@@ -1147,9 +1194,11 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
                        break;
                }
 
-               target->status = srp_alloc_iu_bufs(target);
-               if (target->status)
-                       break;
+               if (!target->rx_ring[0]) {
+                       target->status = srp_alloc_iu_bufs(target);
+                       if (target->status)
+                               break;
+               }
 
                qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL);
                if (!qp_attr) {
@@ -1290,6 +1339,8 @@ static int srp_abort(struct scsi_cmnd *scmnd)
 
        printk(KERN_ERR "SRP abort called\n");
 
+       if (target->qp_in_error)
+               return FAILED;
        if (srp_find_req(target, scmnd, &req))
                return FAILED;
        if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
@@ -1318,6 +1369,8 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
 
        printk(KERN_ERR "SRP reset_device called\n");
 
+       if (target->qp_in_error)
+               return FAILED;
        if (srp_find_req(target, scmnd, &req))
                return FAILED;
        if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
@@ -1328,11 +1381,8 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
        spin_lock_irq(target->scsi_host->host_lock);
 
        list_for_each_entry_safe(req, tmp, &target->req_queue, list)
-               if (req->scmnd->device == scmnd->device) {
-                       req->scmnd->result = DID_RESET << 16;
-                       req->scmnd->scsi_done(req->scmnd);
-                       srp_remove_req(target, req);
-               }
+               if (req->scmnd->device == scmnd->device)
+                       srp_reset_req(target, req);
 
        spin_unlock_irq(target->scsi_host->host_lock);
 
@@ -1418,6 +1468,25 @@ static ssize_t show_dgid(struct class_device *cdev, char *buf)
                       be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
 }
 
+static ssize_t show_orig_dgid(struct class_device *cdev, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+       if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_REMOVED)
+               return -ENODEV;
+
+       return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                      be16_to_cpu(target->orig_dgid[0]),
+                      be16_to_cpu(target->orig_dgid[1]),
+                      be16_to_cpu(target->orig_dgid[2]),
+                      be16_to_cpu(target->orig_dgid[3]),
+                      be16_to_cpu(target->orig_dgid[4]),
+                      be16_to_cpu(target->orig_dgid[5]),
+                      be16_to_cpu(target->orig_dgid[6]),
+                      be16_to_cpu(target->orig_dgid[7]));
+}
+
 static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf)
 {
        struct srp_target_port *target = host_to_target(class_to_shost(cdev));
@@ -1429,12 +1498,29 @@ static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf)
        return sprintf(buf, "%d\n", target->zero_req_lim);
 }
 
-static CLASS_DEVICE_ATTR(id_ext,       S_IRUGO, show_id_ext,           NULL);
-static CLASS_DEVICE_ATTR(ioc_guid,     S_IRUGO, show_ioc_guid,         NULL);
-static CLASS_DEVICE_ATTR(service_id,   S_IRUGO, show_service_id,       NULL);
-static CLASS_DEVICE_ATTR(pkey,         S_IRUGO, show_pkey,             NULL);
-static CLASS_DEVICE_ATTR(dgid,         S_IRUGO, show_dgid,             NULL);
-static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim,     NULL);
+static ssize_t show_local_ib_port(struct class_device *cdev, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+       return sprintf(buf, "%d\n", target->srp_host->port);
+}
+
+static ssize_t show_local_ib_device(struct class_device *cdev, char *buf)
+{
+       struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+       return sprintf(buf, "%s\n", target->srp_host->dev->dev->name);
+}
+
+static CLASS_DEVICE_ATTR(id_ext,         S_IRUGO, show_id_ext,          NULL);
+static CLASS_DEVICE_ATTR(ioc_guid,       S_IRUGO, show_ioc_guid,        NULL);
+static CLASS_DEVICE_ATTR(service_id,     S_IRUGO, show_service_id,      NULL);
+static CLASS_DEVICE_ATTR(pkey,           S_IRUGO, show_pkey,            NULL);
+static CLASS_DEVICE_ATTR(dgid,           S_IRUGO, show_dgid,            NULL);
+static CLASS_DEVICE_ATTR(orig_dgid,      S_IRUGO, show_orig_dgid,       NULL);
+static CLASS_DEVICE_ATTR(zero_req_lim,   S_IRUGO, show_zero_req_lim,    NULL);
+static CLASS_DEVICE_ATTR(local_ib_port,   S_IRUGO, show_local_ib_port,  NULL);
+static CLASS_DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
 
 static struct class_device_attribute *srp_host_attrs[] = {
        &class_device_attr_id_ext,
@@ -1442,13 +1528,17 @@ static struct class_device_attribute *srp_host_attrs[] = {
        &class_device_attr_service_id,
        &class_device_attr_pkey,
        &class_device_attr_dgid,
+       &class_device_attr_orig_dgid,
        &class_device_attr_zero_req_lim,
+       &class_device_attr_local_ib_port,
+       &class_device_attr_local_ib_device,
        NULL
 };
 
 static struct scsi_host_template srp_template = {
        .module                         = THIS_MODULE,
-       .name                           = DRV_NAME,
+       .name                           = "InfiniBand SRP initiator",
+       .proc_name                      = DRV_NAME,
        .info                           = srp_target_info,
        .queuecommand                   = srp_queuecommand,
        .eh_abort_handler               = srp_abort,
@@ -1511,6 +1601,8 @@ enum {
        SRP_OPT_SERVICE_ID      = 1 << 4,
        SRP_OPT_MAX_SECT        = 1 << 5,
        SRP_OPT_MAX_CMD_PER_LUN = 1 << 6,
+       SRP_OPT_IO_CLASS        = 1 << 7,
+       SRP_OPT_INITIATOR_EXT   = 1 << 8,
        SRP_OPT_ALL             = (SRP_OPT_ID_EXT       |
                                   SRP_OPT_IOC_GUID     |
                                   SRP_OPT_DGID         |
@@ -1526,6 +1618,8 @@ static match_table_t srp_opt_tokens = {
        { SRP_OPT_SERVICE_ID,           "service_id=%s"         },
        { SRP_OPT_MAX_SECT,             "max_sect=%d"           },
        { SRP_OPT_MAX_CMD_PER_LUN,      "max_cmd_per_lun=%d"    },
+       { SRP_OPT_IO_CLASS,             "io_class=%x"           },
+       { SRP_OPT_INITIATOR_EXT,        "initiator_ext=%s"      },
        { SRP_OPT_ERR,                  NULL                    }
 };
 
@@ -1555,18 +1649,30 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
                switch (token) {
                case SRP_OPT_ID_EXT:
                        p = match_strdup(args);
+                       if (!p) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
                        target->id_ext = cpu_to_be64(simple_strtoull(p, NULL, 16));
                        kfree(p);
                        break;
 
                case SRP_OPT_IOC_GUID:
                        p = match_strdup(args);
+                       if (!p) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
                        target->ioc_guid = cpu_to_be64(simple_strtoull(p, NULL, 16));
                        kfree(p);
                        break;
 
                case SRP_OPT_DGID:
                        p = match_strdup(args);
+                       if (!p) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
                        if (strlen(p) != 32) {
                                printk(KERN_WARNING PFX "bad dest GID parameter '%s'\n", p);
                                kfree(p);
@@ -1578,6 +1684,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
                                target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
                        }
                        kfree(p);
+                       memcpy(target->orig_dgid, target->path.dgid.raw, 16);
                        break;
 
                case SRP_OPT_PKEY:
@@ -1590,6 +1697,10 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
 
                case SRP_OPT_SERVICE_ID:
                        p = match_strdup(args);
+                       if (!p) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
                        target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16));
                        kfree(p);
                        break;
@@ -1610,6 +1721,31 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
                        target->scsi_host->cmd_per_lun = min(token, SRP_SQ_SIZE);
                        break;
 
+               case SRP_OPT_IO_CLASS:
+                       if (match_hex(args, &token)) {
+                               printk(KERN_WARNING PFX "bad  IO class parameter '%s' \n", p);
+                               goto out;
+                       }
+                       if (token != SRP_REV10_IB_IO_CLASS &&
+                           token != SRP_REV16A_IB_IO_CLASS) {
+                               printk(KERN_WARNING PFX "unknown IO class parameter value"
+                                      " %x specified (use %x or %x).\n",
+                                      token, SRP_REV10_IB_IO_CLASS, SRP_REV16A_IB_IO_CLASS);
+                               goto out;
+                       }
+                       target->io_class = token;
+                       break;
+
+               case SRP_OPT_INITIATOR_EXT:
+                       p = match_strdup(args);
+                       if (!p) {
+                               ret = -ENOMEM;
+                               goto out;
+                       }
+                       target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16));
+                       kfree(p);
+                       break;
+
                default:
                        printk(KERN_WARNING PFX "unknown parameter or missing value "
                               "'%s' in target creation request\n", p);
@@ -1647,16 +1783,15 @@ static ssize_t srp_create_target(struct class_device *class_dev,
        if (!target_host)
                return -ENOMEM;
 
-       target_host->max_lun = SRP_MAX_LUN;
+       target_host->max_lun     = SRP_MAX_LUN;
+       target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
 
        target = host_to_target(target_host);
-       memset(target, 0, sizeof *target);
 
+       target->io_class   = SRP_REV16A_IB_IO_CLASS;
        target->scsi_host  = target_host;
        target->srp_host   = host;
 
-       INIT_WORK(&target->work, srp_reconnect_work, target);
-
        INIT_LIST_HEAD(&target->free_reqs);
        INIT_LIST_HEAD(&target->req_queue);
        for (i = 0; i < SRP_SQ_SIZE; ++i) {
@@ -1695,6 +1830,7 @@ static ssize_t srp_create_target(struct class_device *class_dev,
                goto err_free;
        }
 
+       target->qp_in_error = 0;
        ret = srp_connect_target(target);
        if (ret) {
                printk(KERN_ERR PFX "Connection failed\n");
@@ -1758,9 +1894,6 @@ static struct srp_host *srp_add_port(struct srp_device *device, u8 port)
        host->dev  = device;
        host->port = port;
 
-       host->initiator_port_id[7] = port;
-       memcpy(host->initiator_port_id + 8, &device->dev->node_guid, 8);
-
        host->class_dev.class = &srp_class;
        host->class_dev.dev   = device->dev->dma_device;
        snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d",
@@ -1815,7 +1948,7 @@ static void srp_add_one(struct ib_device *device)
         */
        srp_dev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1);
        srp_dev->fmr_page_size  = 1 << srp_dev->fmr_page_shift;
-       srp_dev->fmr_page_mask  = ~((unsigned long) srp_dev->fmr_page_size - 1);
+       srp_dev->fmr_page_mask  = ~((u64) srp_dev->fmr_page_size - 1);
 
        INIT_LIST_HEAD(&srp_dev->dev_list);
 
@@ -1845,7 +1978,7 @@ static void srp_add_one(struct ib_device *device)
        if (IS_ERR(srp_dev->fmr_pool))
                srp_dev->fmr_pool = NULL;
 
-       if (device->node_type == IB_NODE_SWITCH) {
+       if (device->node_type == RDMA_NODE_IB_SWITCH) {
                s = 0;
                e = 0;
        } else {
@@ -1944,9 +2077,12 @@ static int __init srp_init_module(void)
                return ret;
        }
 
+       ib_sa_register_client(&srp_sa_client);
+
        ret = ib_register_client(&srp_client);
        if (ret) {
                printk(KERN_ERR PFX "couldn't register IB client\n");
+               ib_sa_unregister_client(&srp_sa_client);
                class_unregister(&srp_class);
                return ret;
        }
@@ -1957,6 +2093,7 @@ static int __init srp_init_module(void)
 static void __exit srp_cleanup_module(void)
 {
        ib_unregister_client(&srp_client);
+       ib_sa_unregister_client(&srp_sa_client);
        class_unregister(&srp_class);
 }