- Fixed problems with big amount of LUNs. Tested on 1500 LUNS
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Mon, 13 Nov 2006 17:14:19 +0000 (17:14 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Mon, 13 Nov 2006 17:14:19 +0000 (17:14 +0000)
 - Docs update

git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@32 d57e44dd-8a1f-0410-8b47-8ef2f437770f

scst/README
scst/src/dev_handlers/scst_fileio.c
scst/src/scst_lib.c
scst/src/scst_proc.c
scst/src/scst_targ.c

index 06d4da4..6d52b3e 100644 (file)
@@ -323,20 +323,20 @@ subdirectories "disk_fileio" and "cdrom_fileio". They have similar layout:
         way as "*_perf" handlers.
 
       - NV_CACHE - enables "non-volatile cache" mode. In this mode it is
-        assumed that the target has GOOD uninterruptable power supply
-       and software/hardware bug free, i.e. all data from the target's
-       cache are guaranteed sooner or later to go to the media, hence
-       all data synchronization with media operations, like
-       SYNCHRONIZE_CACHE, are ignored (BTW, so violating SCSI standard)
-       in order to bring a bit more performance. Use with extreme
-       caution, since in this mode after a crash of the target
-       journaled file systems don't guarantee the consistency after
-       journal recovery, therefore manual fsck MUST be ran. The main
-       intent for it is to determine the performance impact caused by
-       the cache synchronization. Note, that since usually the journal
-       barrier protection (see "IMPORTANT" below) turned off, enabling
-       NV_CACHE could change nothing, since no data synchronization
-       with media operations will go from the initiator.
+        assumed that the target has GOOD UPS and software/hardware bug
+       free, i.e. all data from the target's cache are guaranteed
+       sooner or later to go to the media, hence all data
+       synchronization with media operations, like SYNCHRONIZE_CACHE,
+       are ignored (BTW, so violating SCSI standard) in order to bring
+       a bit more performance. Use with extreme caution, since in this
+       mode after a crash of the target journaled file systems don't
+       guarantee the consistency after journal recovery, therefore
+       manual fsck MUST be ran. The main intent for it is to determine
+       the performance impact caused by the cache synchronization.
+       Note, that since usually the journal barrier protection (see
+       "IMPORTANT" below) turned off, enabling NV_CACHE could change
+       nothing, since no data synchronization with media operations
+       will go from the initiator.
     
     * "close NAME" - closes device "NAME".
 
@@ -349,32 +349,36 @@ IMPORTANT: By default for performance reasons FILEIO devices use write back
 =========  caching policy. This is generally safe from the consistence of
            journaled file systems, laying over them, point of view, but
           your unsaved cached data will be lost in case of
-          power/hardware/software faulure, so you must supply your
+          power/hardware/software failure, so you must supply your
           target server with some kind of UPS or disable write back
           caching using WRITE_THROUGH flag. You also should note, that
           the file systems journaling over write back caching enabled
-          devices works reliably *ONLY* if it uses some kind of data
-          protection barriers (i.e. after writing journaling data some
-          kind of synchronization with media operations will be used),
-          otherwise, because of possible reordering in the cache, even
-          after successful journal rollback you very much risk to loose
-          your data on the FS. On Linux initiators for EXT3 and
-          ReiserFS file systems the barrier protection could be turned
-          on using "barrier=1" and "barrier=flush" mount options
-          correspondingly. Note, that usually it turned off by default
-          and the status of barriers usage isn't reported anywhere in
-          the system logs as well as there is no way to know it on the
-          mounted file system (at least no known one). Also note
-          that on some real-life workloads write through caching might
-          perform better, than write back one with the barrier protection
-          turned on.
-
-IMPORTANT: Many disk and partition table mananagement utilities don't support
+          devices works reliably *ONLY* if the order of journal writes
+          is guaranteed or it uses some kind of data protection
+          barriers (i.e. after writing journal data some kind of
+          synchronization with media operations is used), otherwise,
+          because of possible reordering in the cache, even after
+          successful journal rollback, you very much risk to loose your
+          data on the FS. Currently, Linux IO subsystem guarantees
+          order of write operations only using data protection
+          barriers. Some info about it from the XFS point of view could
+          be found at http://oss.sgi.com/projects/xfs/faq.html#wcache.
+          On Linux initiators for EXT3 and ReiserFS file systems the
+          barrier protection could be turned on using "barrier=1" and
+          "barrier=flush" mount options correspondingly. Note, that
+          usually it turned off by default and the status of barriers
+          usage isn't reported anywhere in the system logs as well as
+          there is no way to know it on the mounted file system (at
+          least no known one). Also note that on some real-life
+          workloads write through caching might perform better, than
+          write back one with the barrier protection turned on.
+
+IMPORTANT: Many disk and partition table management utilities don't support
 =========  block sizes >512 bytes, therefore make sure that your favorite one
            supports it. Also, if you export disk file or device with
           some block size, different from one, with which it was
           already divided on partitions, you could get various weird
-          things like utilities hang up or other unexpected behaviour.
+          things like utilities hang up or other unexpected behavior.
           Hence, to be sure, zero the exported file or device before the
           first access to it from the remote initiator with another
           block size.
@@ -384,10 +388,15 @@ Performance
 
 Before doing any performance measurements note that:
 
-I. Maximum performance is possible only with real SCSI devices or
-performance handlers. If you have enough CPU power, FILEIO handler could
-provide the same results, when aggregate throughput is close to
-aggregate throuput locally on the target on the same disks.
+I. Currently maximum performance is possible only with real SCSI devices
+with several simultaneously executed commands (SCSI tagged queuing) or
+performance handlers. If you have enough CPU power, FILEIO handler also
+could provide the same results, when aggregate throughput is close to
+the aggregate throughput locally on the target from the same disks. Also
+note, that currently IO subsystem in Linux implemented on such way, so a
+FILEIO device over a single file occupied entire formatted with some
+file system device (eg /dev/hdc) could perform considerably better, than
+a FILEIO device over /dev/hdc itself without the file system involved.
 
 II. In order to get the maximum performance you should:
 
@@ -414,8 +423,8 @@ IMPORTANT: Some of those options enabled by default, i.e. SCST is optimized
 
  - The default kernel read-ahead and queuing settings are optimized
    for locally attached disks, therefore they are not optimal if they
-   attached remotly (our case), which sometimes could lead to unexpectedly
-   low throughput. You should increase read-ahead size
+   attached remotely (our case), which sometimes could lead to
+   unexpectedly low throughput. You should increase read-ahead size
    (/sys/block/device/queue/read_ahead_kb) to at least 256Kb or even
    more on all initiators and the target. Also experiment with other
    parameters in /sys/block/device directory, they also affect the
@@ -448,7 +457,7 @@ IMPORTANT: If you use on initiator some versions of Windows (at least W2K)
           a device node is used. Both values are on the target.
 
 Just for reference: we had with 0.9.2 and "old" Qlogic driver on 2.4.2x
-kernel, where we did carefull performance study, aggregate throuhput
+kernel, where we did careful performance study, aggregate throughput
 about 390 Mb/sec from 2 qla2300 cards sitting on different 64-bit PCI
 buses and working simultaneously for two different initiators with
 several simultaneously working load programs on each. From one card -
index 73cbb8b..e954189 100644 (file)
@@ -2066,7 +2066,7 @@ restart:
                 * value less, than requested. Let's restart.
                 */
                int i, e = eiv_count;
-               TRACE(TRACE_MINOR, "write() returned %d from %zd "
+               TRACE_MGMT_DBG("write() returned %d from %zd "
                        "(iv_count=%d)", (int)err, full_len,
                        eiv_count);
                if (err == 0) {
@@ -2261,20 +2261,43 @@ out:
        return dev;
 }
 
-static int fileio_proc_update_size(int size, int *len,
-       off_t *begin, off_t *pos, off_t *offset)
+struct fileio_proc_update_struct {
+       int len, plen, pplen;
+       off_t begin, pbegin, ppbegin;
+       off_t pos;
+};
+
+static int fileio_proc_update_size(int size, off_t offset, int length,
+       struct fileio_proc_update_struct *p, int is_start)
 {
        int res;
        if (size > 0) {
-               *len += size;
-               *pos = *begin + *len;
-               if (*pos < *offset) {
-                       *len = 0;
-                       *begin = *pos;
+               p->len += size;
+               p->pos = p->begin + p->len;
+               if (p->pos < offset) {
+                       p->len = 0;
+                       p->begin = p->pos;
                }
-               res = 0;
-       } else
+               if (p->pos > offset + length) {
+                       p->begin = p->pbegin;
+                       p->len = p->plen;
+                       res = 1;
+                       goto out;
+               } else
+                       res = 0;
+       } else {
+               p->begin = p->ppbegin;
+               p->len = p->pplen;
                res = 1;
+               goto out;
+       }
+       if (is_start) {
+               p->ppbegin = p->pbegin;
+               p->pplen = p->plen;
+               p->pbegin = p->begin;
+               p->plen = p->len;
+       }
+out:
        return res;
 }
 
@@ -2288,10 +2311,12 @@ static int disk_fileio_proc(char *buffer, char **start, off_t offset,
        int res = 0, action;
        char *p, *name, *file_name;
        struct scst_fileio_dev *virt_dev, *vv;
-       int size, len = 0;
-       off_t begin = 0, pos = 0;
+       int size;
+       struct fileio_proc_update_struct pu;
 
        TRACE_ENTRY();
+
+       memset(&pu, 0, sizeof(pu));
        
        /* VERY UGLY code. You can rewrite it if you want */
        
@@ -2303,99 +2328,84 @@ static int disk_fileio_proc(char *buffer, char **start, off_t offset,
        if (inout == 0) { /* read */
                size = scnprintf(buffer, length, "%-17s %-11s %-11s %-15s %s\n",
                               "Name", "Size(MB)", "Block size", "Options", "File name");
-               if (fileio_proc_update_size(size, &len, &begin, &pos, &offset)) {
-                       res = len;
-                       goto out_up;
-               }
+               if (fileio_proc_update_size(size, offset, length, &pu, 1))
+                       goto stop_output;
 
                list_for_each_entry(virt_dev, &disk_fileio_dev_list, 
                        fileio_dev_list_entry)
                {
                        int c;
-                       size = scnprintf(buffer + len, length - len, 
+                       size = scnprintf(buffer + pu.len, length - pu.len, 
                                "%-17s %-11d %-12d", virt_dev->name,
                                (uint32_t)(virt_dev->file_size >> 20),
                                virt_dev->block_size);
-                       if (fileio_proc_update_size(size, &len, &begin, &pos, 
-                                               &offset)) {
-                               res = len;
-                               goto out_up;
+                       if (fileio_proc_update_size(size, offset, length, &pu,
+                                       1)) {
+                               goto stop_output;
                        }
                        c = 0;
                        if (virt_dev->wt_flag) {
-                               size = scnprintf(buffer + len, length - len, "WT");
+                               size = scnprintf(buffer + pu.len, length - pu.len, "WT");
                                c += size;
-                               if (fileio_proc_update_size(size, &len, &begin, 
-                                                       &pos, &offset)) {
-                                       res = len;
-                                       goto out_up;
+                               if (fileio_proc_update_size(size, offset,
+                                               length, &pu, 0)) {
+                                       goto stop_output;
                                }
                        }
                        if (virt_dev->nv_cache) {
-                               size = scnprintf(buffer + len, length - len,
+                               size = scnprintf(buffer + pu.len, length - pu.len,
                                        c ? ",NV" : "NV");
                                c += size;
-                               if (fileio_proc_update_size(size, &len, &begin, 
-                                                       &pos, &offset)) {
-                                       res = len;
-                                       goto out_up;
+                               if (fileio_proc_update_size(size, offset,
+                                               length, &pu, 0)) {
+                                       goto stop_output;
                                }
                        }
                        if (virt_dev->rd_only_flag) {
-                               size = scnprintf(buffer + len, length - len, 
+                               size = scnprintf(buffer + pu.len, length - pu.len, 
                                        c ? ",RO" : "RO");
                                c += size;
-                               if (fileio_proc_update_size(size, &len, &begin, 
-                                                       &pos, &offset)) {
-                                       res = len;
-                                       goto out_up;
+                               if (fileio_proc_update_size(size, offset,
+                                               length, &pu, 0)) {
+                                       goto stop_output;
                                }
                        }
                        if (virt_dev->o_direct_flag) {
-                               size = scnprintf(buffer + len, length - len, 
+                               size = scnprintf(buffer + pu.len, length - pu.len, 
                                        c ? ",DR" : "DR");
                                c += size;
-                               if (fileio_proc_update_size(size, &len, &begin, 
-                                                       &pos, &offset)) {
-                                       res = len;
-                                       goto out_up;
+                               if (fileio_proc_update_size(size, offset,
+                                               length, &pu, 0)) {
+                                       goto stop_output;
                                }
                        }
                        if (virt_dev->nullio) {
-                               size = scnprintf(buffer + len, length - len, 
+                               size = scnprintf(buffer + pu.len, length - pu.len, 
                                        c ? ",NIO" : "NIO");
                                c += size;
-                               if (fileio_proc_update_size(size, &len, &begin, 
-                                                       &pos, &offset)) {
-                                       res = len;
-                                       goto out_up;
+                               if (fileio_proc_update_size(size, offset,
+                                               length, &pu, 0)) {
+                                       goto stop_output;
                                }
                        }
                        while (c < 16) {
-                               size = scnprintf(buffer + len, length - len, " ");
-                               if (fileio_proc_update_size(size, &len, &begin, &pos, 
-                                               &offset)) {
-                                       res = len;
-                                       goto out_up;
+                               size = scnprintf(buffer + pu.len, length - pu.len, " ");
+                               if (fileio_proc_update_size(size, offset,
+                                               length, &pu, 0)) {
+                                       goto stop_output;
                                }
                                c++;
                        }
-                       size = scnprintf(buffer + len, length - len, "%s\n",
+                       size = scnprintf(buffer + pu.len, length - pu.len, "%s\n",
                                        virt_dev->file_name);
-                       if (fileio_proc_update_size(size, &len, &begin, 
-                                               &pos, &offset)) {
-                               res = len;
-                               goto out_up;
+                       if (fileio_proc_update_size(size, offset, length, &pu,
+                                       0)) {
+                               goto stop_output;
                        }
                }
-               *start = buffer + (offset - begin);
-               len -= (offset - begin);
-               if (len > length)
-                       len = length;
-               res = len;
                *eof = 1;
-       } 
-       else {  /* write */
+               goto stop_output;
+       else {  /* write */
                uint32_t block_size = DEF_DISK_BLOCKSIZE;
                int block_shift = DEF_DISK_BLOCKSIZE_SHIFT;
                p = buffer;
@@ -2545,15 +2555,15 @@ static int disk_fileio_proc(char *buffer, char **start, off_t offset,
                        
                        strcpy(virt_dev->name, name);
 
-                       len = strlen(file_name) + 1;
-                       virt_dev->file_name = kmalloc(len, GFP_KERNEL);
+                       pu.len = strlen(file_name) + 1;
+                       virt_dev->file_name = kmalloc(pu.len, GFP_KERNEL);
                        if (virt_dev->file_name == NULL) {
                                TRACE(TRACE_OUT_OF_MEM, "%s",
                                      "Allocation of file_name failed");
                                res = -ENOMEM;
                                goto out_free_vdev;
                        }
-                       strncpy(virt_dev->file_name, file_name, len);
+                       strncpy(virt_dev->file_name, file_name, pu.len);
 
                        list_add_tail(&virt_dev->fileio_dev_list_entry,
                                      &disk_fileio_dev_list);
@@ -2605,6 +2615,14 @@ out:
        TRACE_EXIT_RES(res);
        return res;
 
+stop_output:
+       *start = buffer + (offset - pu.begin);
+       pu.len -= (offset - pu.begin);
+       if (pu.len > length)
+               pu.len = length;
+       res = pu.len;
+       goto out_up;
+
 out_free_vpath:
        list_del(&virt_dev->fileio_dev_list_entry);
        kfree(virt_dev->file_name);
@@ -2924,11 +2942,13 @@ static int cdrom_fileio_proc(char *buffer, char **start, off_t offset,
        int res = 0, action;
        char *p, *name;
        struct scst_fileio_dev *virt_dev;
-       int size, len = 0;
-       off_t begin = 0, pos = 0;
+       int size;
+       struct fileio_proc_update_struct pu;
 
        TRACE_ENTRY();
 
+       memset(&pu, 0, sizeof(pu));
+
        if (down_interruptible(&scst_fileio_mutex) != 0) {
                res = -EINTR;
                goto out;
@@ -2937,32 +2957,24 @@ static int cdrom_fileio_proc(char *buffer, char **start, off_t offset,
        if (inout == 0) { /* read */
                size = scnprintf(buffer, length, "%-17s %-9s %s\n",
                               "Name", "Size(MB)", "File name");
-               if (fileio_proc_update_size(size, &len, &begin, &pos, 
-                                       &offset)) {
-                       res = len;
-                       goto out_up;
-               }
+               if (fileio_proc_update_size(size, offset, length, &pu, 1))
+                       goto stop_output;
 
                list_for_each_entry(virt_dev, &cdrom_fileio_dev_list, 
                        fileio_dev_list_entry)
                {
-                       size = scnprintf(buffer + len, length - len, 
+                       size = scnprintf(buffer + pu.len, length - pu.len, 
                                "%-17s %-9d %s\n", virt_dev->name,
                                (uint32_t)(virt_dev->file_size >> 20),
                                virt_dev->file_name);
-                       if (fileio_proc_update_size(size, &len, &begin, 
-                                               &pos, &offset)) {
-                               res = len;
-                               goto out_up;
+                       if (fileio_proc_update_size(size, offset, length, &pu,
+                                       1)) {
+                               goto stop_output;
                        }
                }
-               *start = buffer + (offset - begin);
-               len -= (offset - begin);
-               if (len > length)
-                       len = length;
-               res = len;
-       } 
-       else {  /* write */
+               *eof = 1;
+               goto stop_output;
+       } else {  /* write */
                p = buffer;
                if (p[strlen(p) - 1] == '\n') {
                        p[strlen(p) - 1] = '\0';
@@ -3022,6 +3034,13 @@ out:
        TRACE_EXIT_RES(res);
        return res;
 
+stop_output:
+       *start = buffer + (offset - pu.begin);
+       pu.len -= (offset - pu.begin);
+       if (pu.len > length)
+               pu.len = length;
+       res = pu.len;
+       goto out_up;
 }
 
 static int fileio_proc_help_build(struct scst_dev_type *dev_type)
index 5a3cd50..a926e64 100644 (file)
@@ -341,7 +341,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
                      dev->scsi_dev->lun, (uint64_t)tgt_dev->acg_dev->lun);
        }
        else {
-               TRACE(TRACE_MINOR, "Virtual device SCST lun=%Ld", 
+               TRACE_MGMT_DBG("Virtual device SCST lun=%Ld", 
                      (uint64_t)tgt_dev->acg_dev->lun);
        }
 
@@ -1562,6 +1562,7 @@ lun_t scst_unpack_lun(const uint8_t *lun, int len)
        address_method = (*lun) >> 6;   /* high 2 bits of byte 0 */
        switch (address_method) {
        case 0: /* peripheral device addressing method */
+#if 0 /* At least QLA2300 Linux ini uses it as the flat space addressing method */
                if (*lun) {
                        PRINT_ERROR_PR("Illegal BUS INDENTIFIER in LUN "
                             "peripheral device addressing method 0x%02x, "
@@ -1570,6 +1571,9 @@ lun_t scst_unpack_lun(const uint8_t *lun, int len)
                }
                res = *(lun + 1);
                break;
+#else
+               /* go through */
+#endif
 
        case 1: /* flat space addressing method */
                res = *(lun + 1) | (((*lun) & 0x3f) << 8);
index 8ada240..47667e1 100644 (file)
@@ -726,45 +726,62 @@ static void scst_proc_cleanup_groups(void)
        TRACE_EXIT();
 }
 
-static int scst_proc_update_size(int size, int *len,
-       off_t *begin, off_t *pos, off_t *offset, int length)
+struct scst_proc_update_struct {
+       int len, plen, pplen;
+       off_t begin, pbegin, ppbegin;
+       off_t pos;
+};
+
+static int scst_proc_update_size(int size, off_t offset, int length,
+       struct scst_proc_update_struct *p)
 {
        int res;
        if (size > 0) {
-               *len += size;
-               *pos = *begin + *len;
-               if (*pos < *offset) {
-                       *len = 0;
-                       *begin = *pos;
+               p->len += size;
+               p->pos = p->begin + p->len;
+               if (p->pos < offset) {
+                       p->len = 0;
+                       p->begin = p->pos;
                }
-               if (pos > offset + length)
+               if (p->pos > offset + length) {
+                       p->begin = p->pbegin;
+                       p->len = p->plen;
                        res = 1;
-               else
+                       goto out;
+               } else
                        res = 0;
-       } else
+       } else {
+               p->begin = p->ppbegin;
+               p->len = p->pplen;
                res = 1;
+               goto out;
+       }
+       p->ppbegin = p->pbegin;
+       p->pplen = p->plen;
+       p->pbegin = p->begin;
+       p->plen = p->len;
+out:
        return res;
 }
 
-static int scst_proc_sgv_read_1(char *buffer, int *len,
-       off_t *begin, off_t *pos, off_t *offset, int length,
+static int scst_proc_sgv_read_1(char *buffer, off_t offset, int length,
+       struct scst_proc_update_struct *p,
        const struct sgv_pool *pool, const char *name)
 {
        int i, size;
 
-       size = scnprintf(buffer + *len, length - *len, "\n%-20s %-11d %-11d\n",
+       size = scnprintf(buffer + p->len, length - p->len, "\n%-20s %-11d %-11d\n",
                name, atomic_read(&pool->acc.hit_alloc),
                atomic_read(&pool->acc.total_alloc));
-       if (scst_proc_update_size(size, len, begin, pos, offset, length))
+       if (scst_proc_update_size(size, offset, length, p))
                return 1;
 
        for(i = 0; i < SGV_POOL_ELEMENTS; i++) {
-               size = scnprintf(buffer + *len, length - *len, 
+               size = scnprintf(buffer + p->len, length - p->len, 
                        "  %-18s %-11d %-11d\n", pool->cache_names[i], 
                        atomic_read(&pool->cache_acc[i].hit_alloc),
                        atomic_read(&pool->cache_acc[i].total_alloc));
-               if (scst_proc_update_size(size, len, begin, pos, offset,
-                               length))
+               if (scst_proc_update_size(size, offset, length, p))
                        return 1;
        }
        return 0;
@@ -774,48 +791,52 @@ static int scst_proc_sgv_read(char *buffer, char **start,
        off_t offset, int length, int *eof, void *data)
 {
        int res = 0;
-       int size, len = 0;
-       off_t begin = 0, pos = 0;
+       int size;
+       struct scst_proc_update_struct st;
 
        TRACE_ENTRY();
 
        TRACE_DBG("offset: %d, length %d", (int) offset, length);
 
-       size = scnprintf(buffer + len, length - len, "%-20s %-11s %-11s",
+       memset(&st, 0, sizeof(st));
+
+       size = scnprintf(buffer + st.len, length - st.len, "%-20s %-11s %-11s",
                "Name", "Hit", "Total");
-       if (scst_proc_update_size(size, &len, &begin, &pos, &offset, length))
+       if (scst_proc_update_size(size, offset, length, &st))
                goto stop_output;
 
-       if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length, 
-                       &scst_sgv.norm, "sgv"))
+       if (scst_proc_sgv_read_1(buffer, offset, length, &st, &scst_sgv.norm,
+                       "sgv"))
                goto stop_output;
 
-       if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length, 
+       if (scst_proc_sgv_read_1(buffer, offset, length, &st,
                        &scst_sgv.norm_clust, "sgv-clust"))
                goto stop_output;
 
-       if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length, 
+       if (scst_proc_sgv_read_1(buffer, offset, length, &st,
                        &scst_sgv.dma, "sgv-dma"))
                goto stop_output;
 
 #ifdef SCST_HIGHMEM
-       if (scst_proc_sgv_read_1(buffer, &len, &begin, &pos, &offset, length, 
+       if (scst_proc_sgv_read_1(buffer, offset, length, &st,
                        &scst_sgv.highmem, "sgv-highmem"))
                goto stop_output;
 
 #endif
 
-       size = scnprintf(buffer + len, length - len, "\n%-32s %-11d\n", 
+       size = scnprintf(buffer + st.len, length - st.len, "\n%-32s %-11d\n", 
                "big", atomic_read(&sgv_big_total_alloc));
-       if (scst_proc_update_size(size, &len, &begin, &pos, &offset, length))
+       if (scst_proc_update_size(size, offset, length, &st))
                goto stop_output;
 
+       *eof = 1;
+
 stop_output:
-       *start = buffer + (offset - begin);
-       len -= (offset - begin);
-       if (len > length)
-               len = length;
-       res = len;
+       *start = buffer + (offset - st.begin);
+       st.len -= (offset - st.begin);
+       if (st.len > length)
+               st.len = length;
+       res = st.len;
 
        TRACE_EXIT_RES(res);
        return res;
@@ -979,8 +1000,8 @@ static int scst_scsi_tgt_proc_info(char *buffer, char **start,
                                   void *data)
 {
        int res = 0;
-       int size, len = 0;
-       off_t begin = 0, pos = 0;
+       int size, len = 0, plen, pplen;
+       off_t begin = 0, pos = 0, pbegin, ppbegin;
        struct scst_device *dev;
 
        TRACE_ENTRY();
@@ -1005,6 +1026,8 @@ static int scst_scsi_tgt_proc_info(char *buffer, char **start,
        } else
                goto stop_output;
 
+       ppbegin = pbegin = begin;
+       pplen = plen = len;
        list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
                if (dev->virt_id == 0) {
                        size = scnprintf(buffer + len, length - len,
@@ -1027,12 +1050,24 @@ static int scst_scsi_tgt_proc_info(char *buffer, char **start,
                                len = 0;
                                begin = pos;
                        }
-                       if (pos > offset + length)
+                       if (pos > offset + length) {
+                               begin = pbegin;
+                               len = plen;
                                goto stop_output;
-               } else
+                       }
+               } else {
+                       begin = ppbegin;
+                       len = pplen;
                        goto stop_output;
+               }
+               ppbegin = pbegin;
+               pplen = plen;
+               pbegin = begin;
+               plen = len;
        }
 
+       *eof = 1;
+
 stop_output:
        *start = buffer + (offset - begin);
        len -= (offset - begin);
@@ -1771,8 +1806,8 @@ static int scst_proc_groups_devices_read(char *buffer, char **start,
        int res = 0;
        struct scst_acg *acg = (struct scst_acg *)data;
        struct scst_acg_dev *acg_dev;
-       int size, len = 0;
-       off_t begin = 0, pos = 0;
+       int size, len = 0, plen, pplen;
+       off_t begin = 0, pos = 0, pbegin, ppbegin;
 
        TRACE_ENTRY();
 
@@ -1796,6 +1831,8 @@ static int scst_proc_groups_devices_read(char *buffer, char **start,
        } else
                goto stop_output;
 
+       ppbegin = pbegin = begin;
+       pplen = plen = len;
        list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
                if (acg_dev->dev->virt_id == 0) {
                        size = scnprintf(buffer + len, length - len,
@@ -1819,12 +1856,24 @@ static int scst_proc_groups_devices_read(char *buffer, char **start,
                                len = 0;
                                begin = pos;
                        }
-                       if (pos > offset + length)
+                       if (pos > offset + length) {
+                               begin = pbegin;
+                               len = plen;
                                goto stop_output;
-               } else
+                       }
+               } else {
+                       begin = ppbegin;
+                       len = pplen;
                        goto stop_output;
+               }
+               ppbegin = pbegin;
+               pplen = plen;
+               pbegin = begin;
+               plen = len;
        }
 
+       *eof = 1;
+
 stop_output:
        *start = buffer + (offset - begin);
        len -= (offset - begin);
@@ -2034,8 +2083,8 @@ static int scst_proc_sessions_read(char *buffer, char **start,
        int res = 0;
        struct scst_acg *acg;
        struct scst_session *sess;
-       int size, len = 0;
-       off_t begin = 0, pos = 0;
+       int size, len = 0, plen, pplen;
+       off_t begin = 0, pos = 0,  pbegin, ppbegin;
 
        TRACE_ENTRY();
 
@@ -2059,6 +2108,8 @@ static int scst_proc_sessions_read(char *buffer, char **start,
        } else
                goto stop_output;
 
+       ppbegin = pbegin = begin;
+       pplen = plen = len;
        list_for_each_entry(acg, &scst_acg_list, scst_acg_list_entry) {
                list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
                        size = scnprintf(buffer + len, length - len,
@@ -2074,13 +2125,25 @@ static int scst_proc_sessions_read(char *buffer, char **start,
                                        len = 0;
                                        begin = pos;
                                }
-                               if (pos > offset + length)
+                               if (pos > offset + length) {
+                                       begin = pbegin;
+                                       len = plen;
                                        goto stop_output;
-                       } else
+                               }
+                       } else {
+                               begin = ppbegin;
+                               len = pplen;
                                goto stop_output;
+                       }
+                       ppbegin = pbegin;
+                       pplen = plen;
+                       pbegin = begin;
+                       plen = len;
                }
        }
 
+       *eof = 1;
+
 stop_output:
        *start = buffer + (offset - begin);
        len -= (offset - begin);
@@ -2102,8 +2165,8 @@ static int scst_proc_groups_names_read(char *buffer, char **start,
        int res = 0;
        struct scst_acg *acg = (struct scst_acg *)data;
        struct scst_acn *name;
-       int size, len = 0;
-       off_t begin = 0, pos = 0;
+       int size, len = 0, plen, pplen;
+       off_t begin = 0, pos = 0, pbegin, ppbegin;
 
        TRACE_ENTRY();
 
@@ -2112,6 +2175,8 @@ static int scst_proc_groups_names_read(char *buffer, char **start,
                goto out;
        }
 
+       ppbegin = pbegin = begin;
+       pplen = plen = len;
        list_for_each_entry(name, &acg->acn_list, acn_list_entry) {
                size = scnprintf(buffer + len, length - len, "%s\n",
                        name->name);
@@ -2122,12 +2187,24 @@ static int scst_proc_groups_names_read(char *buffer, char **start,
                                len = 0;
                                begin = pos;
                        }
-                       if (pos > offset + length)
+                       if (pos > offset + length) {
+                               begin = pbegin;
+                               len = plen;
                                goto stop_output;
-               } else
+                       }
+               } else {
+                       begin = ppbegin;
+                       len = pplen;
                        goto stop_output;
+               }
+               ppbegin = pbegin;
+               pplen = plen;
+               pbegin = begin;
+               plen = len;
        }
 
+       *eof = 1;
+
 stop_output:
        *start = buffer + (offset - begin);
        len -= (offset - begin);
index 5f2771c..5cff7f2 100644 (file)
@@ -306,7 +306,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
                                cmd->cdb[0], dev->handler->name);
                }
                if (scst_cmd_is_expected_set(cmd)) {
-                       TRACE(TRACE_MINOR, "Using initiator supplied values: "
+                       TRACE(TRACE_SCSI, "Using initiator supplied values: "
                                "direction %d, transfer_len %d",
                                cmd->expected_data_direction,
                                cmd->expected_transfer_len);
@@ -1234,6 +1234,7 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
        int buffer_size;
        struct scst_tgt_dev *tgt_dev = NULL;
        uint8_t *buffer;
+       int offs, overflow = 0;
 
        TRACE_ENTRY();
 
@@ -1243,45 +1244,70 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
        cmd->host_status = DID_OK;
        cmd->driver_status = 0;
 
-       /* ToDo: use full SG buffer, not only the first entry */
+       if (cmd->cdb[2] != 0) {
+               PRINT_ERROR_PR("Unsupported SELECT REPORT value %x in REPORT "
+                       "LUNS command", cmd->cdb[2]);
+               goto out_err;
+       }
+
        buffer_size = scst_get_buf_first(cmd, &buffer);
        if (unlikely(buffer_size <= 0))
                goto out_err;
 
-       if (buffer_size < 16) {
+       if (buffer_size < 16)
                goto out_put_err;
-       }
 
        memset(buffer, 0, buffer_size);
+       offs = 8;
 
        /* sess->sess_tgt_dev_list is protected by suspended activity */
        list_for_each_entry(tgt_dev, &cmd->sess->sess_tgt_dev_list,
                            sess_tgt_dev_list_entry) 
        {
-               if (8 + 8 * dev_cnt + 2 <= buffer_size) {
-                       buffer[8 + 8 * dev_cnt] = (tgt_dev->acg_dev->lun >> 8) & 0xff;
-                       buffer[8 + 8 * dev_cnt + 1] = tgt_dev->acg_dev->lun & 0xff;
+               if (!overflow) {
+                       if (offs >= buffer_size) {
+                               scst_put_buf(cmd, buffer);
+                               buffer_size = scst_get_buf_first(cmd, &buffer);
+                               if (buffer_size > 0) {
+                                       memset(buffer, 0, buffer_size);
+                                       offs = 0;
+                               } else {
+                                       overflow = 1;
+                                       goto inc_dev_cnt;
+                               }
+                       }
+                       if ((buffer_size - offs) < 8) {
+                               PRINT_ERROR_PR("Buffer allocated for REPORT "
+                                       "LUNS command doesn't allow to fit 8 "
+                                       "byte entry (buffer_size=%d)",
+                                       buffer_size);
+                               goto out_put_hw_err;
+                       }
+                       buffer[offs] = (tgt_dev->acg_dev->lun >> 8) & 0xff;
+                       buffer[offs + 1] = tgt_dev->acg_dev->lun & 0xff;
+                       offs += 8;
                }
+inc_dev_cnt:
                dev_cnt++;
-               /* Tmp, until ToDo above done */
-               if (dev_cnt >= ((PAGE_SIZE >> 3) - 2))
-                       break;
        }
+       if (!overflow)
+               scst_put_buf(cmd, buffer);
 
        /* Set the response header */
+       buffer_size = scst_get_buf_first(cmd, &buffer);
+       if (unlikely(buffer_size <= 0))
+               goto out_err;
        dev_cnt *= 8;
        buffer[0] = (dev_cnt >> 24) & 0xff;
        buffer[1] = (dev_cnt >> 16) & 0xff;
        buffer[2] = (dev_cnt >> 8) & 0xff;
        buffer[3] = dev_cnt & 0xff;
-
-       dev_cnt += 8;
-
        scst_put_buf(cmd, buffer);
 
-       if (buffer_size > dev_cnt)
+       dev_cnt += 8;
+       if (dev_cnt < cmd->resp_data_len)
                scst_set_resp_data_len(cmd, dev_cnt);
-       
+
 out_done:
        cmd->completed = 1;
 
@@ -1298,6 +1324,11 @@ out_err:
        scst_set_cmd_error(cmd,
                   SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
        goto out_done;
+
+out_put_hw_err:
+       scst_put_buf(cmd, buffer);
+       scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
+       goto out_done;
 }
 
 static int scst_pre_select(struct scst_cmd *cmd)