linux/drivers/scsi/scsi_tgt_lib.c
<<
>>
Prefs
   1/*
   2 * SCSI target lib functions
   3 *
   4 * Copyright (C) 2005 Mike Christie <michaelc@cs.wisc.edu>
   5 * Copyright (C) 2005 FUJITA Tomonori <tomof@acm.org>
   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/blkdev.h>
  23#include <linux/hash.h>
  24#include <linux/module.h>
  25#include <linux/pagemap.h>
  26#include <linux/slab.h>
  27#include <scsi/scsi.h>
  28#include <scsi/scsi_cmnd.h>
  29#include <scsi/scsi_device.h>
  30#include <scsi/scsi_host.h>
  31#include <scsi/scsi_transport.h>
  32#include <scsi/scsi_tgt.h>
  33
  34#include "scsi_tgt_priv.h"
  35
  36static struct workqueue_struct *scsi_tgtd;
  37static struct kmem_cache *scsi_tgt_cmd_cache;
  38
  39/*
  40 * TODO: this struct will be killed when the block layer supports large bios
  41 * and James's work struct code is in
  42 */
  43struct scsi_tgt_cmd {
  44        /* TODO replace work with James b's code */
  45        struct work_struct work;
  46        /* TODO fix limits of some drivers */
  47        struct bio *bio;
  48
  49        struct list_head hash_list;
  50        struct request *rq;
  51        u64 itn_id;
  52        u64 tag;
  53};
  54
  55#define TGT_HASH_ORDER  4
  56#define cmd_hashfn(tag) hash_long((unsigned long) (tag), TGT_HASH_ORDER)
  57
  58struct scsi_tgt_queuedata {
  59        struct Scsi_Host *shost;
  60        struct list_head cmd_hash[1 << TGT_HASH_ORDER];
  61        spinlock_t cmd_hash_lock;
  62};
  63
  64/*
  65 * Function:    scsi_host_get_command()
  66 *
  67 * Purpose:     Allocate and setup a scsi command block and blk request
  68 *
  69 * Arguments:   shost   - scsi host
  70 *              data_dir - dma data dir
  71 *              gfp_mask- allocator flags
  72 *
  73 * Returns:     The allocated scsi command structure.
  74 *
  75 * This should be called by target LLDs to get a command.
  76 */
  77struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
  78                                        enum dma_data_direction data_dir,
  79                                        gfp_t gfp_mask)
  80{
  81        int write = (data_dir == DMA_TO_DEVICE);
  82        struct request *rq;
  83        struct scsi_cmnd *cmd;
  84        struct scsi_tgt_cmd *tcmd;
  85
  86        /* Bail if we can't get a reference to the device */
  87        if (!get_device(&shost->shost_gendev))
  88                return NULL;
  89
  90        tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC);
  91        if (!tcmd)
  92                goto put_dev;
  93
  94        /*
  95         * The blk helpers are used to the READ/WRITE requests
  96         * transferring data from a initiator point of view. Since
  97         * we are in target mode we want the opposite.
  98         */
  99        rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask);
 100        if (!rq)
 101                goto free_tcmd;
 102
 103        cmd = __scsi_get_command(shost, gfp_mask);
 104        if (!cmd)
 105                goto release_rq;
 106
 107        cmd->sc_data_direction = data_dir;
 108        cmd->jiffies_at_alloc = jiffies;
 109        cmd->request = rq;
 110
 111        cmd->cmnd = rq->cmd;
 112
 113        rq->special = cmd;
 114        rq->cmd_type = REQ_TYPE_DRV_PRIV;
 115        rq->cmd_flags |= REQ_TYPE_BLOCK_PC;
 116        rq->end_io_data = tcmd;
 117
 118        tcmd->rq = rq;
 119
 120        return cmd;
 121
 122release_rq:
 123        blk_put_request(rq);
 124free_tcmd:
 125        kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
 126put_dev:
 127        put_device(&shost->shost_gendev);
 128        return NULL;
 129
 130}
 131EXPORT_SYMBOL_GPL(scsi_host_get_command);
 132
 133/*
 134 * Function:    scsi_host_put_command()
 135 *
 136 * Purpose:     Free a scsi command block
 137 *
 138 * Arguments:   shost   - scsi host
 139 *              cmd     - command block to free
 140 *
 141 * Returns:     Nothing.
 142 *
 143 * Notes:       The command must not belong to any lists.
 144 */
 145void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
 146{
 147        struct request_queue *q = shost->uspace_req_q;
 148        struct request *rq = cmd->request;
 149        struct scsi_tgt_cmd *tcmd = rq->end_io_data;
 150        unsigned long flags;
 151
 152        kmem_cache_free(scsi_tgt_cmd_cache, tcmd);
 153
 154        spin_lock_irqsave(q->queue_lock, flags);
 155        __blk_put_request(q, rq);
 156        spin_unlock_irqrestore(q->queue_lock, flags);
 157
 158        __scsi_put_command(shost, cmd);
 159        put_device(&shost->shost_gendev);
 160}
 161EXPORT_SYMBOL_GPL(scsi_host_put_command);
 162
 163static void cmd_hashlist_del(struct scsi_cmnd *cmd)
 164{
 165        struct request_queue *q = cmd->request->q;
 166        struct scsi_tgt_queuedata *qdata = q->queuedata;
 167        unsigned long flags;
 168        struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
 169
 170        spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
 171        list_del(&tcmd->hash_list);
 172        spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
 173}
 174
 175static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
 176{
 177        blk_rq_unmap_user(tcmd->bio);
 178}
 179
 180static void scsi_tgt_cmd_destroy(struct work_struct *work)
 181{
 182        struct scsi_tgt_cmd *tcmd =
 183                container_of(work, struct scsi_tgt_cmd, work);
 184        struct scsi_cmnd *cmd = tcmd->rq->special;
 185
 186        dprintk("cmd %p %d %u\n", cmd, cmd->sc_data_direction,
 187                rq_data_dir(cmd->request));
 188        scsi_unmap_user_pages(tcmd);
 189        tcmd->rq->bio = NULL;
 190        scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
 191}
 192
 193static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd,
 194                              u64 itn_id, u64 tag)
 195{
 196        struct scsi_tgt_queuedata *qdata = rq->q->queuedata;
 197        unsigned long flags;
 198        struct list_head *head;
 199
 200        tcmd->itn_id = itn_id;
 201        tcmd->tag = tag;
 202        tcmd->bio = NULL;
 203        INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy);
 204        spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
 205        head = &qdata->cmd_hash[cmd_hashfn(tag)];
 206        list_add(&tcmd->hash_list, head);
 207        spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
 208}
 209
 210/*
 211 * scsi_tgt_alloc_queue - setup queue used for message passing
 212 * shost: scsi host
 213 *
 214 * This should be called by the LLD after host allocation.
 215 * And will be released when the host is released.
 216 */
 217int scsi_tgt_alloc_queue(struct Scsi_Host *shost)
 218{
 219        struct scsi_tgt_queuedata *queuedata;
 220        struct request_queue *q;
 221        int err, i;
 222
 223        /*
 224         * Do we need to send a netlink event or should uspace
 225         * just respond to the hotplug event?
 226         */
 227        q = __scsi_alloc_queue(shost, NULL);
 228        if (!q)
 229                return -ENOMEM;
 230
 231        queuedata = kzalloc(sizeof(*queuedata), GFP_KERNEL);
 232        if (!queuedata) {
 233                err = -ENOMEM;
 234                goto cleanup_queue;
 235        }
 236        queuedata->shost = shost;
 237        q->queuedata = queuedata;
 238
 239        /*
 240         * this is a silly hack. We should probably just queue as many
 241         * command as is recvd to userspace. uspace can then make
 242         * sure we do not overload the HBA
 243         */
 244        q->nr_requests = shost->can_queue;
 245        /*
 246         * We currently only support software LLDs so this does
 247         * not matter for now. Do we need this for the cards we support?
 248         * If so we should make it a host template value.
 249         */
 250        blk_queue_dma_alignment(q, 0);
 251        shost->uspace_req_q = q;
 252
 253        for (i = 0; i < ARRAY_SIZE(queuedata->cmd_hash); i++)
 254                INIT_LIST_HEAD(&queuedata->cmd_hash[i]);
 255        spin_lock_init(&queuedata->cmd_hash_lock);
 256
 257        return 0;
 258
 259cleanup_queue:
 260        blk_cleanup_queue(q);
 261        return err;
 262}
 263EXPORT_SYMBOL_GPL(scsi_tgt_alloc_queue);
 264
 265void scsi_tgt_free_queue(struct Scsi_Host *shost)
 266{
 267        int i;
 268        unsigned long flags;
 269        struct request_queue *q = shost->uspace_req_q;
 270        struct scsi_cmnd *cmd;
 271        struct scsi_tgt_queuedata *qdata = q->queuedata;
 272        struct scsi_tgt_cmd *tcmd, *n;
 273        LIST_HEAD(cmds);
 274
 275        spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
 276
 277        for (i = 0; i < ARRAY_SIZE(qdata->cmd_hash); i++) {
 278                list_for_each_entry_safe(tcmd, n, &qdata->cmd_hash[i],
 279                                         hash_list)
 280                        list_move(&tcmd->hash_list, &cmds);
 281        }
 282
 283        spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
 284
 285        while (!list_empty(&cmds)) {
 286                tcmd = list_entry(cmds.next, struct scsi_tgt_cmd, hash_list);
 287                list_del(&tcmd->hash_list);
 288                cmd = tcmd->rq->special;
 289
 290                shost->hostt->eh_abort_handler(cmd);
 291                scsi_tgt_cmd_destroy(&tcmd->work);
 292        }
 293}
 294EXPORT_SYMBOL_GPL(scsi_tgt_free_queue);
 295
 296struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *cmd)
 297{
 298        struct scsi_tgt_queuedata *queue = cmd->request->q->queuedata;
 299        return queue->shost;
 300}
 301EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);
 302
 303/*
 304 * scsi_tgt_queue_command - queue command for userspace processing
 305 * @cmd:        scsi command
 306 * @scsilun:    scsi lun
 307 * @tag:        unique value to identify this command for tmf
 308 */
 309int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id,
 310                           struct scsi_lun *scsilun, u64 tag)
 311{
 312        struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
 313        int err;
 314
 315        init_scsi_tgt_cmd(cmd->request, tcmd, itn_id, tag);
 316        err = scsi_tgt_uspace_send_cmd(cmd, itn_id, scsilun, tag);
 317        if (err)
 318                cmd_hashlist_del(cmd);
 319
 320        return err;
 321}
 322EXPORT_SYMBOL_GPL(scsi_tgt_queue_command);
 323
 324/*
 325 * This is run from a interrupt handler normally and the unmap
 326 * needs process context so we must queue
 327 */
 328static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
 329{
 330        struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
 331
 332        dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
 333
 334        scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag);
 335
 336        scsi_release_buffers(cmd);
 337
 338        queue_work(scsi_tgtd, &tcmd->work);
 339}
 340
 341static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
 342{
 343        struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
 344        int err;
 345
 346        dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
 347
 348        err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done);
 349        switch (err) {
 350        case SCSI_MLQUEUE_HOST_BUSY:
 351        case SCSI_MLQUEUE_DEVICE_BUSY:
 352                return -EAGAIN;
 353        }
 354        return 0;
 355}
 356
 357/* TODO: test this crap and replace bio_map_user with new interface maybe */
 358static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
 359                               unsigned long uaddr, unsigned int len, int rw)
 360{
 361        struct request_queue *q = cmd->request->q;
 362        struct request *rq = cmd->request;
 363        int err;
 364
 365        dprintk("%lx %u\n", uaddr, len);
 366        err = blk_rq_map_user(q, rq, NULL, (void *)uaddr, len, GFP_KERNEL);
 367        if (err) {
 368                /*
 369                 * TODO: need to fixup sg_tablesize, max_segment_size,
 370                 * max_sectors, etc for modern HW and software drivers
 371                 * where this value is bogus.
 372                 *
 373                 * TODO2: we can alloc a reserve buffer of max size
 374                 * we can handle and do the slow copy path for really large
 375                 * IO.
 376                 */
 377                eprintk("Could not handle request of size %u.\n", len);
 378                return err;
 379        }
 380
 381        tcmd->bio = rq->bio;
 382        err = scsi_init_io(cmd, GFP_KERNEL);
 383        if (err) {
 384                scsi_release_buffers(cmd);
 385                goto unmap_rq;
 386        }
 387        /*
 388         * we use REQ_TYPE_BLOCK_PC so scsi_init_io doesn't set the
 389         * length for us.
 390         */
 391        cmd->sdb.length = blk_rq_bytes(rq);
 392
 393        return 0;
 394
 395unmap_rq:
 396        scsi_unmap_user_pages(tcmd);
 397        return err;
 398}
 399
 400static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr,
 401                                unsigned len)
 402{
 403        char __user *p = (char __user *) uaddr;
 404
 405        if (copy_from_user(cmd->sense_buffer, p,
 406                           min_t(unsigned, SCSI_SENSE_BUFFERSIZE, len))) {
 407                printk(KERN_ERR "Could not copy the sense buffer\n");
 408                return -EIO;
 409        }
 410        return 0;
 411}
 412
 413static int scsi_tgt_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
 414{
 415        struct scsi_tgt_cmd *tcmd;
 416        int err;
 417
 418        err = shost->hostt->eh_abort_handler(cmd);
 419        if (err)
 420                eprintk("fail to abort %p\n", cmd);
 421
 422        tcmd = cmd->request->end_io_data;
 423        scsi_tgt_cmd_destroy(&tcmd->work);
 424        return err;
 425}
 426
 427static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag)
 428{
 429        struct scsi_tgt_queuedata *qdata = q->queuedata;
 430        struct request *rq = NULL;
 431        struct list_head *head;
 432        struct scsi_tgt_cmd *tcmd;
 433        unsigned long flags;
 434
 435        head = &qdata->cmd_hash[cmd_hashfn(tag)];
 436        spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
 437        list_for_each_entry(tcmd, head, hash_list) {
 438                if (tcmd->tag == tag) {
 439                        rq = tcmd->rq;
 440                        list_del(&tcmd->hash_list);
 441                        break;
 442                }
 443        }
 444        spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
 445
 446        return rq;
 447}
 448
 449int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag,
 450                         unsigned long uaddr, u32 len, unsigned long sense_uaddr,
 451                         u32 sense_len, u8 rw)
 452{
 453        struct Scsi_Host *shost;
 454        struct scsi_cmnd *cmd;
 455        struct request *rq;
 456        struct scsi_tgt_cmd *tcmd;
 457        int err = 0;
 458
 459        dprintk("%d %llu %d %u %lx %u\n", host_no, (unsigned long long) tag,
 460                result, len, uaddr, rw);
 461
 462        /* TODO: replace with a O(1) alg */
 463        shost = scsi_host_lookup(host_no);
 464        if (!shost) {
 465                printk(KERN_ERR "Could not find host no %d\n", host_no);
 466                return -EINVAL;
 467        }
 468
 469        if (!shost->uspace_req_q) {
 470                printk(KERN_ERR "Not target scsi host %d\n", host_no);
 471                goto done;
 472        }
 473
 474        rq = tgt_cmd_hash_lookup(shost->uspace_req_q, tag);
 475        if (!rq) {
 476                printk(KERN_ERR "Could not find tag %llu\n",
 477                       (unsigned long long) tag);
 478                err = -EINVAL;
 479                goto done;
 480        }
 481        cmd = rq->special;
 482
 483        dprintk("cmd %p scb %x result %d len %d bufflen %u %u %x\n",
 484                cmd, cmd->cmnd[0], result, len, scsi_bufflen(cmd),
 485                rq_data_dir(rq), cmd->cmnd[0]);
 486
 487        if (result == TASK_ABORTED) {
 488                scsi_tgt_abort_cmd(shost, cmd);
 489                goto done;
 490        }
 491        /*
 492         * store the userspace values here, the working values are
 493         * in the request_* values
 494         */
 495        tcmd = cmd->request->end_io_data;
 496        cmd->result = result;
 497
 498        if (cmd->result == SAM_STAT_CHECK_CONDITION)
 499                scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len);
 500
 501        if (len) {
 502                err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw);
 503                if (err) {
 504                        /*
 505                         * user-space daemon bugs or OOM
 506                         * TODO: we can do better for OOM.
 507                         */
 508                        struct scsi_tgt_queuedata *qdata;
 509                        struct list_head *head;
 510                        unsigned long flags;
 511
 512                        eprintk("cmd %p ret %d uaddr %lx len %d rw %d\n",
 513                                cmd, err, uaddr, len, rw);
 514
 515                        qdata = shost->uspace_req_q->queuedata;
 516                        head = &qdata->cmd_hash[cmd_hashfn(tcmd->tag)];
 517
 518                        spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
 519                        list_add(&tcmd->hash_list, head);
 520                        spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
 521
 522                        goto done;
 523                }
 524        }
 525        err = scsi_tgt_transfer_response(cmd);
 526done:
 527        scsi_host_put(shost);
 528        return err;
 529}
 530
 531int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, u64 itn_id,
 532                              int function, u64 tag, struct scsi_lun *scsilun,
 533                              void *data)
 534{
 535        int err;
 536
 537        /* TODO: need to retry if this fails. */
 538        err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, itn_id,
 539                                            function, tag, scsilun, data);
 540        if (err < 0)
 541                eprintk("The task management request lost!\n");
 542        return err;
 543}
 544EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request);
 545
 546int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result)
 547{
 548        struct Scsi_Host *shost;
 549        int err = -EINVAL;
 550
 551        dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
 552
 553        shost = scsi_host_lookup(host_no);
 554        if (!shost) {
 555                printk(KERN_ERR "Could not find host no %d\n", host_no);
 556                return err;
 557        }
 558
 559        if (!shost->uspace_req_q) {
 560                printk(KERN_ERR "Not target scsi host %d\n", host_no);
 561                goto done;
 562        }
 563
 564        err = shost->transportt->tsk_mgmt_response(shost, itn_id, mid, result);
 565done:
 566        scsi_host_put(shost);
 567        return err;
 568}
 569
 570int scsi_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
 571                             char *initiator)
 572{
 573        int err;
 574
 575        /* TODO: need to retry if this fails. */
 576        err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 0,
 577                                                    initiator);
 578        if (err < 0)
 579                eprintk("The i_t_neuxs request lost, %d %llx!\n",
 580                        shost->host_no, (unsigned long long)itn_id);
 581        return err;
 582}
 583EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_create);
 584
 585int scsi_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
 586{
 587        int err;
 588
 589        /* TODO: need to retry if this fails. */
 590        err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no,
 591                                                    itn_id, 1, NULL);
 592        if (err < 0)
 593                eprintk("The i_t_neuxs request lost, %d %llx!\n",
 594                        shost->host_no, (unsigned long long)itn_id);
 595        return err;
 596}
 597EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_destroy);
 598
 599int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result)
 600{
 601        struct Scsi_Host *shost;
 602        int err = -EINVAL;
 603
 604        dprintk("%d %d%llx\n", host_no, result, (unsigned long long)itn_id);
 605
 606        shost = scsi_host_lookup(host_no);
 607        if (!shost) {
 608                printk(KERN_ERR "Could not find host no %d\n", host_no);
 609                return err;
 610        }
 611
 612        if (!shost->uspace_req_q) {
 613                printk(KERN_ERR "Not target scsi host %d\n", host_no);
 614                goto done;
 615        }
 616
 617        err = shost->transportt->it_nexus_response(shost, itn_id, result);
 618done:
 619        scsi_host_put(shost);
 620        return err;
 621}
 622
 623static int __init scsi_tgt_init(void)
 624{
 625        int err;
 626
 627        scsi_tgt_cmd_cache =  KMEM_CACHE(scsi_tgt_cmd, 0);
 628        if (!scsi_tgt_cmd_cache)
 629                return -ENOMEM;
 630
 631        scsi_tgtd = alloc_workqueue("scsi_tgtd", 0, 1);
 632        if (!scsi_tgtd) {
 633                err = -ENOMEM;
 634                goto free_kmemcache;
 635        }
 636
 637        err = scsi_tgt_if_init();
 638        if (err)
 639                goto destroy_wq;
 640
 641        return 0;
 642
 643destroy_wq:
 644        destroy_workqueue(scsi_tgtd);
 645free_kmemcache:
 646        kmem_cache_destroy(scsi_tgt_cmd_cache);
 647        return err;
 648}
 649
 650static void __exit scsi_tgt_exit(void)
 651{
 652        destroy_workqueue(scsi_tgtd);
 653        scsi_tgt_if_exit();
 654        kmem_cache_destroy(scsi_tgt_cmd_cache);
 655}
 656
 657module_init(scsi_tgt_init);
 658module_exit(scsi_tgt_exit);
 659
 660MODULE_DESCRIPTION("SCSI target core");
 661MODULE_LICENSE("GPL");
 662