UBUNTU: ubuntu: iscsitarget -- version 1.4.20.1
authorLeann Ogasawara <leann.ogasawara@canonical.com>
Wed, 26 May 2010 02:31:39 +0000 (19:31 -0700)
committerLeann Ogasawara <leann.ogasawara@canonical.com>
Mon, 28 Mar 2011 13:48:41 +0000 (06:48 -0700)
Update iscsitarget to the latest stable version (v1.4.20.1) from
sourceforge.

ExternalDriver: iscsi_trgt
Url: http://sourceforge.net/projects/iscsitarget/files/
Version: 1.4.20.1

Signed-off-by: Leann Ogasawara <leann.ogasawara@canonical.com>

18 files changed:
ubuntu/iscsitarget/BOM
ubuntu/iscsitarget/block-io.c
ubuntu/iscsitarget/config.c
ubuntu/iscsitarget/conn.c
ubuntu/iscsitarget/file-io.c
ubuntu/iscsitarget/include/iet_u.h
ubuntu/iscsitarget/iotype.h
ubuntu/iscsitarget/iscsi.c
ubuntu/iscsitarget/iscsi.h
ubuntu/iscsitarget/nthread.c
ubuntu/iscsitarget/null-io.c
ubuntu/iscsitarget/param.c
ubuntu/iscsitarget/session.c
ubuntu/iscsitarget/target.c
ubuntu/iscsitarget/target_disk.c
ubuntu/iscsitarget/ua.c
ubuntu/iscsitarget/volume.c
ubuntu/iscsitarget/wthread.c

index cda1135..0fde30c 100644 (file)
@@ -1,2 +1,2 @@
 Downloaded from:       svn://svn.berlios.de/iscsitarget/trunk
-Current Version:       1.4.19
+Current Version:       1.4.20.1
index 708f101..4de1d20 100644 (file)
@@ -86,7 +86,8 @@ blockio_make_request(struct iet_volume *volume, struct tio *tio, int rw)
                        goto out;
                }
 
-               bio->bi_sector = ppos >> volume->blk_shift;
+               /* bi_sector is ALWAYS in units of 512 bytes */
+               bio->bi_sector = ppos >> 9;
                bio->bi_bdev = bio_data->bdev;
                bio->bi_end_io = blockio_bio_endio;
                bio->bi_private = tio_work;
@@ -174,77 +175,21 @@ blockio_open_path(struct iet_volume *volume, const char *path)
        return err;
 }
 
-static int
-set_scsiid(struct iet_volume *volume, const char *id)
-{
-       size_t len;
-
-       if ((len = strlen(id)) > SCSI_ID_LEN - VENDOR_ID_LEN) {
-               eprintk("SCSI ID too long, %zd provided, %u max\n", len,
-                       SCSI_ID_LEN - VENDOR_ID_LEN);
-               return -EINVAL;
-       }
-
-       memcpy(volume->scsi_id + VENDOR_ID_LEN, id, len);
-
-       return 0;
-}
-
-static void
-gen_scsiid(struct iet_volume *volume, struct inode *inode)
-{
-       int i;
-       u32 *p;
-
-       strlcpy(volume->scsi_id, VENDOR_ID, VENDOR_ID_LEN);
-
-       for (i = VENDOR_ID_LEN; i < SCSI_ID_LEN; i++)
-               if (volume->scsi_id[i])
-                       return;
-
-       /* If a scsi id doesn't exist generate a 16 byte one:
-        * Bytes   1-4: target type
-        * Bytes   5-8: target id
-        * Bytes  9-12: inode number
-        * Bytes 13-16: device type
-        */
-       p = (u32 *) (volume->scsi_id + VENDOR_ID_LEN);
-       *(p + 0) = volume->target->trgt_param.target_type;
-       *(p + 1) = volume->target->tid;
-       *(p + 2) = volume->lun;
-       *(p + 3) = (unsigned int) inode->i_sb->s_dev;
-}
-
-static int
-set_scsisn(struct iet_volume *volume, const char *sn)
-{
-       size_t len;
-
-       if ((len = strlen(sn)) > SCSI_SN_LEN) {
-               eprintk("SCSI SN too long, %zd provided, %u max\n", len,
-                       SCSI_SN_LEN);
-               return -EINVAL;
-       }
-
-       memcpy(volume->scsi_sn, sn, len);
-
-       return 0;
-}
-
 /* Create an enumeration of our accepted actions */
 enum
 {
-       Opt_scsiid, Opt_scsisn, Opt_path, Opt_ignore, Opt_err,
+       opt_path, opt_ignore, opt_err,
 };
 
 /* Create a match table using our action enums and their matching options */
 static match_table_t tokens = {
-       {Opt_scsiid, "ScsiId=%s"},
-       {Opt_scsisn, "ScsiSN=%s"},
-       {Opt_path, "Path=%s"},
-       {Opt_ignore, "Type=%s"},
-       {Opt_ignore, "IOMode=%s"},
-       {Opt_err, NULL},
+       {opt_path, "path=%s"},
+       {opt_ignore, "scsiid=%s"},
+       {opt_ignore, "scsisn=%s"},
+       {opt_ignore, "type=%s"},
+       {opt_ignore, "iomode=%s"},
+       {opt_ignore, "blocksize=%s"},
+       {opt_err, NULL},
 };
 
 static int
@@ -262,29 +207,10 @@ parse_blockio_params(struct iet_volume *volume, char *params)
                int token;
                if (!*p)
                        continue;
