linux/drivers/scsi/libsrp.c
<<
>>
Prefs
   1/*
   2 * SCSI RDMA Protocol lib functions
   3 *
   4 * Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License as
   8 * published by the Free Software Foundation; either version 2 of the
   9 * License, or (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  19 * 02110-1301 USA
  20 */
  21#include <linux/err.h>
  22#include <linux/slab.h>
  23#include <linux/kfifo.h>
  24#include <linux/scatterlist.h>
  25#include <linux/dma-mapping.h>
  26#include <linux/module.h>
  27#include <scsi/scsi.h>
  28#include <scsi/scsi_cmnd.h>
  29#include <scsi/scsi_tcq.h>
  30#include <scsi/scsi_tgt.h>
  31#include <scsi/srp.h>
  32#include <scsi/libsrp.h>
  33
  34enum srp_task_attributes {
  35        SRP_SIMPLE_TASK = 0,
  36        SRP_HEAD_TASK = 1,
  37        SRP_ORDERED_TASK = 2,
  38        SRP_ACA_TASK = 4
  39};
  40
  41/* tmp - will replace with SCSI logging stuff */
  42#define eprintk(fmt, args...)                                   \
  43do {                                                            \
  44        printk("%s(%d) " fmt, __func__, __LINE__, ##args);      \
  45} while (0)
  46/* #define dprintk eprintk */
  47#define dprintk(fmt, args...)
  48
  49static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
  50                             struct srp_buf **ring)
  51{
  52        int i;
  53        struct iu_entry *iue;
  54
  55        q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
  56        if (!q->pool)
  57                return -ENOMEM;
  58        q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
  59        if (!q->items)
  60                goto free_pool;
  61
  62        spin_lock_init(&q->lock);
  63        kfifo_init(&q->queue, (void *) q->pool, max * sizeof(void *));
  64
  65        for (i = 0, iue = q->items; i < max; i++) {
  66                kfifo_in(&q->queue, (void *) &iue, sizeof(void *));
  67                iue->sbuf = ring[i];
  68                iue++;
  69        }
  70        return 0;
  71
  72        kfree(q->items);
  73free_pool:
  74        kfree(q->pool);
  75        return -ENOMEM;
  76}
  77
  78static void srp_iu_pool_free(struct srp_queue *q)
  79{
  80        kfree(q->items);
  81        kfree(q->pool);
  82}
  83
  84static struct srp_buf **srp_ring_alloc(struct device *dev,
  85                                       size_t max, size_t size)
  86{
  87        int i;
  88        struct srp_buf **ring;
  89
  90        ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
  91        if (!ring)
  92                return NULL;
  93
  94        for (i = 0; i < max; i++) {
  95                ring[i] = kzalloc(sizeof(struct srp_buf), GFP_KERNEL);
  96                if (!ring[i])
  97                        goto out;
  98                ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
  99                                                  GFP_KERNEL);
 100                if (!ring[i]->buf)
 101                        goto out;
 102        }
 103        return ring;
 104
 105out:
 106        for (i = 0; i < max && ring[i]; i++) {
 107                if (ring[i]->buf)
 108                        dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
 109                kfree(ring[i]);
 110        }
 111        kfree(ring);
 112
 113        return NULL;
 114}
 115
 116static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max,
 117                          size_t size)
 118{
 119        int i;
 120
 121        for (i = 0; i < max; i++) {
 122                dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
 123                kfree(ring[i]);
 124        }
 125        kfree(ring);
 126}
 127
 128int srp_target_alloc(struct srp_target *target, struct device *dev,
 129                     size_t nr, size_t iu_size)
 130{
 131        int err;
 132
 133        spin_lock_init(&target->lock);
 134        INIT_LIST_HEAD(&target->cmd_queue);
 135
 136        target->dev = dev;
 137        dev_set_drvdata(target->dev, target);
 138
 139        target->srp_iu_size = iu_size;
 140        target->rx_ring_size = nr;
 141        target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
 142        if (!target->rx_ring)
 143                return -ENOMEM;
 144        err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
 145        if (err)
 146                goto free_ring;
 147
 148        return 0;
 149
 150free_ring:
 151        srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
 152        return -ENOMEM;
 153}
 154EXPORT_SYMBOL_GPL(srp_target_alloc);
 155
 156void srp_target_free(struct srp_target *target)
 157{
 158        srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
 159                      target->srp_iu_size);
 160        srp_iu_pool_free(&target->iu_queue);
 161}
 162EXPORT_SYMBOL_GPL(srp_target_free);
 163
 164struct iu_entry *srp_iu_get(struct srp_target *target)
 165{
 166        struct iu_entry *iue = NULL;
 167
 168        if (kfifo_out_locked(&target->iu_queue.queue, (void *) &iue,
 169                sizeof(void *), &target->iu_queue.lock) != sizeof(void *)) {
 170                        WARN_ONCE(1, "unexpected fifo state");
 171                        return NULL;
 172        }
 173        if (!iue)
 174                return iue;
 175        iue->target = target;
 176        INIT_LIST_HEAD(&iue->ilist);
 177        iue->flags = 0;
 178        return iue;
 179}
 180EXPORT_SYMBOL_GPL(srp_iu_get);
 181
 182void srp_iu_put(struct iu_entry *iue)
 183{
 184        kfifo_in_locked(&iue->target->iu_queue.queue, (void *) &iue,
 185                        sizeof(void *), &iue->target->iu_queue.lock);
 186}
 187EXPORT_SYMBOL_GPL(srp_iu_put);
 188
 189static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
 190                           enum dma_data_direction dir, srp_rdma_t rdma_io,
 191                           int dma_map, int ext_desc)
 192{
 193        struct iu_entry *iue = NULL;
 194        struct scatterlist *sg = NULL;
 195        int err, nsg = 0, len;
 196
 197        if (dma_map) {
 198                iue = (struct iu_entry *) sc->SCp.ptr;
 199                sg = scsi_sglist(sc);
 200
 201                dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc),
 202                        md->len, scsi_sg_count(sc));
 203
 204                nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
 205                                 DMA_BIDIRECTIONAL);
 206                if (!nsg) {
 207                        printk("fail to map %p %d\n", iue, scsi_sg_count(sc));
 208                        return 0;
 209                }
 210                len = min(scsi_bufflen(sc), md->len);
 211        } else
 212                len = md->len;
 213
 214        err = rdma_io(sc, sg, nsg, md, 1, dir, len);
 215
 216        if (dma_map)
 217                dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
 218
 219        return err;
 220}
 221
 222static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
 223                             struct srp_indirect_buf *id,
 224                             enum dma_data_direction dir, srp_rdma_t rdma_io,
 225                             int dma_map, int ext_desc)
 226{
 227        struct iu_entry *iue = NULL;
 228        struct srp_direct_buf *md = NULL;
 229        struct scatterlist dummy, *sg = NULL;
 230        dma_addr_t token = 0;
 231        int err = 0;
 232        int nmd, nsg = 0, len;
 233
 234        if (dma_map || ext_desc) {
 235                iue = (struct iu_entry *) sc->SCp.ptr;
 236                sg = scsi_sglist(sc);
 237
 238                dprintk("%p %u %u %d %d\n",
 239                        iue, scsi_bufflen(sc), id->len,
 240                        cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
 241        }
 242
 243        nmd = id->table_desc.len / sizeof(struct srp_direct_buf);
 244
 245        if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) ||
 246            (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) {
 247                md = &id->desc_list[0];
 248                goto rdma;
 249        }
 250
 251        if (ext_desc && dma_map) {
 252                md = dma_alloc_coherent(iue->target->dev, id->table_desc.len,
 253                                &token, GFP_KERNEL);
 254                if (!md) {
 255                        eprintk("Can't get dma memory %u\n", id->table_desc.len);
 256                        return -ENOMEM;
 257                }
 258
 259                sg_init_one(&dummy, md, id->table_desc.len);
 260                sg_dma_address(&dummy) = token;
 261                sg_dma_len(&dummy) = id->table_desc.len;
 262                err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
 263                              id->table_desc.len);
 264                if (err) {
 265                        eprintk("Error copying indirect table %d\n", err);
 266                        goto free_mem;
 267                }
 268        } else {
 269                eprintk("This command uses external indirect buffer\n");
 270                return -EINVAL;
 271        }
 272
 273rdma:
 274        if (dma_map) {
 275                nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
 276                                 DMA_BIDIRECTIONAL);
 277                if (!nsg) {
 278                        eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc));
 279                        err = -EIO;
 280                        goto free_mem;
 281                }
 282                len = min(scsi_bufflen(sc), id->len);
 283        } else
 284                len = id->len;
 285
 286        err = rdma_io(sc, sg, nsg, md, nmd, dir, len);
 287
 288        if (dma_map)
 289                dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
 290
 291free_mem:
 292        if (token && dma_map)
 293                dma_free_coherent(iue->target->dev, id->table_desc.len, md, token);
 294
 295        return err;
 296}
 297
 298static int data_out_desc_size(struct srp_cmd *cmd)
 299{
 300        int size = 0;
 301        u8 fmt = cmd->buf_fmt >> 4;
 302
 303        switch (fmt) {
 304        case SRP_NO_DATA_DESC:
 305                break;
 306        case SRP_DATA_DESC_DIRECT:
 307                size = sizeof(struct srp_direct_buf);
 308                break;
 309        case SRP_DATA_DESC_INDIRECT:
 310                size = sizeof(struct srp_indirect_buf) +
 311                        sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
 312                break;
 313        default:
 314                eprintk("client error. Invalid data_out_format %x\n", fmt);
 315                break;
 316        }
 317        return size;
 318}
 319
 320/*
 321 * TODO: this can be called multiple times for a single command if it
 322 * has very long data.
 323 */
 324int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
 325                      srp_rdma_t rdma_io, int dma_map, int ext_desc)
 326{
 327        struct srp_direct_buf *md;
 328        struct srp_indirect_buf *id;
 329        enum dma_data_direction dir;
 330        int offset, err = 0;
 331        u8 format;
 332
 333        offset = cmd->add_cdb_len & ~3;
 334
 335        dir = srp_cmd_direction(cmd);
 336        if (dir == DMA_FROM_DEVICE)
 337                offset += data_out_desc_size(cmd);
 338
 339        if (dir == DMA_TO_DEVICE)
 340                format = cmd->buf_fmt >> 4;
 341        else
 342                format = cmd->buf_fmt & ((1U << 4) - 1);
 343
 344        switch (format) {
 345        case SRP_NO_DATA_DESC:
 346                break;
 347        case SRP_DATA_DESC_DIRECT:
 348                md = (struct srp_direct_buf *)
 349                        (cmd->add_data + offset);
 350                err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc);
 351                break;
 352        case SRP_DATA_DESC_INDIRECT:
 353                id = (struct srp_indirect_buf *)
 354                        (cmd->add_data + offset);
 355                err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map,
 356                                        ext_desc);
 357                break;
 358        default:
 359                eprintk("Unknown format %d %x\n", dir, format);
 360                err = -EINVAL;
 361        }
 362
 363        return err;
 364}
 365EXPORT_SYMBOL_GPL(srp_transfer_data);
 366
 367static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
 368{
 369        struct srp_direct_buf *md;
 370        struct srp_indirect_buf *id;
 371        int len = 0, offset = cmd->add_cdb_len & ~3;
 372        u8 fmt;
 373
 374        if (dir == DMA_TO_DEVICE)
 375                fmt = cmd->buf_fmt >> 4;
 376        else {
 377                fmt = cmd->buf_fmt & ((1U << 4) - 1);
 378                offset += data_out_desc_size(cmd);
 379        }
 380
 381        switch (fmt) {
 382        case SRP_NO_DATA_DESC:
 383                break;
 384        case SRP_DATA_DESC_DIRECT:
 385                md = (struct srp_direct_buf *) (cmd->add_data + offset);
 386                len = md->len;
 387                break;
 388        case SRP_DATA_DESC_INDIRECT:
 389                id = (struct srp_indirect_buf *) (cmd->add_data + offset);
 390                len = id->len;
 391                break;
 392        default:
 393                eprintk("invalid data format %x\n", fmt);
 394                break;
 395        }
 396        return len;
 397}
 398
 399int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
 400                  u64 itn_id, u64 addr)
 401{
 402        enum dma_data_direction dir;
 403        struct scsi_cmnd *sc;
 404        int tag, len, err;
 405
 406        switch (cmd->task_attr) {
 407        case SRP_SIMPLE_TASK:
 408                tag = MSG_SIMPLE_TAG;
 409                break;
 410        case SRP_ORDERED_TASK:
 411                tag = MSG_ORDERED_TAG;
 412                break;
 413        case SRP_HEAD_TASK:
 414                tag = MSG_HEAD_TAG;
 415                break;
 416        default:
 417                eprintk("Task attribute %d not supported\n", cmd->task_attr);
 418                tag = MSG_ORDERED_TAG;
 419        }
 420
 421        dir = srp_cmd_direction(cmd);
 422        len = vscsis_data_length(cmd, dir);
 423
 424        dprintk("%p %x %lx %d %d %d %llx\n", info, cmd->cdb[0],
 425                cmd->lun, dir, len, tag, (unsigned long long) cmd->tag);
 426
 427        sc = scsi_host_get_command(shost, dir, GFP_KERNEL);
 428        if (!sc)
 429                return -ENOMEM;
 430
 431        sc->SCp.ptr = info;
 432        memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE);
 433        sc->sdb.length = len;
 434        sc->sdb.table.sgl = (void *) (unsigned long) addr;
 435        sc->tag = tag;
 436        err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun,
 437                                     cmd->tag);
 438        if (err)
 439                scsi_host_put_command(shost, sc);
 440
 441        return err;
 442}
 443EXPORT_SYMBOL_GPL(srp_cmd_queue);
 444
 445MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions");
 446MODULE_AUTHOR("FUJITA Tomonori");
 447MODULE_LICENSE("GPL");
 448
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.