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