+               iet_strtolower(p);
                token = match_token(p, tokens, args);
                switch (token) {
-               case Opt_scsiid:
-                       if (!(q = match_strdup(&args[0]))) {
-                               err = -ENOMEM;
-                               goto out;
-                       }
-                       err = set_scsiid(volume, q);
-                       kfree(q);
-                       if (err < 0)
-                               goto out;
-                       break;
-               case Opt_scsisn:
-                       if (!(q = match_strdup(&args[0]))) {
-                               err = -ENOMEM;
-                               goto out;
-                       }
-                       err = set_scsisn(volume, q);
-                       kfree(q);
-                       if (err < 0)
-                               goto out;
-                       break;
-               case Opt_path:
+               case opt_path:
                        if (info->path) {
                                iprintk("Target %s, LUN %u: "
                                        "duplicate \"Path\" param\n",
@@ -301,7 +227,7 @@ parse_blockio_params(struct iet_volume *volume, char *params)
                        if (err < 0)
                                goto out;
                        break;
-               case Opt_ignore:
+               case opt_ignore:
                        break;
                default:
                        iprintk("Target %s, LUN %u: unknown param %s\n",
@@ -315,6 +241,7 @@ parse_blockio_params(struct iet_volume *volume, char *params)
                        volume->target->name, volume->lun);
                err = -EINVAL;
        }
+
   out:
        return err;
 }
@@ -350,22 +277,31 @@ blockio_attach(struct iet_volume *volume, char *args)
 
        volume->private = bio_data;
 
-       if ((err = parse_blockio_params(volume, args)) < 0) {
+       err = parse_blockio_params(volume, args);
+       if (!err) {
+               /* see Documentation/ABI/testing/sysfs-block */
+               unsigned bsz = bdev_logical_block_size(bio_data->bdev);
+               if (!volume->blk_shift)
+                       volume->blk_shift = ilog2(bsz);
+               else if (volume->blk_shift < ilog2(bsz)) {
+                       eprintk("Specified block size (%u) smaller than "
+                               "device %s logical block size (%u)\n",
+                               (1 << volume->blk_shift), bio_data->path, bsz);
+                       err = -EINVAL;
+               }
+       }
+       if (err < 0) {
                eprintk("Error attaching Lun %u to Target %s \n",
                        volume->lun, volume->target->name);
                goto out;
        }
 
-       /* Assign a vendor id, generate scsi id if none exists */
-       gen_scsiid(volume, bio_data->bdev->bd_inode);
+       volume->blk_cnt = bio_data->bdev->bd_inode->i_size >> volume->blk_shift;
 
        /* Offer neither write nor read caching */
        ClearLURCache(volume);
        ClearLUWCache(volume);
 
-       volume->blk_shift = SECTOR_SIZE_BITS;
-       volume->blk_cnt = bio_data->bdev->bd_inode->i_size >> volume->blk_shift;
-
   out:
        if (err < 0)
                blockio_detach(volume);
index 51331fb..87fa44b 100644 (file)
@@ -9,6 +9,8 @@
 #include "iscsi.h"
 #include "iscsi_dbg.h"
 
+static DECLARE_MUTEX(ioctl_sem);
+
 struct proc_entries {
        const char *name;
        struct file_operations *fops;
@@ -60,26 +62,45 @@ err:
        return -ENOMEM;
 }
 
-static int get_conn_info(struct iscsi_target *target, unsigned long ptr)
+static int get_module_info(unsigned long ptr)
 {
+       struct module_info info;
        int err;
+
+       snprintf(info.version, sizeof(info.version), "%s", IET_VERSION_STRING);
+
+       err = copy_to_user((void *) ptr, &info, sizeof(info));
+       if (err)
+               return -EFAULT;
+
+       return 0;
+}
+
+static int get_conn_info(struct iscsi_target *target, unsigned long ptr)
+{
        struct iscsi_session *session;
-       struct conn_info info;
        struct iscsi_conn *conn;
+       struct conn_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
-               return err;
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
 
        session = session_lookup(target, info.sid);
        if (!session)
                return -ENOENT;
+
        conn = conn_lookup(session, info.cid);
+       if (!conn)
+               return -ENOENT;
 
        info.cid = conn->cid;
        info.stat_sn = conn->stat_sn;
        info.exp_stat_sn = conn->exp_stat_sn;
 
-       if (copy_to_user((void *) ptr, &info, sizeof(info)))
+       err = copy_to_user((void *) ptr, &info, sizeof(info));
+       if (err)
                return -EFAULT;
 
        return 0;
@@ -87,14 +108,16 @@ static int get_conn_info(struct iscsi_target *target, unsigned long ptr)
 
 static int add_conn(struct iscsi_target *target, unsigned long ptr)
 {
-       int err;
        struct iscsi_session *session;
        struct conn_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
-               return err;
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
 
-       if (!(session = session_lookup(target, info.sid)))
+       session = session_lookup(target, info.sid);
+       if (!session)
                return -ENOENT;
 
        return conn_add(session, &info);
@@ -102,14 +125,16 @@ static int add_conn(struct iscsi_target *target, unsigned long ptr)
 
 static int del_conn(struct iscsi_target *target, unsigned long ptr)
 {
-       int err;
        struct iscsi_session *session;
        struct conn_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
-               return err;
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
 
-       if (!(session = session_lookup(target, info.sid)))
+       session = session_lookup(target, info.sid);
+       if (!session)
                return -ENOENT;
 
        return conn_del(session, &info);
@@ -117,22 +142,23 @@ static int del_conn(struct iscsi_target *target, unsigned long ptr)
 
 static int get_session_info(struct iscsi_target *target, unsigned long ptr)
 {
-       int err;
        struct iscsi_session *session;
        struct session_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
-               return err;
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
 
        session = session_lookup(target, info.sid);
-
        if (!session)
                return -ENOENT;
 
        info.exp_cmd_sn = session->exp_cmd_sn;
        info.max_cmd_sn = session->max_cmd_sn;
 
-       if (copy_to_user((void *) ptr, &info, sizeof(info)))
+       err = copy_to_user((void *) ptr, &info, sizeof(info));
+       if (err)
                return -EFAULT;
 
        return 0;
@@ -140,78 +166,90 @@ static int get_session_info(struct iscsi_target *target, unsigned long ptr)
 
 static int add_session(struct iscsi_target *target, unsigned long ptr)
 {
-       int err;
        struct session_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
-               return err;
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
 
        return session_add(target, &info);
 }
 
 static int del_session(struct iscsi_target *target, unsigned long ptr)
 {
-       int err;
        struct session_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
-               return err;
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
 
        return session_del(target, info.sid);
 }
 
 static int add_volume(struct iscsi_target *target, unsigned long ptr)
 {
-       int err;
        struct volume_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
-               return err;
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
 
        return volume_add(target, &info);
 }
 
 static int del_volume(struct iscsi_target *target, unsigned long ptr)
 {
-       int err;
        struct volume_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
-               return err;
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
 
        return iscsi_volume_del(target, &info);
 }
 
 static int iscsi_param_config(struct iscsi_target *target, unsigned long ptr, int set)
 {
-       int err;
        struct iscsi_param_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
-               goto out;
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
 
-       if ((err = iscsi_param_set(target, &info, set)) < 0)
-               goto out;
+       err = iscsi_param_set(target, &info, set);
+       if (err < 0 || set)
+               return err;
 
-       if (!set)
-               err = copy_to_user((void *) ptr, &info, sizeof(info));
+       err = copy_to_user((void *) ptr, &info, sizeof(info));
+       if (err)
+               return -EFAULT;
 
-out:
-       return err;
+       return 0;
 }
 
 static int add_target(unsigned long ptr)
 {
-       int err;
        struct target_info info;
+       int err;
 
-       if ((err = copy_from_user(&info, (void *) ptr, sizeof(info))) < 0)
+       err = copy_from_user(&info, (void *) ptr, sizeof(info));
+       if (err)
+               return -EFAULT;
+
+       err = target_add(&info);
+       if (err < 0)
                return err;
 
-       if (!(err = target_add(&info)))
-               err = copy_to_user((void *) ptr, &info, sizeof(info));
+       err = copy_to_user((void *) ptr, &info, sizeof(info));
+       if (err)
+               return -EFAULT;
 
-       return err;
+       return 0;
 }
 
 static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -220,40 +258,39 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        long err;
        u32 id;
 
-       if ((err = get_user(id, (u32 *) arg)) != 0)
-               goto done;
+       err = down_interruptible(&ioctl_sem);
+       if (err < 0)
+               return err;
 
-       if (cmd == DEL_TARGET) {
-               err = target_del(id);
+       if (cmd == GET_MODULE_INFO) {
+               err = get_module_info(arg);
                goto done;
        }
 
-       target = target_lookup_by_id(id);
+       if (cmd == ADD_TARGET) {
+               err = add_target(arg);
+               goto done;
+       }
 
-       if (cmd == ADD_TARGET)
-               if (target) {
-                       err = -EEXIST;
-                       eprintk("Target %u already exist!\n", id);
-                       goto done;
-               }
+       err = get_user(id, (u32 *) arg);
+       if (err < 0)
+               goto done;
 
-       switch (cmd) {
-       case ADD_TARGET:
-               assert(!target);
-               err = add_target(arg);
+       /* locking handled in target_del */
+       if (cmd == DEL_TARGET) {
+               err = target_del(id);
                goto done;
        }
 
+       target = target_lookup_by_id(id);
        if (!target) {
-               eprintk("can't find the target %u\n", id);
-               err = -EINVAL;
+               err = -ENOENT;
                goto done;
        }
 
-       if ((err = target_lock(target, 1)) < 0) {
-               eprintk("interrupted %ld %d\n", err, cmd);
+       err = target_lock(target, 1);
+       if (err < 0)
                goto done;
-       }
 
        switch (cmd) {
        case ADD_VOLUME:
@@ -300,17 +337,20 @@ static long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                err = -EINVAL;
        }
 
-       if (target)
-               target_unlock(target);
-
+       target_unlock(target);
 done:
+       up(&ioctl_sem);
+
        return err;
 }
 
 static int release(struct inode *i __attribute__((unused)),
                   struct file *f __attribute__((unused)))
 {
+       down(&ioctl_sem);
        target_del_all();
+       up(&ioctl_sem);
+
        return 0;
 }
 
index 5f91e3d..ec6dada 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/file.h>
 #include <linux/ip.h>
 #include <net/tcp.h>
+#include <scsi/scsi.h>
 
 #include "iscsi.h"
 #include "iscsi_dbg.h"
@@ -211,22 +212,39 @@ static int iet_conn_alloc(struct iscsi_session *session, struct conn_info *info)
 
 void conn_close(struct iscsi_conn *conn)
 {
+       struct iscsi_cmnd *cmnd;
+       struct iscsi_session *session = conn->session;
+
        if (test_and_clear_bit(CONN_ACTIVE, &conn->state))
                set_bit(CONN_CLOSING, &conn->state);
 
+       spin_lock(&conn->list_lock);
+       list_for_each_entry(cmnd, &conn->pdu_list, conn_list) {
+               set_cmnd_tmfabort(cmnd);
+               if (cmnd->lun) {
+                       ua_establish_for_session(session, cmnd->lun->lun, 0x47, 0x7f);
+                       iscsi_cmnd_set_sense(cmnd, UNIT_ATTENTION, 0x6e, 0x0);
+               }
+       }
+       spin_unlock(&conn->list_lock);
+
        nthread_wakeup(conn->session->target);
 }
 
 int conn_add(struct iscsi_session *session, struct conn_info *info)
 {
        struct iscsi_conn *conn;
-       int err = -EEXIST;
+       int err;
 
        conn = conn_lookup(session, info->cid);
        if (conn)
-               return err;
+               conn_close(conn);
 
-       return iet_conn_alloc(session, info);
+       err = iet_conn_alloc(session, info);
+       if (!err && conn)
+               err = -EEXIST;
+
+       return err;
 }
 
 int conn_del(struct iscsi_session *session, struct conn_info *info)
@@ -242,12 +260,3 @@ int conn_del(struct iscsi_session *session, struct conn_info *info)
 
        return 0;
 }
-
-/* target_lock() supposed to be held */
-void conn_del_all(struct iscsi_session *session)
-{
-       struct iscsi_conn *conn;
-
-       list_for_each_entry(conn, &session->conn_list, list)
-               conn_close(conn);
-}
index a492ce4..38951a9 100644 (file)
@@ -53,9 +53,9 @@ static int fileio_make_request(struct iet_volume *lu, struct tio *tio, int rw)
                set_fs(get_ds());
 
                if (rw == READ)
-                       ret = do_sync_read(filp, buf, count, &ppos);
+                       ret = vfs_read(filp, buf, count, &ppos);
                else
-                       ret = do_sync_write(filp, buf, count, &ppos);
+                       ret = vfs_write(filp, buf, count, &ppos);
 
                set_fs(oldfs);
 
@@ -82,6 +82,7 @@ static int fileio_sync(struct iet_volume *lu, struct tio *tio)
 
        if (tio) {
                ppos = (loff_t) tio->idx << PAGE_CACHE_SHIFT;
+               ppos += tio->offset;
                count = tio->size;
        } else {
                ppos = 0;
@@ -124,63 +125,18 @@ static int open_path(struct iet_volume *volume, const char *path)
        return err;
 }
 
-static int set_scsiid(struct iet_volume *volume, const char *id)
-{
-       size_t len;
-
-       if ((len = strlen(id)) > SCSI_ID_LEN - VENDOR_ID_LEN) {
-               eprintk("SCSI ID too long, %zd provided, %u max\n", len,
-                       SCSI_ID_LEN - VENDOR_ID_LEN);
-               return -EINVAL;
-       }
-
-       memcpy(volume->scsi_id + VENDOR_ID_LEN, id, len);
-
-       return 0;
-}
-
-static void gen_scsiid(struct iet_volume *volume, struct inode *inode)
-{
-       int i;
-       u32 *p;
-
-       strlcpy(volume->scsi_id, VENDOR_ID, VENDOR_ID_LEN);
-
-       for (i = VENDOR_ID_LEN; i < SCSI_ID_LEN; i++)
-               if (volume->scsi_id[i])
-                       return;
-
-       p = (u32 *) (volume->scsi_id + VENDOR_ID_LEN);
-       *(p + 0) = volume->target->trgt_param.target_type;
-       *(p + 1) = volume->target->tid;
-       *(p + 2) = (unsigned int) inode->i_ino;
-       *(p + 3) = (unsigned int) inode->i_sb->s_dev;
-}
-
-static int set_scsisn(struct iet_volume *volume, const char *sn)
-{
-       size_t len;
-
-       if ((len = strlen(sn)) > SCSI_SN_LEN) {
-               eprintk("SCSI SN too long, %zd provided, %u max\n", len,
-                       SCSI_SN_LEN);
-               return -EINVAL;
-       }
-       memcpy(volume->scsi_sn, sn, len);
-       return 0;
-}
-
 enum {
-       Opt_scsiid, Opt_scsisn, Opt_path, Opt_ignore, Opt_err,
+       opt_path, opt_ignore, opt_err,
 };
 
 static match_table_t tokens = {
-       {Opt_scsiid, "ScsiId=%s"},
-       {Opt_scsisn, "ScsiSN=%s"},
-       {Opt_path, "Path=%s"},
-       {Opt_ignore, "Type=%s"},
-       {Opt_ignore, "IOMode=%s"},
-       {Opt_err, NULL},
+       {opt_path, "path=%s"},
+       {opt_ignore, "scsiid=%s"},
+       {opt_ignore, "scsisn=%s"},
+       {opt_ignore, "type=%s"},
+       {opt_ignore, "iomode=%s"},
+       {opt_ignore, "blocksize=%s"},
+       {opt_err, NULL},
 };
 
 static int parse_fileio_params(struct iet_volume *volume, char *params)
@@ -194,29 +150,10 @@ static int parse_fileio_params(struct iet_volume *volume, char *params)
                int token;
                if (!*p)
                        continue;
+               iet_strtolower(p);
                token = match_token(p, tokens, args);
                switch (token) {
-               case Opt_scsiid:
-                       if (!(q = match_strdup(&args[0]))) {
-                               err = -ENOMEM;
-                               goto out;
-                       }
-                       err = set_scsiid(volume, q);
-                       kfree(q);
-                       if (err < 0)
-                               goto out;
-                       break;
-               case Opt_scsisn:
-                       if (!(q = match_strdup(&args[0]))) {
-                               err = -ENOMEM;
-                               goto out;
-                       }
-                       err = set_scsisn(volume, q);
-                       kfree(q);
-                       if (err < 0)
-                               goto out;
-                       break;
-               case Opt_path:
+               case opt_path:
                        if (info->path) {
                                iprintk("Target %s, LUN %u: "
                                        "duplicate \"Path\" param\n",
@@ -233,7 +170,7 @@ static int parse_fileio_params(struct iet_volume *volume, char *params)
                        if (err < 0)
                                goto out;
                        break;
-               case Opt_ignore:
+               case opt_ignore:
                        break;
                default:
                        iprintk("Target %s, LUN %u: unknown param %s\n",
@@ -285,8 +222,6 @@ static int fileio_attach(struct iet_volume *lu, char *args)
        }
        inode = p->filp->f_dentry->d_inode;
 
-       gen_scsiid(lu, inode);
-
        if (S_ISREG(inode->i_mode))
                ;
        else if (S_ISBLK(inode->i_mode))
@@ -296,7 +231,9 @@ static int fileio_attach(struct iet_volume *lu, char *args)
                goto out;
        }
 
-       lu->blk_shift = SECTOR_SIZE_BITS;
+       if (!lu->blk_shift)
+               lu->blk_shift = ilog2(IET_DEF_BLOCK_SIZE);
+
        lu->blk_cnt = inode->i_size >> lu->blk_shift;
 
        /* we're using the page cache */
index 620b3c4..174f0dc 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _IET_U_H
 #define _IET_U_H
 
-#define IET_VERSION_STRING     "1.4.19"
+#define IET_VERSION_STRING     "1.4.20.1"
 
 /* The maximum length of 223 bytes in the RFC. */
 #define ISCSI_NAME_LEN 256
@@ -9,14 +9,17 @@
 
 #define ISCSI_LISTEN_PORT      3260
 
-#define VENDOR_ID_LEN  8
-#define SCSI_ID_LEN    24
-#define SCSI_SN_LEN    16
+#define SCSI_ID_LEN    16
+#define SCSI_SN_LEN    (SCSI_ID_LEN * 2)
 
 #ifndef aligned_u64
 #define aligned_u64 unsigned long long __attribute__((aligned(8)))
 #endif
 
+struct module_info {
+       char version[128];
+};
+
 struct target_info {
        u32 tid;
        char name[ISCSI_NAME_LEN];
@@ -131,19 +134,18 @@ struct iet_event {
 
 #define NETLINK_IET    21
 
-#define ADD_TARGET _IOW('i', 0, struct target_info)
-#define DEL_TARGET _IOW('i', 1, struct target_info)
-#define START_TARGET _IO('i', 2)
-#define STOP_TARGET _IO('i', 3)
-#define ADD_VOLUME _IOW('i', 4, struct volume_info)
-#define DEL_VOLUME _IOW('i', 5, struct volume_info)
-#define ADD_SESSION _IOW('i', 6, struct session_info)
-#define DEL_SESSION _IOW('i', 7, struct session_info)
-#define GET_SESSION_INFO _IOWR('i', 8, struct session_info)
-#define ADD_CONN _IOW('i', 9, struct conn_info)
-#define DEL_CONN _IOW('i', 10, struct conn_info)
-#define GET_CONN_INFO _IOWR('i', 11, struct conn_info)
-#define ISCSI_PARAM_SET _IOW('i', 12, struct iscsi_param_info)
-#define ISCSI_PARAM_GET _IOWR('i', 13, struct iscsi_param_info)
+#define GET_MODULE_INFO _IOW('i', 20, struct module_info)
+#define ADD_TARGET _IOWR('i', 21, struct target_info)
+#define DEL_TARGET _IOW('i', 22, struct target_info)
+#define ADD_VOLUME _IOW('i', 24, struct volume_info)
+#define DEL_VOLUME _IOW('i', 25, struct volume_info)
+#define ADD_SESSION _IOW('i', 26, struct session_info)
+#define DEL_SESSION _IOW('i', 27, struct session_info)
+#define GET_SESSION_INFO _IOWR('i', 28, struct session_info)
+#define ADD_CONN _IOW('i', 29, struct conn_info)
+#define DEL_CONN _IOW('i', 30, struct conn_info)
+#define GET_CONN_INFO _IOWR('i', 31, struct conn_info)
+#define ISCSI_PARAM_SET _IOW('i', 32, struct iscsi_param_info)
+#define ISCSI_PARAM_GET _IOWR('i', 33, struct iscsi_param_info)
 
 #endif
index bd7fbd0..db7956a 100644 (file)
@@ -3,6 +3,7 @@
  * This code is licenced under the GPL.
  */
 
+#include <linux/ctype.h>
 #include "iscsi.h"
 
 #ifndef __IOTYPE_H__
@@ -26,4 +27,16 @@ extern struct iotype blockio;
 extern int iotype_init(void);
 extern void iotype_exit(void);
 
+/* For option parameter parsing.
+ * This is slightly iet specific: we only tolower() up to the first '='.
+ * Note that this changes *c _in place_, but our parsing
+ * routines copy the input to a scratch page before parsing anyways. */
+static inline void iet_strtolower(char *c)
+{
+       if (!c)
+               return;
+       for (; *c && *c != '='; c++)
+               *c = tolower(*c);
+}
+
 #endif
index 4f62b8b..05197f2 100644 (file)
@@ -345,6 +345,8 @@ void iscsi_cmnd_set_sense(struct iscsi_cmnd *cmnd, u8 sense_key, u8 asc,
        cmnd->sense_buf[7] = 6; // Additional sense length
        cmnd->sense_buf[12] = asc;
        cmnd->sense_buf[13] = ascq;
+
+       /* Call to ACA/UAI handler */
 }
 
 static struct iscsi_cmnd *create_sense_rsp(struct iscsi_cmnd *req,
@@ -534,10 +536,20 @@ static int check_cmd_sn(struct iscsi_cmnd *cmnd)
        u32 cmd_sn;
 
        cmnd->pdu.bhs.sn = cmd_sn = be32_to_cpu(cmnd->pdu.bhs.sn);
-       dprintk(D_GENERIC, "%d(%d)\n", cmd_sn, session->exp_cmd_sn);
-       if ((s32)(cmd_sn - session->exp_cmd_sn) >= 0)
+
+       dprintk(D_GENERIC, "cmd_sn(%u) exp_cmd_sn(%u) max_cmd_sn(%u)\n",
+               cmd_sn, session->exp_cmd_sn, session->max_cmd_sn);
+
+       if  (between(cmd_sn, session->exp_cmd_sn, session->max_cmd_sn))
+               return 0;
+       else if (cmnd_immediate(cmnd))
                return 0;
-       eprintk("sequence error (%x,%x)\n", cmd_sn, session->exp_cmd_sn);
+
+       eprintk("sequence error: cmd_sn(%u) exp_cmd_sn(%u) max_cmd_sn(%u)\n",
+               cmd_sn, session->exp_cmd_sn, session->max_cmd_sn);
+
+       set_cmnd_tmfabort(cmnd);
+
        return -ISCSI_REASON_PROTOCOL_ERROR;
 }
 
@@ -609,7 +621,8 @@ static int cmnd_insert_hash(struct iscsi_cmnd *cmnd)
        if (!err) {
                update_stat_sn(cmnd);
                err = check_cmd_sn(cmnd);
-       }
+       } else if (!cmnd_immediate(cmnd))
+               set_cmnd_tmfabort(cmnd);
 
        return err;
 }
@@ -826,15 +839,12 @@ static void send_r2t(struct iscsi_cmnd *req)
 
 static void scsi_cmnd_exec(struct iscsi_cmnd *cmnd)
 {
-       if (cmnd->r2t_length) {
-               if (!cmnd->is_unsolicited_data)
-                       send_r2t(cmnd);
+       assert(!cmnd->r2t_length);
+
+       if (cmnd->lun) {
+               iscsi_scsi_queuecmnd(cmnd);
        } else {
-               if (cmnd->lun) {
-                       iscsi_scsi_queuecmnd(cmnd);
-               } else {
-                       iscsi_device_queue_cmnd(cmnd);
-               }
+               iscsi_device_queue_cmnd(cmnd);
        }
 }
 
@@ -864,7 +874,7 @@ static int nop_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
        }
 
        if (cmnd_itt(cmnd) == cpu_to_be32(ISCSI_RESERVED_TAG)) {
-               if (!(cmnd->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE))
+               if (!cmnd_immediate(cmnd))
                        eprintk("%s\n", "initiator bug!");
                update_stat_sn(cmnd);
                err = check_cmd_sn(cmnd);
@@ -1093,6 +1103,8 @@ skip_data:
        return;
 }
 
+static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd);
+
 static void data_out_end(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
 {
        struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *) &cmnd->pdu.bhs;
@@ -1116,8 +1128,7 @@ static void data_out_end(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
        if (req->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
                if (req->flags & ISCSI_FLG_FINAL) {
                        scsi_cmnd->is_unsolicited_data = 0;
-                       if (!cmnd_pending(scsi_cmnd))
-                               scsi_cmnd_exec(scsi_cmnd);
+                       iscsi_session_push_cmnd(scsi_cmnd);
                }
        } else {
                /* TODO : proper error handling */
@@ -1132,7 +1143,7 @@ static void data_out_end(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
                if (scsi_cmnd->r2t_length == 0)
                        assert(list_empty(&scsi_cmnd->pdu_list));
 
-               scsi_cmnd_exec(scsi_cmnd);
+               iscsi_session_push_cmnd(scsi_cmnd);
        }
 
 out:
@@ -1140,35 +1151,64 @@ out:
        return;
 }
 
-static int __cmnd_abort(struct iscsi_cmnd *cmnd)
+static void __cmnd_abort(struct iscsi_cmnd *cmnd)
 {
+       if (cmnd_rxstart(cmnd))
+               set_cmnd_tmfabort(cmnd);
+
        if (cmnd_waitio(cmnd))
-               return -ISCSI_RESPONSE_UNKNOWN_TASK;
+               return;
 
        if (cmnd->conn->read_cmnd != cmnd)
                cmnd_release(cmnd, 1);
-       else if (cmnd_rxstart(cmnd))
-               set_cmnd_tmfabort(cmnd);
-       else
-               return -ISCSI_RESPONSE_UNKNOWN_TASK;
-
-       return 0;
 }
 
-static int cmnd_abort(struct iscsi_session *session, u32 itt)
+static int cmnd_abort(struct iscsi_session *session, struct iscsi_cmnd *req)
 {
+       struct iscsi_task_mgt_hdr *req_hdr =
+                               (struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
        struct iscsi_cmnd *cmnd;
-       int err =  -ISCSI_RESPONSE_UNKNOWN_TASK;
-
-       if ((cmnd = cmnd_find_hash(session, itt, ISCSI_RESERVED_TAG))) {
-               eprintk("%x %x %x %u %u %u %u\n", cmnd_itt(cmnd), cmnd_opcode(cmnd),
-                       cmnd->r2t_length, cmnd_scsicode(cmnd),
-                       cmnd_write_size(cmnd), cmnd->is_unsolicited_data,
-                       cmnd->outstanding_r2t);
-               err = __cmnd_abort(cmnd);
+
+       u32 min_cmd_sn = req_hdr->cmd_sn - session->max_queued_cmnds;
+
+       req_hdr->ref_cmd_sn = be32_to_cpu(req_hdr->ref_cmd_sn);
+
+       dprintk(D_GENERIC, "cmd_sn(%u) ref_cmd_sn(%u) min_cmd_sn(%u) rtt(%x)"
+               " lun(%d) cid(%u)\n",
+               req_hdr->cmd_sn, req_hdr->ref_cmd_sn, min_cmd_sn, req_hdr->rtt,
+               translate_lun(req_hdr->lun), req->conn->cid);
+
+       if (after(req_hdr->ref_cmd_sn, req_hdr->cmd_sn))
+               return ISCSI_RESPONSE_FUNCTION_REJECTED;
+
+       if (!(cmnd = cmnd_find_hash(session, req_hdr->rtt, ISCSI_RESERVED_TAG))) {
+               if (between(req_hdr->ref_cmd_sn, min_cmd_sn, req_hdr->cmd_sn))
+                       return ISCSI_RESPONSE_FUNCTION_COMPLETE;
+               else
+                       return ISCSI_RESPONSE_UNKNOWN_TASK;
        }
 
-       return err;
+       dprintk(D_GENERIC, "itt(%x) opcode(%x) scsicode(%x) lun(%d) cid(%u)\n",
+               cmnd_itt(cmnd), cmnd_opcode(cmnd), cmnd_scsicode(cmnd),
+               translate_lun(cmnd_hdr(cmnd)->lun), cmnd->conn->cid);
+
+       if (cmnd_opcode(cmnd) == ISCSI_OP_SCSI_TASK_MGT_MSG)
+               return ISCSI_RESPONSE_FUNCTION_REJECTED;
+
+       if (translate_lun(cmnd_hdr(cmnd)->lun) !=
+                                               translate_lun(req_hdr->lun))
+               return ISCSI_RESPONSE_FUNCTION_REJECTED;
+
+       if (cmnd->conn && test_bit(CONN_ACTIVE, &cmnd->conn->state)) {
+               if (cmnd->conn->cid != req->conn->cid)
+                       return ISCSI_RESPONSE_FUNCTION_REJECTED;
+       } else {
+               /* Switch cmnd connection allegiance */
+       }
+
+       __cmnd_abort(cmnd);
+
+       return ISCSI_RESPONSE_FUNCTION_COMPLETE;
 }
 
 static int target_reset(struct iscsi_cmnd *req, u32 lun, int all)
@@ -1187,7 +1227,8 @@ static int target_reset(struct iscsi_cmnd *req, u32 lun, int all)
 
                                if (all)
                                        __cmnd_abort(cmnd);
-                               else if (translate_lun(cmnd_hdr(cmnd)->lun) == lun)
+                               else if (translate_lun(cmnd_hdr(cmnd)->lun)
+                                                                       == lun)
                                        __cmnd_abort(cmnd);
                        }
                }
@@ -1214,7 +1255,12 @@ static void task_set_abort(struct iscsi_cmnd *req)
 
        list_for_each_entry(conn, &session->conn_list, list) {
                list_for_each_entry_safe(cmnd, tmp, &conn->pdu_list, conn_list) {
-                       if (cmnd != req)
+                       if (translate_lun(cmnd_hdr(cmnd)->lun)
+                                       != translate_lun(cmnd_hdr(req)->lun))
+                               continue;
+
+                       if (before(cmnd_hdr(cmnd)->cmd_sn,
+                                       cmnd_hdr(req)->cmd_sn))
                                __cmnd_abort(cmnd);
                }
        }
@@ -1274,7 +1320,7 @@ static void execute_task_management(struct iscsi_cmnd *req)
        struct iscsi_task_mgt_hdr *req_hdr = (struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
        struct iscsi_task_rsp_hdr *rsp_hdr;
        u32 lun;
-       int err, function = req_hdr->function & ISCSI_FUNCTION_MASK;
+       int function = req_hdr->function & ISCSI_FUNCTION_MASK;
 
        rsp = iscsi_cmnd_create_rsp_cmnd(req, 1);
        rsp_hdr = (struct iscsi_task_rsp_hdr *)&rsp->pdu.bhs;
@@ -1299,8 +1345,7 @@ static void execute_task_management(struct iscsi_cmnd *req)
 
        switch (function) {
        case ISCSI_FUNCTION_ABORT_TASK:
-               if ((err = cmnd_abort(conn->session, req_hdr->rtt)) < 0)
-                       rsp_hdr->response = -err;
+               rsp_hdr->response = cmnd_abort(conn->session, req);
                break;
        case ISCSI_FUNCTION_ABORT_TASK_SET:
                task_set_abort(req);
@@ -1443,7 +1488,7 @@ static void nop_in_tx_end(struct iscsi_cmnd *cmnd)
                conn->session->target->trgt_param.nop_timeout = t;
        }
 
-       dprintk(D_GENERIC, "NOP-In %p, %x: timer %p\n", cmnd, cmnd_ttt(cmnd),
+       dprintk(D_GENERIC, "NOP-In %p, %x: timer %p\n", cmnd, cmnd_ttt(cmnd),
                &cmnd->req->timer);
 
        set_cmnd_timer_active(cmnd->req);
@@ -1700,10 +1745,16 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
        struct list_head *entry;
        u32 cmd_sn;
 
+       if (cmnd->r2t_length) {
+               if (!cmnd->is_unsolicited_data)
+                       send_r2t(cmnd);
+               return;
+       }
+
        dprintk(D_GENERIC, "%p:%x %u,%u\n",
                cmnd, cmnd_opcode(cmnd), cmnd->pdu.bhs.sn, session->exp_cmd_sn);
 
-       if (cmnd->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE) {
+       if (cmnd_immediate(cmnd)) {
                iscsi_cmnd_exec(cmnd);
                return;
        }
@@ -1716,24 +1767,16 @@ static void iscsi_session_push_cmnd(struct iscsi_cmnd *cmnd)
 
                        if (list_empty(&session->pending_list))
                                break;
+
                        cmnd = list_entry(session->pending_list.next, struct iscsi_cmnd, list);
                        if (cmnd->pdu.bhs.sn != cmd_sn)
                                break;
-/*                     eprintk("find out-of-order %x %u %u\n", */
-/*                             cmnd_itt(cmnd), cmd_sn, cmnd->pdu.bhs.sn); */
+
                        list_del_init(&cmnd->list);
                        clear_cmnd_pending(cmnd);
                }
        } else {
-/*             eprintk("out-of-order %x %u %u\n", */
-/*                     cmnd_itt(cmnd), cmd_sn, session->exp_cmd_sn); */
-
                set_cmnd_pending(cmnd);
-               if (before(cmd_sn, session->exp_cmd_sn)) /* close the conn */
-                       eprintk("unexpected cmd_sn (%u,%u)\n", cmd_sn, session->exp_cmd_sn);
-
-               if (after(cmd_sn, session->exp_cmd_sn + session->max_queued_cmnds))
-                       eprintk("too large cmd_sn (%u,%u)\n", cmd_sn, session->exp_cmd_sn);
 
                list_for_each(entry, &session->pending_list) {
                        struct iscsi_cmnd *tmp = list_entry(entry, struct iscsi_cmnd, list);
index 92ce252..e9d37a4 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __ISCSI_H__
 #define __ISCSI_H__
 
+#include <linux/blkdev.h>
 #include <linux/completion.h>
 #include <linux/pagemap.h>
 #include <linux/seq_file.h>
@@ -92,6 +93,8 @@ struct worker_thread_info {
        struct list_head work_queue;
 
        wait_queue_head_t wthread_sleep;
+
+       struct io_context *wthread_ioc;
 };
 
 struct iscsi_cmnd;
@@ -127,7 +130,6 @@ struct iscsi_target {
        struct worker_thread_info * wthread_info;
 
        struct semaphore target_sem;
-       struct completion *done;
 };
 
 struct iscsi_queue {
@@ -149,7 +151,7 @@ struct iet_volume {
        struct iscsi_queue queue;
 
        u8 scsi_id[SCSI_ID_LEN];
-       u8 scsi_sn[SCSI_SN_LEN];
+       u8 scsi_sn[SCSI_SN_LEN + 1];
 
        u32 blk_shift;
        u64 blk_cnt;
@@ -336,7 +338,6 @@ extern void send_nop_in(struct iscsi_conn *);
 extern struct iscsi_conn *conn_lookup(struct iscsi_session *, u16);
 extern int conn_add(struct iscsi_session *, struct conn_info *);
 extern int conn_del(struct iscsi_session *, struct conn_info *);
-extern void conn_del_all(struct iscsi_session *);
 extern int conn_free(struct iscsi_conn *);
 extern void conn_close(struct iscsi_conn *);
 extern void conn_info_show(struct seq_file *, struct iscsi_session *);
@@ -377,7 +378,6 @@ extern struct file_operations session_seq_fops;
 extern struct iscsi_session *session_lookup(struct iscsi_target *, u64);
 extern int session_add(struct iscsi_target *, struct session_info *);
 extern int session_del(struct iscsi_target *, u64);
-extern void session_del_all(struct iscsi_target *);
 
 /* volume.c */
 extern struct file_operations volume_seq_fops;
@@ -464,8 +464,11 @@ static inline void iscsi_cmnd_set_length(struct iscsi_pdu *pdu)
 #define cmnd_itt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.itt)
 #define cmnd_opcode(cmnd) ((cmnd)->pdu.bhs.opcode & ISCSI_OPCODE_MASK)
 #define cmnd_scsicode(cmnd) cmnd_hdr(cmnd)->scb[0]
+#define cmnd_immediate(cmnd) ((cmnd)->pdu.bhs.opcode & ISCSI_OP_IMMEDIATE)
 
-#define        SECTOR_SIZE_BITS        9
+/* default and maximum scsi level block sizes */
+#define IET_DEF_BLOCK_SIZE     512
+#define IET_MAX_BLOCK_SIZE     4096
 
 enum cmnd_flags {
        CMND_hashed,
index ec54ead..52cd69a 100644 (file)
@@ -209,6 +209,7 @@ static int recv(struct iscsi_conn *conn)
        hdigest = conn->hdigest_type & DIGEST_NONE ? 0 : 1;
        ddigest = conn->ddigest_type & DIGEST_NONE ? 0 : 1;
 
+next_state:
        switch (conn->read_state) {
        case RX_INIT_BHS:
                assert(!cmnd);
@@ -270,7 +271,7 @@ static int recv(struct iscsi_conn *conn)
                return res;
 
        if (conn->read_state != RX_END)
-               return res;
+               goto next_state;
 
        if (conn->read_size) {
                eprintk("%d %x %d\n", res, cmnd_opcode(cmnd), conn->read_size);
@@ -525,6 +526,7 @@ static int send(struct iscsi_conn *conn)
 
        ddigest = conn->ddigest_type != DIGEST_NONE ? 1 : 0;
 
+next_state:
        switch (conn->write_state) {
        case TX_INIT:
                assert(!cmnd);
@@ -555,7 +557,7 @@ static int send(struct iscsi_conn *conn)
                return res;
 
        if (conn->write_state != TX_END)
-               return res;
+               goto next_state;
 
        if (conn->write_size) {
                eprintk("%d %x %u\n", res, cmnd_opcode(cmnd), conn->write_size);
index cfa5899..f64b18c 100644 (file)
 #include "iscsi_dbg.h"
 #include "iotype.h"
 
-struct nullio_data {
-       u64 sectors;
-};
-
 enum {
-       Opt_sectors, Opt_ignore, Opt_err,
+       opt_blk_cnt, opt_ignore, opt_err,
 };
 
 static match_table_t tokens = {
-       {Opt_sectors, "Sectors=%u"},
-       {Opt_ignore, "Type=%s"},
-       {Opt_err, NULL},
+       /* alias for compatibility with existing setups and documentation */
+       {opt_blk_cnt, "sectors=%u"},
+       /* but actually it is the scsi block count, now that we can
+        * specify the block size. */
+       {opt_blk_cnt, "blocks=%u"},
+       {opt_ignore, "scsiid=%s"},
+       {opt_ignore, "scsisn=%s"},
+       {opt_ignore, "blocksize=%s"},
+       {opt_ignore, "type=%s"},
+       {opt_err, NULL},
 };
 
 static int parse_nullio_params(struct iet_volume *volume, char *params)
 {
        int err = 0;
        char *p, *q;
-       struct nullio_data *data = volume->private;
 
        while ((p = strsep(&params, ",")) != NULL) {
                substring_t args[MAX_OPT_ARGS];
                int token;
                if (!*p)
                        continue;
+               iet_strtolower(p);
                token = match_token(p, tokens, args);
                switch (token) {
-               case Opt_sectors:
+               case opt_blk_cnt:
                        q = match_strdup(&args[0]);
                        if (!q)
                                return -ENOMEM;
-                       data->sectors = simple_strtoull(q, NULL, 10);
+                       volume->blk_cnt = simple_strtoull(q, NULL, 10);
                        kfree(q);
                        break;
-               case Opt_ignore:
+               case opt_ignore:
                        break;
                default:
                        eprintk("Unknown %s\n", p);
@@ -63,35 +66,23 @@ static int parse_nullio_params(struct iet_volume *volume, char *params)
 
 static void nullio_detach(struct iet_volume *lu)
 {
-       struct nullio_data *p = lu->private;
-
-       kfree(p);
-       lu->private = NULL;
 }
 
 static int nullio_attach(struct iet_volume *lu, char *args)
 {
        int err = 0;
-       struct nullio_data *p;
-
-       if (lu->private) {
-               printk("already attached ? %d\n", lu->lun);
-               return -EBUSY;
-       }
-
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
-       if (!p)
-               return -ENOMEM;
-
-       lu->private = p;
 
        if ((err = parse_nullio_params(lu, args)) < 0) {
                eprintk("%d\n", err);
                goto out;
        }
 
-       lu->blk_shift = SECTOR_SIZE_BITS;
-       lu->blk_cnt = (p->sectors = p->sectors ? : 1 << 27); /* 64 GB */
+       if (!lu->blk_shift)
+               lu->blk_shift = ilog2(IET_DEF_BLOCK_SIZE);
+
+       /* defaults to 64 GiB */
+       if (!lu->blk_cnt)
+               lu->blk_cnt = 1 << (36 - lu->blk_shift);
 
 out:
        if (err < 0)
@@ -99,16 +90,9 @@ out:
        return err;
 }
 
-void nullio_show(struct iet_volume *lu, struct seq_file *seq)
-{
-       struct nullio_data *p = lu->private;
-       seq_printf(seq, " sectors:%llu\n", p->sectors);
-}
-
 struct iotype nullio =
 {
        .name = "nullio",
        .attach = nullio_attach,
        .detach = nullio_detach,
-       .show = nullio_show,
 };
index 57ad301..482d00c 100644 (file)
@@ -43,7 +43,7 @@ static void sess_param_check(struct iscsi_param_info *info)
 {
        u32 *iparam = info->session_param;
 
-       CHECK_PARAM(info, iparam, max_connections, 1, 1);
+       CHECK_PARAM(info, iparam, max_connections, 1, 65535);
        CHECK_PARAM(info, iparam, max_recv_data_length, 512,
                    (u32) ((ISCSI_CONN_IOV_MAX - 1) * PAGE_CACHE_SIZE));
        CHECK_PARAM(info, iparam, max_xmit_data_length, 512,
index 6365373..a566d8b 100644 (file)
@@ -124,40 +124,30 @@ int session_add(struct iscsi_target *target, struct session_info *info)
 int session_del(struct iscsi_target *target, u64 sid)
 {
        struct iscsi_session *session;
+       struct iet_volume *volume;
 
        session = session_lookup(target, sid);
        if (!session)
                return -ENOENT;
 
        if (!list_empty(&session->conn_list)) {
-               eprintk("%llu still have connections\n", (unsigned long long) session->sid);
-               return -EBUSY;
-       }
+               DECLARE_COMPLETION_ONSTACK(done);
+               struct iscsi_conn *conn;
 
-       return session_free(session);
-}
-
-void session_del_all(struct iscsi_target *target)
-{
-       DECLARE_COMPLETION_ONSTACK(done);
-       struct iscsi_session *sess;
+               session->done = &done;
+               list_for_each_entry(conn, &session->conn_list, list)
+                       conn_close(conn);
 
-       while (!list_empty(&target->session_list)) {
-               init_completion(&done);
-               target_lock(target, 0);
-               sess = list_entry(target->session_list.next, struct
-                                 iscsi_session, list);
-               sess->done = &done;
-               conn_del_all(sess);
                target_unlock(target);
                wait_for_completion(&done);
                target_lock(target, 0);
-               session_free(sess);
-               target_unlock(target);
        }
 
-       if (target->done)
-               complete(target->done);
+       list_for_each_entry(volume, &target->volumes, list){
+               volume_release(volume, sid, 0);
+       }
+
+       return session_free(session);
 }
 
 static void iet_session_info_show(struct seq_file *seq, struct iscsi_target *target)
index 15c0715..43326dc 100644 (file)
@@ -192,21 +192,23 @@ out:
 
 int target_add(struct target_info *info)
 {
-       int err = -EEXIST;
        u32 tid = info->tid;
+       int err;
 
-       down(&target_list_sem);
+       err = down_interruptible(&target_list_sem);
+       if (err < 0)
+               return err;
 
        if (nr_targets > MAX_NR_TARGETS) {
                err = -EBUSY;
                goto out;
        }
 
-       if (__target_lookup_by_name(info->name))
-               goto out;
-
-       if (tid && __target_lookup_by_id(tid))
+       if (__target_lookup_by_name(info->name) || 
+                       (tid && __target_lookup_by_id(tid))) {
+               err = -EEXIST;
                goto out;
+       }
 
        if (!tid) {
                do {
@@ -217,7 +219,8 @@ int target_add(struct target_info *info)
                tid = next_target_id;
        }
 
-       if (!(err = iscsi_target_create(info, tid)))
+       err = iscsi_target_create(info, tid);
+       if (!err)
                nr_targets++;
 out:
        up(&target_list_sem);
@@ -246,13 +249,24 @@ static void target_destroy(struct iscsi_target *target)
 }
 
 /* @locking: target_list_sem must be locked */
-int __target_del(struct iscsi_target *target)
+static int __target_del(struct iscsi_target *target)
 {
+       int err;
+
        target_lock(target, 0);
 
        if (!list_empty(&target->session_list)) {
-               target_unlock(target);
-               return -EBUSY;
+               struct iscsi_session *session;
+
+               do {
+                       session = list_entry(target->session_list.next,
+                                               struct iscsi_session, list);
+                       err = session_del(target, session->sid);
+                       if (err < 0) {
+                               target_unlock(target);
+                               return err;
+                       }
+               } while (!list_empty(&target->session_list));
        }
 
        list_del(&target->t_list);
@@ -260,13 +274,16 @@ int __target_del(struct iscsi_target *target)
 
        target_unlock(target);
        target_destroy(target);
+
        return 0;
 }
 
 int target_del(u32 id)
 {
        struct iscsi_target *target;
-       int err = down_interruptible(&target_list_sem);
+       int err;
+
+       err = down_interruptible(&target_list_sem);
        if (err < 0)
                return err;
 
@@ -277,15 +294,16 @@ int target_del(u32 id)
        }
 
        err = __target_del(target);
- out:
+out:
        up(&target_list_sem);
+
        return err;
 }
 
 void target_del_all(void)
 {
-       DECLARE_COMPLETION_ONSTACK(done);
        struct iscsi_target *target, *tmp;
+       int err;
 
        down(&target_list_sem);
 
@@ -293,11 +311,10 @@ void target_del_all(void)
                iprintk("Removing all connections, sessions and targets\n");
 
        list_for_each_entry_safe(target, tmp, &target_list, t_list) {
-               init_completion(&done);
-               target->done = &done;
-               session_del_all(target);
-               wait_for_completion(&done);
-               __target_del(target);
+               u32 tid = target->tid;
+               err =__target_del(target);
+               if (err)
+                       eprintk("Error deleteing target %u: %d\n", tid, err);
        }
 
        next_target_id = 0;
index 694edb2..1f7693c 100644 (file)
@@ -193,11 +193,11 @@ static void build_inquiry_response(struct iscsi_cmnd *cmnd)
                data[7] = 0x02;
                memset(data + 8, 0x20, 28);
                memcpy(data + 8,
-                      VENDOR_ID, min_t(size_t, strlen(VENDOR_ID), 8));
+                       VENDOR_ID, min_t(size_t, strlen(VENDOR_ID), 8));
                memcpy(data + 16,
-                      PRODUCT_ID, min_t(size_t, strlen(PRODUCT_ID), 16));
+                       PRODUCT_ID, min_t(size_t, strlen(PRODUCT_ID), 16));
                memcpy(data + 32,
-                      PRODUCT_REV, min_t(size_t, strlen(PRODUCT_REV), 4));
+                       PRODUCT_REV, min_t(size_t, strlen(PRODUCT_REV), 4));
                data[58] = 0x03;
                data[59] = 0x20;
                data[60] = 0x09;
@@ -217,35 +217,41 @@ static void build_inquiry_response(struct iscsi_cmnd *cmnd)
                        tio_set(tio, 7, 0);
                        err = 0;
                } else if (scb[2] == 0x80) {
-                       int len = (cmnd->lun && strlen(cmnd->lun->scsi_sn)) ?
-                               SCSI_SN_LEN : 4;
+                       u32 len = 4;
+
+                       if (cmnd->lun) {
+                               if (strlen(cmnd->lun->scsi_sn) <= 16)
+                                       len = 16;
+                               else
+                                       len = SCSI_SN_LEN;
+                       }
 
                        data[1] = 0x80;
                        data[3] = len;
                        memset(data + 4, 0x20, len);
+                       if (cmnd->lun) {
+                               size_t offset = len -
+                                               strlen(cmnd->lun->scsi_sn);
+                               memcpy(data + 4 + offset, cmnd->lun->scsi_sn,
+                                               strlen(cmnd->lun->scsi_sn));
+                       }
                        tio_set(tio, len + 4, 0);
                        err = 0;
-
-                       if (len == SCSI_SN_LEN) {
-                               char *p, *q;
-
-                               p = data + 4 + len - 1;
-                               q = cmnd->lun->scsi_sn + len - 1;
-
-                               for (; len > 0; len--, q--)
-                                       if (isascii(*q) && isprint(*q))
-                                               *(p--) = *q;
-                       }
                } else if (scb[2] == 0x83) {
-                       u32 len = SCSI_ID_LEN * sizeof(u8);
+                       u32 len = SCSI_ID_LEN + 8;
 
                        data[1] = 0x83;
                        data[3] = len + 4;
                        data[4] = 0x1;
                        data[5] = 0x1;
                        data[7] = len;
-                       if (cmnd->lun) /* We need this ? */
-                               memcpy(data + 8, cmnd->lun->scsi_id, len);
+                       if (cmnd->lun) { /* We need this ? */
+                               memset(data + 8, 0x00, 8);
+                               memcpy(data + 8, VENDOR_ID, 
+                                       min_t(size_t, strlen(VENDOR_ID), 8));
+                               memcpy(data + 16, cmnd->lun->scsi_id,
+                                                               SCSI_ID_LEN);
+                       }
                        tio_set(tio, len + 8, 0);
                        err = 0;
                }
@@ -432,9 +438,19 @@ static void build_reserve_response(struct iscsi_cmnd *cmnd)
 
 static void build_release_response(struct iscsi_cmnd *cmnd)
 {
-       if (volume_release(cmnd->lun,
-                          cmnd->conn->session->sid, 0))
+       int ret = volume_release(cmnd->lun,
+                                cmnd->conn->session->sid, 0);
+       switch (ret) {
+       case -ENOENT:
+               /* Logical Unit Not Supported (?) */
+               iscsi_cmnd_set_sense(cmnd, ILLEGAL_REQUEST, 0x25, 0x0);
+               break;
+       case -EBUSY:
                cmnd->status = SAM_STAT_RESERVATION_CONFLICT;
+               break;
+       default:
+               break;
+       }
 }
 
 static void build_reservation_conflict_response(struct iscsi_cmnd *cmnd)
@@ -475,8 +491,9 @@ static int disk_check_reservation(struct iscsi_cmnd *cmnd)
 {
        struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd);
 
-       if (is_volume_reserved(cmnd->lun,
-                              cmnd->conn->session->sid)) {
+       int ret = is_volume_reserved(cmnd->lun,
+                                    cmnd->conn->session->sid);
+       if (ret == -EBUSY) {
                switch (req->scb[0]) {
                case INQUIRY:
                case RELEASE:
index db08169..c4ba4c2 100644 (file)
@@ -109,6 +109,7 @@ void ua_establish_for_session(struct iscsi_session *sess, u32 lun,
 {
        struct list_head *l = &sess->ua_hash[ua_hashfn(lun)];
        struct ua_entry *ua = kmem_cache_alloc(ua_cache, GFP_KERNEL);
+       struct ua_entry *e;
 
        if (!ua) {
                eprintk("%s", "Failed to alloc ua");
@@ -119,8 +120,19 @@ void ua_establish_for_session(struct iscsi_session *sess, u32 lun,
        ua->ascq = ascq;
        ua->lun = lun;
        ua->session = sess;
+       INIT_LIST_HEAD(&ua->entry);
 
        spin_lock(&sess->ua_hash_lock);
+       /* One UA per occurrence of an event */
+       list_for_each_entry(e, l, entry) {
+               if (e->session == sess && e->lun == lun &&
+                               e->asc == asc && e->ascq == ascq &&
+                               e->session->exp_cmd_sn == sess->exp_cmd_sn) {
+                       spin_unlock(&sess->ua_hash_lock);
+                       ua_free(ua);
+                       return;
+               }
+       }
        list_add_tail(&ua->entry, l);
        spin_unlock(&sess->ua_hash_lock);
 
index ca0d9ca..6abe16b 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/types.h>
 #include <linux/parser.h>
+#include <linux/log2.h>
 
 #include "iscsi.h"
 #include "iscsi_dbg.h"
@@ -23,25 +24,108 @@ struct iet_volume *volume_lookup(struct iscsi_target *target, u32 lun)
 }
 
 enum {
-       Opt_type,
-       Opt_iomode,
-       Opt_err,
+       opt_type,
+       opt_iomode,
+       opt_scsiid,
+       opt_scsisn,
+       opt_blk_size,
+       opt_err,
 };
 
 static match_table_t tokens = {
-       {Opt_type, "Type=%s"},
-       {Opt_iomode, "IOMode=%s"},
-       {Opt_err, NULL},
+       {opt_type, "type=%s"},
+       {opt_iomode, "iomode=%s"},
+       {opt_scsiid, "scsiid=%s"},
+       {opt_scsisn, "scsisn=%s"},
+       {opt_blk_size, "blocksize=%u"},
+       {opt_err, NULL},
 };
 
-static int set_iotype(struct iet_volume *volume, char *params)
+static int set_scsiid(struct iet_volume *volume, const char *id)
+{
+       size_t len;
+
+       if ((len = strlen(id)) > SCSI_ID_LEN) {
+               eprintk("SCSI ID too long, %zd provided, %u max\n", len,
+                                                               SCSI_ID_LEN);
+               return -EINVAL;
+       }
+
+       memcpy(volume->scsi_id, id, len);
+
+       return 0;
+}
+
+static int set_scsisn(struct iet_volume *volume, const char *sn)
+{
+       size_t len;
+       int i;
+
+       if ((len = strlen(sn)) > SCSI_SN_LEN) {
+               eprintk("SCSI SN too long, %zd provided, %u max\n", len,
+                                                               SCSI_SN_LEN);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < len; i++) {
+               if (!isascii(*(sn + i)) || !isprint(*(sn + i))) {
+                       eprintk("invalid characters in SCSI SN, %s\n",
+                               "only printable ascii characters allowed!");
+                       return -EINVAL;
+               }
+       }
+
+       memcpy(volume->scsi_sn, sn, len);
+
+       return 0;
+}
+
+/* Generate a MD5 hash of the target IQN and LUN number */
+static void gen_scsiid(struct iet_volume *volume)
+{
+       struct hash_desc hash;
+
+       hash.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
+       hash.flags = 0;
+
+       if (hash.tfm) {
+               struct scatterlist sg[2];
+               unsigned int nbytes = 0;
+
+               sg_init_table(sg, 2);
+
+               sg_set_buf(&sg[0], volume->target->name,
+                                       strlen(volume->target->name));
+               nbytes += strlen(volume->target->name);
+
+               sg_set_buf(&sg[1], &volume->lun, sizeof(volume->lun));
+               nbytes += sizeof(volume->lun);
+
+               crypto_hash_init(&hash);
+               crypto_hash_update(&hash, sg, nbytes);
+               crypto_hash_final(&hash, volume->scsi_id);
+
+               crypto_free_hash(hash.tfm);
+       } else {
+               /* If no MD5 available set ID to TID and LUN */
+               memcpy(volume->scsi_id, &volume->target->tid,
+                                               sizeof(volume->target->tid));
+               memcpy(volume->scsi_id + sizeof(volume->target->tid),
+                                       &volume->lun, sizeof(volume->lun));
+       }       
+
+}
+
+static int parse_volume_params(struct iet_volume *volume, char *params)
 {
        int err = 0;
+       unsigned blk_sz;
        substring_t args[MAX_OPT_ARGS];
        char *p, *argp = NULL, *buf = (char *) get_zeroed_page(GFP_USER);
 
        if (!buf)
                return -ENOMEM;
+
        strncpy(buf, params, PAGE_CACHE_SIZE);
 
        while ((p = strsep(&buf, ",")) != NULL) {
@@ -49,22 +133,65 @@ static int set_iotype(struct iet_volume *volume, char *params)
 
                if (!*p)
                        continue;
+               iet_strtolower(p);
                token = match_token(p, tokens, args);
                switch (token) {
-               case Opt_type:
-                       if (!(argp = match_strdup(&args[0])))
+               case opt_type:
+                       argp = match_strdup(&args[0]);
+                       if (!argp) {
                                err = -ENOMEM;
-                       if (argp && !(volume->iotype = get_iotype(argp)))
+                               break;
+                       }
+                       if (!(volume->iotype = get_iotype(argp)))
                                err = -ENOENT;
                        kfree(argp);
                        break;
-               case Opt_iomode:
-                       if (!(argp = match_strdup(&args[0])))
+               case opt_iomode:
+                       argp = match_strdup(&args[0]);
+                       if (!argp) {
                                err = -ENOMEM;
-                       if (argp && !strcmp(argp, "ro"))
+                               break;
+                       }
+                       if (!strcmp(argp, "ro"))
                                SetLUReadonly(volume);
-                       else if (argp && !strcmp(argp, "wb"))
+                       else if (!strcmp(argp, "wb"))
                                SetLUWCache(volume);
+                       else if (strcmp(argp, "wt"))
+                               err = -EINVAL;
+                       kfree(argp);
+                       break;
+               case opt_scsiid:
+                       argp = match_strdup(&args[0]);
+                       if (!argp) {
+                               err = -ENOMEM;
+                               break;
+                       }
+                       err = set_scsiid(volume, argp);
+                       kfree(argp);
+                       break;
+               case opt_scsisn:
+                       argp = match_strdup(&args[0]);
+                       if (!argp) {
+                               err = -ENOMEM;
+                               break;
+                       }
+                       err = set_scsisn(volume, argp);
+                       kfree(argp);
+                       break;
+               case opt_blk_size:
+                       argp = match_strdup(&args[0]);
+                       if (!argp) {
+                               err = -ENOMEM;
+                               break;
+                       }
+                       blk_sz = simple_strtoull(argp, NULL, 10);
+                       if (is_power_of_2(blk_sz) &&
+                           512 <= blk_sz && blk_sz <= IET_MAX_BLOCK_SIZE)
+                               volume->blk_shift = ilog2(blk_sz);
+                       else {
+                               eprintk("invalid BlockSize=%u\n", blk_sz);
+                               err = -EINVAL;
+                       }
                        kfree(argp);
                        break;
                default:
@@ -115,7 +242,7 @@ int volume_add(struct iscsi_target *target, struct volume_info *info)
                goto free_args;
        }
 
-       ret = set_iotype(volume, args);
+       ret = parse_volume_params(volume, args);
        if (ret < 0)
                goto free_args;
 
@@ -123,6 +250,17 @@ int volume_add(struct iscsi_target *target, struct volume_info *info)
        if (ret < 0)
                goto free_args;
 
+       if (!volume->scsi_id[0])
+               gen_scsiid(volume);
+
+       if (!volume->scsi_sn[0]) {
+               int i;
+
+               for (i = 0; i < SCSI_ID_LEN; i++)
+                       snprintf(volume->scsi_sn + (i * 2), 3, "%02x",
+                                                       volume->scsi_id[i]);
+       }
+
        INIT_LIST_HEAD(&volume->queue.wait_list);
        spin_lock_init(&volume->queue.queue_lock);
        spin_lock_init(&volume->reserve_lock);
@@ -193,35 +331,54 @@ void volume_put(struct iet_volume *volume)
 
 int volume_reserve(struct iet_volume *volume, u64 sid)
 {
+       int err = 0;
+
        if (!volume)
                return -ENOENT;
 
        spin_lock(&volume->reserve_lock);
-       if (volume->reserve_sid && volume->reserve_sid != sid) {
-               spin_unlock(&volume->reserve_lock);
-               return -EBUSY;
-       }
+       if (volume->reserve_sid && volume->reserve_sid != sid)
+               err = -EBUSY;
+       else
+               volume->reserve_sid = sid;
 
-       volume->reserve_sid = sid;
        spin_unlock(&volume->reserve_lock);
-
-       return 0;
+       return err;
 }
 
 int is_volume_reserved(struct iet_volume *volume, u64 sid)
 {
-       if (!volume || !volume->reserve_sid || volume->reserve_sid == sid)
-               return 0;
+       int err = 0;
 
-       return -EBUSY;
+       if (!volume)
+               return -ENOENT;
+
+       spin_lock(&volume->reserve_lock);
+       if (!volume->reserve_sid || volume->reserve_sid == sid)
+               err = 0;
+       else
+               err = -EBUSY;
+
+       spin_unlock(&volume->reserve_lock);
+       return err;
 }
 
 int volume_release(struct iet_volume *volume, u64 sid, int force)
 {
+       int err = 0;
+
+       if (!volume)
+               return -ENOENT;
+
+       spin_lock(&volume->reserve_lock);
+
        if (force || volume->reserve_sid == sid)
                volume->reserve_sid = 0;
+       else
+               err = -EBUSY;
 
-       return 0;
+       spin_unlock(&volume->reserve_lock);
+       return err;
 }
 
 static void iet_volume_info_show(struct seq_file *seq, struct iscsi_target *target)
@@ -238,6 +395,8 @@ static void iet_volume_info_show(struct seq_file *seq, struct iscsi_target *targ
                else
                        seq_printf(seq, " iomode:wt");
 
+               seq_printf(seq, " blocks:%llu blocksize:%u",
+                       volume->blk_cnt, 1 << volume->blk_shift);
                if (volume->iotype->show)
                        volume->iotype->show(volume, seq);
                else
index b49ddb7..997a3d6 100644 (file)
@@ -67,6 +67,15 @@ static int worker_thread(void *arg)
        struct iscsi_conn *conn;
        DECLARE_WAITQUEUE(wait, current);
 
+       get_io_context(GFP_KERNEL, -1);
+
+       if (!current->io_context)
+               eprintk("%s\n", "Failed to get IO context");
+       else if (info->wthread_ioc)
+               copy_io_context(&current->io_context, &info->wthread_ioc);
+       else
+               info->wthread_ioc = current->io_context;
+
        add_wait_queue(&info->wthread_sleep, &wait);
 
        __set_current_state(TASK_RUNNING);
@@ -74,12 +83,15 @@ static int worker_thread(void *arg)
                while (!list_empty(&info->work_queue) &&
                       (cmnd = get_ready_cmnd(info))) {
                        conn = cmnd->conn;
-                       cmnd_execute(cmnd);
+                       if (cmnd_tmfabort(cmnd))
+                               cmnd_release(cmnd, 1);
+                       else
+                               cmnd_execute(cmnd);
                        assert(conn);
                        atomic_dec(&conn->nr_busy_cmnds);
                }
 
-               __set_current_state(TASK_INTERRUPTIBLE);
+               set_current_state(TASK_INTERRUPTIBLE);
                if (list_empty(&info->work_queue))
                        schedule();
 
@@ -88,6 +100,16 @@ static int worker_thread(void *arg)
 
        remove_wait_queue(&info->wthread_sleep, &wait);
 
+       if (current->io_context) {
+               struct io_context *ioc = current->io_context;
+
+               task_lock(current);
+               current->io_context = NULL;
+               task_unlock(current);
+
+               put_io_context(ioc);
+       }
+
        return 0;
 }
 
@@ -138,6 +160,7 @@ int wthread_init(struct worker_thread_info *info)
        spin_lock_init(&info->wthread_lock);
 
        info->nr_running_wthreads = 0;
+       info->wthread_ioc = NULL;
 
        INIT_LIST_HEAD(&info->work_queue);
        INIT_LIST_HEAD(&info->wthread_list);