diff options
Diffstat (limited to 'drivers/infiniband/ulp/srp/ib_srp.c')
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.c | 230 |
1 files changed, 153 insertions, 77 deletions
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 960dae5c87d1..fd8a95a9c5d3 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -503,8 +503,10 @@ err: static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, struct srp_request *req) { + struct scatterlist *scat; struct srp_cmd *cmd = req->cmd->buf; - int len; + int len, nents, count; + int i; u8 fmt; if (!scmnd->request_buffer || scmnd->sc_data_direction == DMA_NONE) @@ -517,82 +519,66 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, return -EINVAL; } - if (scmnd->use_sg) { - struct scatterlist *scat = scmnd->request_buffer; - int n; - int i; - - n = dma_map_sg(target->srp_host->dev->dma_device, - scat, scmnd->use_sg, scmnd->sc_data_direction); + /* + * This handling of non-SG commands can be killed when the + * SCSI midlayer no longer generates non-SG commands. + */ + if (likely(scmnd->use_sg)) { + nents = scmnd->use_sg; + scat = scmnd->request_buffer; + } else { + nents = 1; + scat = &req->fake_sg; + sg_init_one(scat, scmnd->request_buffer, scmnd->request_bufflen); + } - if (n == 1) { - struct srp_direct_buf *buf = (void *) cmd->add_data; + count = dma_map_sg(target->srp_host->dev->dma_device, scat, nents, + scmnd->sc_data_direction); - fmt = SRP_DATA_DESC_DIRECT; + if (count == 1) { + 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->mr->rkey); - buf->len = cpu_to_be32(sg_dma_len(scat)); + fmt = SRP_DATA_DESC_DIRECT; - len = sizeof (struct srp_cmd) + - sizeof (struct srp_direct_buf); - } else { - struct srp_indirect_buf *buf = (void *) cmd->add_data; - u32 datalen = 0; + buf->va = cpu_to_be64(sg_dma_address(scat)); + buf->key = cpu_to_be32(target->srp_host->mr->rkey); + buf->len = cpu_to_be32(sg_dma_len(scat)); - fmt = SRP_DATA_DESC_INDIRECT; + len = sizeof (struct srp_cmd) + + sizeof (struct srp_direct_buf); + } else { + struct srp_indirect_buf *buf = (void *) cmd->add_data; + u32 datalen = 0; - if (scmnd->sc_data_direction == DMA_TO_DEVICE) - cmd->data_out_desc_cnt = n; - else - cmd->data_in_desc_cnt = n; + fmt = SRP_DATA_DESC_INDIRECT; - buf->table_desc.va = cpu_to_be64(req->cmd->dma + - sizeof *cmd + - sizeof *buf); - buf->table_desc.key = + if (scmnd->sc_data_direction == DMA_TO_DEVICE) + cmd->data_out_desc_cnt = count; + else + cmd->data_in_desc_cnt = count; + + buf->table_desc.va = cpu_to_be64(req->cmd->dma + + sizeof *cmd + + sizeof *buf); + buf->table_desc.key = + cpu_to_be32(target->srp_host->mr->rkey); + buf->table_desc.len = + cpu_to_be32(count * sizeof (struct srp_direct_buf)); + + for (i = 0; i < count; ++i) { + buf->desc_list[i].va = cpu_to_be64(sg_dma_address(&scat[i])); + buf->desc_list[i].key = cpu_to_be32(target->srp_host->mr->rkey); - buf->table_desc.len = - cpu_to_be32(n * sizeof (struct srp_direct_buf)); - - for (i = 0; i < n; ++i) { - buf->desc_list[i].va = cpu_to_be64(sg_dma_address(&scat[i])); - buf->desc_list[i].key = - cpu_to_be32(target->srp_host->mr->rkey); - buf->desc_list[i].len = cpu_to_be32(sg_dma_len(&scat[i])); - - datalen += sg_dma_len(&scat[i]); - } - - buf->len = cpu_to_be32(datalen); + buf->desc_list[i].len = cpu_to_be32(sg_dma_len(&scat[i])); - len = sizeof (struct srp_cmd) + - sizeof (struct srp_indirect_buf) + - n * sizeof (struct srp_direct_buf); - } - } else { - struct srp_direct_buf *buf = (void *) cmd->add_data; - dma_addr_t dma; - - dma = dma_map_single(target->srp_host->dev->dma_device, - scmnd->request_buffer, scmnd->request_bufflen, - scmnd->sc_data_direction); - if (dma_mapping_error(dma)) { - printk(KERN_WARNING PFX "unable to map %p/%d (dir %d)\n", - scmnd->request_buffer, (int) scmnd->request_bufflen, - scmnd->sc_data_direction); - return -EINVAL; + datalen += sg_dma_len(&scat[i]); } - pci_unmap_addr_set(req, direct_mapping, dma); - - buf->va = cpu_to_be64(dma); - buf->key = cpu_to_be32(target->srp_host->mr->rkey); - buf->len = cpu_to_be32(scmnd->request_bufflen); + buf->len = cpu_to_be32(datalen); - fmt = SRP_DATA_DESC_DIRECT; - - len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf); + len = sizeof (struct srp_cmd) + + sizeof (struct srp_indirect_buf) + + count * sizeof (struct srp_direct_buf); } if (scmnd->sc_data_direction == DMA_TO_DEVICE) @@ -600,7 +586,6 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, else cmd->buf_fmt = fmt; - return len; } @@ -608,20 +593,28 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, struct srp_request *req) { + struct scatterlist *scat; + int nents; + if (!scmnd->request_buffer || (scmnd->sc_data_direction != DMA_TO_DEVICE && scmnd->sc_data_direction != DMA_FROM_DEVICE)) - return; + return; - if (scmnd->use_sg) - dma_unmap_sg(target->srp_host->dev->dma_device, - (struct scatterlist *) scmnd->request_buffer, - scmnd->use_sg, scmnd->sc_data_direction); - else - dma_unmap_single(target->srp_host->dev->dma_device, - pci_unmap_addr(req, direct_mapping), - scmnd->request_bufflen, - scmnd->sc_data_direction); + /* + * This handling of non-SG commands can be killed when the + * SCSI midlayer no longer generates non-SG commands. + */ + if (likely(scmnd->use_sg)) { + nents = scmnd->use_sg; + scat = scmnd->request_buffer; + } else { + nents = 1; + scat = &req->fake_sg; + } + + dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents, + scmnd->sc_data_direction); } static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) @@ -1237,6 +1230,87 @@ static int srp_reset_host(struct scsi_cmnd *scmnd) return ret; } +static ssize_t show_id_ext(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, "0x%016llx\n", + (unsigned long long) be64_to_cpu(target->id_ext)); +} + +static ssize_t show_ioc_guid(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, "0x%016llx\n", + (unsigned long long) be64_to_cpu(target->ioc_guid)); +} + +static ssize_t show_service_id(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, "0x%016llx\n", + (unsigned long long) be64_to_cpu(target->service_id)); +} + +static ssize_t show_pkey(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, "0x%04x\n", be16_to_cpu(target->path.pkey)); +} + +static ssize_t show_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(((__be16 *) target->path.dgid.raw)[0]), + be16_to_cpu(((__be16 *) target->path.dgid.raw)[1]), + be16_to_cpu(((__be16 *) target->path.dgid.raw)[2]), + be16_to_cpu(((__be16 *) target->path.dgid.raw)[3]), + be16_to_cpu(((__be16 *) target->path.dgid.raw)[4]), + be16_to_cpu(((__be16 *) target->path.dgid.raw)[5]), + be16_to_cpu(((__be16 *) target->path.dgid.raw)[6]), + 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 struct class_device_attribute *srp_host_attrs[] = { + &class_device_attr_id_ext, + &class_device_attr_ioc_guid, + &class_device_attr_service_id, + &class_device_attr_pkey, + &class_device_attr_dgid, + NULL +}; + static struct scsi_host_template srp_template = { .module = THIS_MODULE, .name = DRV_NAME, @@ -1249,7 +1323,8 @@ static struct scsi_host_template srp_template = { .this_id = -1, .sg_tablesize = SRP_MAX_INDIRECT, .cmd_per_lun = SRP_SQ_SIZE, - .use_clustering = ENABLE_CLUSTERING + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = srp_host_attrs }; static int srp_add_target(struct srp_host *host, struct srp_target_port *target) @@ -1366,6 +1441,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) strlcpy(dgid, p + i * 2, 3); target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16); } + kfree(p); break; case SRP_OPT_PKEY: |