Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[pandora-kernel.git] / drivers / infiniband / ulp / srp / ib_srp.c
index 8e6b103..44b9e5b 100644 (file)
@@ -62,6 +62,13 @@ MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator "
                   "v" DRV_VERSION " (" DRV_RELDATE ")");
 MODULE_LICENSE("Dual BSD/GPL");
 
+static int srp_sg_tablesize = SRP_DEF_SG_TABLESIZE;
+static int srp_max_iu_len;
+
+module_param(srp_sg_tablesize, int, 0444);
+MODULE_PARM_DESC(srp_sg_tablesize,
+                "Max number of gather/scatter entries per I/O (default is 12)");
+
 static int topspin_workarounds = 1;
 
 module_param(topspin_workarounds, int, 0444);
@@ -70,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);
@@ -81,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;
@@ -252,7 +269,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          |
@@ -311,10 +329,32 @@ static int srp_send_req(struct srp_target_port *target)
 
        req->priv.opcode        = SRP_LOGIN_REQ;
        req->priv.tag           = 0;
-       req->priv.req_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
+       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->srp_host->initiator_port_id + 8, 8);
+               memcpy(req->priv.initiator_port_id + 8,
+                      target->srp_host->initiator_port_id, 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->srp_host->initiator_port_id, 16);
+               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
@@ -327,8 +367,6 @@ static int srp_send_req(struct srp_target_port *target)
                       (unsigned long long) be64_to_cpu(target->ioc_guid));
                memset(req->priv.initiator_port_id, 0, 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);
 
@@ -444,14 +482,26 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
                     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) {
@@ -487,19 +537,14 @@ 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);
 
        ret = srp_connect_target(target);
        if (ret)
@@ -535,7 +580,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)
 {
@@ -545,10 +590,15 @@ 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;
 
        if (!dev->fmr_pool)
                return -ENODEV;
 
+       if ((sg_dma_address(&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) {
@@ -583,9 +633,10 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
                                (sg_dma_address(&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;
        }
 
@@ -650,7 +701,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
                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,
+       } else if (srp_map_fmr(target, scat, count, req,
                               (void *) cmd->add_data)) {
                /*
                 * FMR mapping failed, and the scatterlist has more
@@ -699,12 +750,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;
@@ -757,13 +802,6 @@ 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 srp_iu *iu;
@@ -816,7 +854,6 @@ 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) {
@@ -824,10 +861,6 @@ 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);
                        break;
                }
 
@@ -887,12 +920,8 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target)
        if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
                return NULL;
 
-       if (unlikely(target->req_lim < 1)) {
-               if (printk_ratelimit())
-                       printk(KERN_DEBUG PFX "Target has req_lim %d\n",
-                              target->req_lim);
-               return NULL;
-       }
+       if (unlikely(target->req_lim < 1))
+               ++target->zero_req_lim;
 
        return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
 }
@@ -953,7 +982,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
                goto err;
 
        dma_sync_single_for_cpu(target->srp_host->dev->dev->dma_device, iu->dma,
-                               SRP_MAX_IU_LEN, DMA_TO_DEVICE);
+                               srp_max_iu_len, DMA_TO_DEVICE);
 
        req = list_entry(target->free_reqs.next, struct srp_request, list);
 
@@ -986,7 +1015,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
        }
 
        dma_sync_single_for_device(target->srp_host->dev->dev->dma_device, iu->dma,
-                                  SRP_MAX_IU_LEN, DMA_TO_DEVICE);
+                                  srp_max_iu_len, DMA_TO_DEVICE);
 
        if (__srp_post_send(target, iu, len)) {
                printk(KERN_ERR PFX "Send failed\n");
@@ -1018,7 +1047,7 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target)
 
        for (i = 0; i < SRP_SQ_SIZE + 1; ++i) {
                target->tx_ring[i] = srp_alloc_iu(target->srp_host,
-                                                 SRP_MAX_IU_LEN,
+                                                 srp_max_iu_len,
                                                  GFP_KERNEL, DMA_TO_DEVICE);
                if (!target->tx_ring[i])
                        goto err;
@@ -1189,11 +1218,10 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
                srp_cm_rej_handler(cm_id, event, target);
                break;
 
-       case IB_CM_MRA_RECEIVED:
-               printk(KERN_ERR PFX "MRA received\n");
-               break;
-
-       case IB_CM_DREP_RECEIVED:
+       case IB_CM_DREQ_RECEIVED:
+               printk(KERN_WARNING PFX "DREQ received - connection closed\n");
+               if (ib_send_cm_drep(cm_id, NULL, 0))
+                       printk(KERN_ERR PFX "Sending CM DREP failed\n");
                break;
 
        case IB_CM_TIMEWAIT_EXIT:
@@ -1203,6 +1231,11 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
                target->status = 0;
                break;
 
+       case IB_CM_MRA_RECEIVED:
+       case IB_CM_DREQ_ERROR:
+       case IB_CM_DREP_RECEIVED:
+               break;
+
        default:
                printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event);
                break;
@@ -1321,11 +1354,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);
 
@@ -1411,11 +1441,39 @@ static ssize_t show_dgid(struct class_device *cdev, char *buf)
                       be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
 }
 
-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 ssize_t show_zero_req_lim(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, "%d\n", target->zero_req_lim);
+}
+
+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(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,
@@ -1423,6 +1481,9 @@ static struct class_device_attribute *srp_host_attrs[] = {
        &class_device_attr_service_id,
        &class_device_attr_pkey,
        &class_device_attr_dgid,
+       &class_device_attr_zero_req_lim,
+       &class_device_attr_local_ib_port,
+       &class_device_attr_local_ib_device,
        NULL
 };
 
@@ -1436,7 +1497,6 @@ static struct scsi_host_template srp_template = {
        .eh_host_reset_handler          = srp_reset_host,
        .can_queue                      = SRP_SQ_SIZE,
        .this_id                        = -1,
-       .sg_tablesize                   = SRP_MAX_INDIRECT,
        .cmd_per_lun                    = SRP_SQ_SIZE,
        .use_clustering                 = ENABLE_CLUSTERING,
        .shost_attrs                    = srp_host_attrs
@@ -1492,6 +1552,7 @@ 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_ALL             = (SRP_OPT_ID_EXT       |
                                   SRP_OPT_IOC_GUID     |
                                   SRP_OPT_DGID         |
@@ -1507,6 +1568,7 @@ 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_ERR,                  NULL                    }
 };
 
@@ -1591,6 +1653,21 @@ 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;
+
                default:
                        printk(KERN_WARNING PFX "unknown parameter or missing value "
                               "'%s' in target creation request\n", p);
@@ -1633,11 +1710,10 @@ static ssize_t srp_create_target(struct class_device *class_dev,
        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) {
@@ -1826,7 +1902,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 {
@@ -1914,15 +1990,23 @@ static int __init srp_init_module(void)
 {
        int ret;
 
+       srp_template.sg_tablesize = srp_sg_tablesize;
+       srp_max_iu_len = (sizeof (struct srp_cmd) +
+                         sizeof (struct srp_indirect_buf) +
+                         srp_sg_tablesize * 16);
+
        ret = class_register(&srp_class);
        if (ret) {
                printk(KERN_ERR PFX "couldn't register class infiniband_srp\n");
                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;
        }
@@ -1933,6 +2017,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);
 }