linux/drivers/scsi/scsi_tgt_if.c
<<
>>
Prefs
   1/*
   2 * SCSI target kernel/user interface functions
   3 *
   4 * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
   5 * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 of the
  10 * License, or (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful, but
  13 * WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20 * 02110-1301 USA
  21 */
  22#include <linux/miscdevice.h>
  23#include <linux/file.h>
  24#include <linux/smp_lock.h>
  25#include <net/tcp.h>
  26#include <scsi/scsi.h>
  27#include <scsi/scsi_cmnd.h>
  28#include <scsi/scsi_device.h>
  29#include <scsi/scsi_host.h>
  30#include <scsi/scsi_tgt.h>
  31#include <scsi/scsi_tgt_if.h>
  32
  33#include <asm/cacheflush.h>
  34
  35#include "scsi_tgt_priv.h"
  36
  37#if TGT_RING_SIZE < PAGE_SIZE
  38#  define TGT_RING_SIZE PAGE_SIZE
  39#endif
  40
  41#define TGT_RING_PAGES (TGT_RING_SIZE >> PAGE_SHIFT)
  42#define TGT_EVENT_PER_PAGE (PAGE_SIZE / sizeof(struct tgt_event))
  43#define TGT_MAX_EVENTS (TGT_EVENT_PER_PAGE * TGT_RING_PAGES)
  44
  45struct tgt_ring {
  46        u32 tr_idx;
  47        unsigned long tr_pages[TGT_RING_PAGES];
  48        spinlock_t tr_lock;
  49};
  50
  51/* tx_ring : kernel->user, rx_ring : user->kernel */
  52static struct tgt_ring tx_ring, rx_ring;
  53static DECLARE_WAIT_QUEUE_HEAD(tgt_poll_wait);
  54
  55static inline void tgt_ring_idx_inc(struct tgt_ring *ring)
  56{
  57        if (ring->tr_idx == TGT_MAX_EVENTS - 1)
  58                ring->tr_idx = 0;
  59        else
  60                ring->tr_idx++;
  61}
  62
  63static struct tgt_event *tgt_head_event(struct tgt_ring *ring, u32 idx)
  64{
  65        u32 pidx, off;
  66
  67        pidx = idx / TGT_EVENT_PER_PAGE;
  68        off = idx % TGT_EVENT_PER_PAGE;
  69
  70        return (struct tgt_event *)
  71                (ring->tr_pages[pidx] + sizeof(struct tgt_event) * off);
  72}
  73
  74static int tgt_uspace_send_event(u32 type, struct tgt_event *p)
  75{
  76        struct tgt_event *ev;
  77        struct tgt_ring *ring = &tx_ring;
  78        unsigned long flags;
  79        int err = 0;
  80
  81        spin_lock_irqsave(&ring->tr_lock, flags);
  82
  83        ev = tgt_head_event(ring, ring->tr_idx);
  84        if (!ev->hdr.status)
  85                tgt_ring_idx_inc(ring);
  86        else
  87                err = -BUSY;
  88
  89        spin_unlock_irqrestore(&ring->tr_lock, flags);
  90
  91        if (err)
  92                return err;
  93
  94        memcpy(ev, p, sizeof(*ev));
  95        ev->hdr.type = type;
  96        mb();
  97        ev->hdr.status = 1;
  98
  99        flush_dcache_page(virt_to_page(ev));
 100
 101        wake_up_interruptible(&tgt_poll_wait);
 102
 103        return 0;
 104}
 105
 106int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id,
 107                             struct scsi_lun *lun, u64 tag)
 108{
 109        struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
 110        struct tgt_event ev;
 111        int err;
 112
 113        memset(&ev, 0, sizeof(ev));
 114        ev.p.cmd_req.host_no = shost->host_no;
 115        ev.p.cmd_req.itn_id = itn_id;
 116        ev.p.cmd_req.data_len = scsi_bufflen(cmd);
 117        memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
 118        memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
 119        ev.p.cmd_req.attribute = cmd->tag;
 120        ev.p.cmd_req.tag = tag;
 121
 122        dprintk("%p %d %u %x %llx\n", cmd, shost->host_no,
 123                ev.p.cmd_req.data_len, cmd->tag,
 124                (unsigned long long) ev.p.cmd_req.tag);
 125
 126        err = tgt_uspace_send_event(TGT_KEVENT_CMD_REQ, &ev);
 127        if (err)
 128                eprintk("tx buf is full, could not send\n");
 129
 130        return err;
 131}
 132
 133int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 itn_id, u64 tag)
 134{
 135        struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
 136        struct tgt_event ev;
 137        int err;
 138
 139        memset(&ev, 0, sizeof(ev));
 140        ev.p.cmd_done.host_no = shost->host_no;
 141        ev.p.cmd_done.itn_id = itn_id;
 142        ev.p.cmd_done.tag = tag;
 143        ev.p.cmd_done.result = cmd->result;
 144
 145        dprintk("%p %d %llu %u %x\n", cmd, shost->host_no,
 146                (unsigned long long) ev.p.cmd_req.tag,
 147                ev.p.cmd_req.data_len, cmd->tag);
 148
 149        err = tgt_uspace_send_event(TGT_KEVENT_CMD_DONE, &ev);
 150        if (err)
 151                eprintk("tx buf is full, could not send\n");
 152
 153        return err;
 154}
 155
 156int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 itn_id, int function,
 157                                  u64 tag, struct scsi_lun *scsilun, void *data)
 158{
 159        struct tgt_event ev;
 160        int err;
 161
 162        memset(&ev, 0, sizeof(ev));
 163        ev.p.tsk_mgmt_req.host_no = host_no;
 164        ev.p.tsk_mgmt_req.itn_id = itn_id;
 165        ev.p.tsk_mgmt_req.function = function;
 166        ev.p.tsk_mgmt_req.tag = tag;
 167        memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun));
 168        ev.p.tsk_mgmt_req.mid = (u64) (unsigned long) data;
 169
 170        dprintk("%d %x %llx %llx\n", host_no, function, (unsigned long long) tag,
 171                (unsigned long long) ev.p.tsk_mgmt_req.mid);
 172
 173        err = tgt_uspace_send_event(TGT_KEVENT_TSK_MGMT_REQ, &ev);
 174        if (err)
 175                eprintk("tx buf is full, could not send\n");
 176
 177        return err;
 178}
 179
 180int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 itn_id,
 181                                          int function, char *initiator_id)
 182{
 183        struct tgt_event ev;
 184        int err;
 185
 186        memset(&ev, 0, sizeof(ev));
 187        ev.p.it_nexus_req.host_no = host_no;
 188        ev.p.it_nexus_req.function = function;
 189        ev.p.it_nexus_req.itn_id = itn_id;
 190        if (initiator_id)
 191                strncpy(ev.p.it_nexus_req.initiator_id, initiator_id,
 192                        sizeof(ev.p.it_nexus_req.initiator_id));
 193
 194        dprintk("%d %x %llx\n", host_no, function, (unsigned long long)itn_id);
 195
 196        err = tgt_uspace_send_event(TGT_KEVENT_IT_NEXUS_REQ, &ev);
 197        if (err)
 198                eprintk("tx buf is full, could not send\n");
 199
 200        return err;
 201}
 202
 203static int event_recv_msg(struct tgt_event *ev)
 204{
 205        int err = 0;
 206
 207        switch (ev->hdr.type) {
 208        case TGT_UEVENT_CMD_RSP:
 209                err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
 210                                           ev->p.cmd_rsp.itn_id,
 211                                           ev->p.cmd_rsp.result,
 212                                           ev->p.cmd_rsp.tag,
 213                                           ev->p.cmd_rsp.uaddr,
 214                                           ev->p.cmd_rsp.len,
 215                                           ev->p.cmd_rsp.sense_uaddr,
 216                                           ev->p.cmd_rsp.sense_len,
 217                                           ev->p.cmd_rsp.rw);
 218                break;
 219        case TGT_UEVENT_TSK_MGMT_RSP:
 220                err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no,
 221                                               ev->p.tsk_mgmt_rsp.itn_id,
 222                                               ev->p.tsk_mgmt_rsp.mid,
 223                                               ev->p.tsk_mgmt_rsp.result);
 224                break;
 225        case TGT_UEVENT_IT_NEXUS_RSP:
 226                err = scsi_tgt_kspace_it_nexus_rsp(ev->p.it_nexus_rsp.host_no,
 227                                                   ev->p.it_nexus_rsp.itn_id,
 228                                                   ev->p.it_nexus_rsp.result);
 229                break;
 230        default:
 231                eprintk("unknown type %d\n", ev->hdr.type);
 232                err = -EINVAL;
 233        }
 234
 235        return err;
 236}
 237
 238static ssize_t tgt_write(struct file *file, const char __user * buffer,
 239                         size_t count, loff_t * ppos)
 240{
 241        struct tgt_event *ev;
 242        struct tgt_ring *ring = &rx_ring;
 243
 244        while (1) {
 245                ev = tgt_head_event(ring, ring->tr_idx);
 246                /* do we need this? */
 247                flush_dcache_page(virt_to_page(ev));
 248
 249                if (!ev->hdr.status)
 250                        break;
 251
 252                tgt_ring_idx_inc(ring);
 253                event_recv_msg(ev);
 254                ev->hdr.status = 0;
 255        };
 256
 257        return count;
 258}
 259
 260static unsigned int tgt_poll(struct file * file, struct poll_table_struct *wait)
 261{
 262        struct tgt_event *ev;
 263        struct tgt_ring *ring = &tx_ring;
 264        unsigned long flags;
 265        unsigned int mask = 0;
 266        u32 idx;
 267
 268        poll_wait(file, &tgt_poll_wait, wait);
 269
 270        spin_lock_irqsave(&ring->tr_lock, flags);
 271
 272        idx = ring->tr_idx ? ring->tr_idx - 1 : TGT_MAX_EVENTS - 1;
 273        ev = tgt_head_event(ring, idx);
 274        if (ev->hdr.status)
 275                mask |= POLLIN | POLLRDNORM;
 276
 277        spin_unlock_irqrestore(&ring->tr_lock, flags);
 278
 279        return mask;
 280}
 281
 282static int uspace_ring_map(struct vm_area_struct *vma, unsigned long addr,
 283                           struct tgt_ring *ring)
 284{
 285        int i, err;
 286
 287        for (i = 0; i < TGT_RING_PAGES; i++) {
 288                struct page *page = virt_to_page(ring->tr_pages[i]);
 289                err = vm_insert_page(vma, addr, page);
 290                if (err)
 291                        return err;
 292                addr += PAGE_SIZE;
 293        }
 294
 295        return 0;
 296}
 297
 298static int tgt_mmap(struct file *filp, struct vm_area_struct *vma)
 299{
 300        unsigned long addr;
 301        int err;
 302
 303        if (vma->vm_pgoff)
 304                return -EINVAL;
 305
 306        if (vma->vm_end - vma->vm_start != TGT_RING_SIZE * 2) {
 307                eprintk("mmap size must be %lu, not %lu \n",
 308                        TGT_RING_SIZE * 2, vma->vm_end - vma->vm_start);
 309                return -EINVAL;
 310        }
 311
 312        addr = vma->vm_start;
 313        err = uspace_ring_map(vma, addr, &tx_ring);
 314        if (err)
 315                return err;
 316        err = uspace_ring_map(vma, addr + TGT_RING_SIZE, &rx_ring);
 317
 318        return err;
 319}
 320
 321static int tgt_open(struct inode *inode, struct file *file)
 322{
 323        tx_ring.tr_idx = rx_ring.tr_idx = 0;
 324
 325        cycle_kernel_lock();
 326        return 0;
 327}
 328
 329static const struct file_operations tgt_fops = {
 330        .owner          = THIS_MODULE,
 331        .open           = tgt_open,
 332        .poll           = tgt_poll,
 333        .write          = tgt_write,
 334        .mmap           = tgt_mmap,
 335};
 336
 337static struct miscdevice tgt_miscdev = {
 338        .minor = MISC_DYNAMIC_MINOR,
 339        .name = "tgt",
 340        .fops = &tgt_fops,
 341};
 342
 343static void tgt_ring_exit(struct tgt_ring *ring)
 344{
 345        int i;
 346
 347        for (i = 0; i < TGT_RING_PAGES; i++)
 348                free_page(ring->tr_pages[i]);
 349}
 350
 351static int tgt_ring_init(struct tgt_ring *ring)
 352{
 353        int i;
 354
 355        spin_lock_init(&ring->tr_lock);
 356
 357        for (i = 0; i < TGT_RING_PAGES; i++) {
 358                ring->tr_pages[i] = get_zeroed_page(GFP_KERNEL);
 359                if (!ring->tr_pages[i]) {
 360                        eprintk("out of memory\n");
 361                        return -ENOMEM;
 362                }
 363        }
 364
 365        return 0;
 366}
 367
 368void scsi_tgt_if_exit(void)
 369{
 370        tgt_ring_exit(&tx_ring);
 371        tgt_ring_exit(&rx_ring);
 372        misc_deregister(&tgt_miscdev);
 373}
 374
 375int scsi_tgt_if_init(void)
 376{
 377        int err;
 378
 379        err = tgt_ring_init(&tx_ring);
 380        if (err)
 381                return err;
 382
 383        err = tgt_ring_init(&rx_ring);
 384        if (err)
 385                goto free_tx_ring;
 386
 387        err = misc_register(&tgt_miscdev);
 388        if (err)
 389                goto free_rx_ring;
 390
 391        return 0;
 392free_rx_ring:
 393        tgt_ring_exit(&rx_ring);
 394free_tx_ring:
 395        tgt_ring_exit(&tx_ring);
 396
 397        return err;
 398}
 399