From: Hannes Reinecke <hare@suse.de>
To: dgilbert@interlog.com, linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, tomas.winkler@intel.com, emilne@redhat.com
Subject: Re: [PATCH 08/12] scsi_debug: rework resp_report_luns
Date: Wed, 27 Apr 2016 07:58:46 +0200	[thread overview]
Message-ID: <57205516.4030809@suse.de> (raw)
In-Reply-To: <57203B49.7040706@interlog.com>
On 04/27/2016 06:08 AM, Douglas Gilbert wrote:
> On 2016-04-26 02:26 AM, Hannes Reinecke wrote:
>> On 04/25/2016 06:16 PM, Douglas Gilbert wrote:
>>> Based on "[PATH V2] scsi_debug: rework resp_report_luns" patch
>>> sent by Tomas Winkler on Thursday, 26 Feb 2015. His notes:
>>>    1. Remove duplicated boundary checks which simplify the fill-in
>>>       loop
>>>    2. Use more of scsi generic API
>>> Replace fixed length response array a with heap allocation
>>> allowing up to 16383 LUNs per target.
>>>
>>> Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
>>> ---
>>>   drivers/scsi/scsi_debug.c | 138
>>> ++++++++++++++++++++++++++++++----------------
>>>   1 file changed, 91 insertions(+), 47 deletions(-)
>>>
>>> diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
>>> index cf44ab0..eac62b8 100644
>>> --- a/drivers/scsi/scsi_debug.c
>>> +++ b/drivers/scsi/scsi_debug.c
>>> @@ -3205,63 +3205,99 @@ static int resp_get_lba_status(struct
>>> scsi_cmnd *scp,
>>>       return fill_from_dev_buffer(scp, arr,
>>> SDEBUG_GET_LBA_STATUS_LEN);
>>>   }
>>>
>>> -#define SDEBUG_RLUN_ARR_SZ 256
>>> -
>>> -static int resp_report_luns(struct scsi_cmnd * scp,
>>> -                struct sdebug_dev_info * devip)
>>> +/* Even though each pseudo target has a REPORT LUNS "well known
>>> logical unit"
>>> + * (W-LUN), the normal Linux scanning logic does not associate
>>> it with a
>>> + * device (e.g. /dev/sg7). The following magic will make that
>>> association:
>>> + *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
>>> + * where <n> is a host number. If there are multiple targets in
>>> a host then
>>> + * the above will associate a W-LUN to each target. To only get
>>> a W-LUN
>>> + * for target 2, then use "echo '- 2 49409' > scan" . */
>>> +static int resp_report_luns(struct scsi_cmnd *scp,
>>> +                struct sdebug_dev_info *devip)
>>>   {
>>> +    unsigned char *cmd = scp->cmnd;
>>>       unsigned int alloc_len;
>>> -    int lun_cnt, i, upper, num, n, want_wlun, shortish;
>>> +    unsigned char select_report;
>>>       u64 lun;
>>> -    unsigned char *cmd = scp->cmnd;
>>> -    int select_report = (int)cmd[2];
>>> -    struct scsi_lun *one_lun;
>>> -    unsigned char arr[SDEBUG_RLUN_ARR_SZ];
>>> -    unsigned char * max_addr;
>>> +    struct scsi_lun *lun_p;
>>> +    u8 *arr;
>>> +    unsigned int lun_cnt;    /* normal LUN count (max: 16383) */
>>> +    unsigned int wlun_cnt;    /* report luns W-LUN count */
>>> +    unsigned int tlun_cnt;    /* total LUN count */
>>> +    unsigned int rlen;    /* response length (in bytes) less
>>> header */
>>> +    int i, res;
>>>
>>>       clear_luns_changed_on_target(devip);
>>> -    alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) +
>>> (cmd[6] << 24);
>>> -    shortish = (alloc_len < 4);
>>> -    if (shortish || (select_report > 2)) {
>>> -        mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2,
>>> -1);
>>> +
>>> +    select_report = cmd[2];
>>> +    alloc_len = get_unaligned_be32(cmd + 6);
>>> +
>>> +    if (alloc_len < 4) {
>>> +        pr_err("alloc len too small %d\n", alloc_len);
>>> +        mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
>>>           return check_condition_result;
>>>       }
>>> -    /* can produce response with up to 16k luns (lun 0 to lun
>>> 16383) */
>>> -    memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
>>> +
>>> +    if (select_report > 0x02) {
>>> +        pr_err("select report invalid %d\n", select_report);
>>> +        mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
>>> +        return check_condition_result;
>>> +    }
>>> +
>>>       lun_cnt = sdebug_max_luns;
>>> -    if (1 == select_report)
>>> +    wlun_cnt = 0;
>>> +
>>> +    /* report only w_lun */
>>> +    if (select_report == 0x01)
>>>           lun_cnt = 0;
>>> -    else if (sdebug_no_lun_0 && (lun_cnt > 0))
>>> +
>>> +    if (sdebug_no_lun_0 && (lun_cnt > 0))
>>>           --lun_cnt;
>>> -    want_wlun = (select_report > 0) ? 1 : 0;
>>> -    num = lun_cnt + want_wlun;
>>> -    arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
>>> -    arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
>>> -    n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
>>> -                sizeof(struct scsi_lun)), num);
>>> -    if (n < num) {
>>> -        want_wlun = 0;
>>> -        lun_cnt = n;
>>> -    }
>>> -    one_lun = (struct scsi_lun *) &arr[8];
>>> -    max_addr = arr + SDEBUG_RLUN_ARR_SZ;
>>> -    for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
>>> -             ((i < lun_cnt) && ((unsigned char *)(one_lun + i) <
>>> max_addr));
>>> -         i++, lun++) {
>>> -        upper = (lun >> 8) & 0x3f;
>>> -        if (upper)
>>> -            one_lun[i].scsi_lun[0] =
>>> -                (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
>>> -        one_lun[i].scsi_lun[1] = lun & 0xff;
>>> -    }
>>> -    if (want_wlun) {
>>> -        one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) &
>>> 0xff;
>>> -        one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
>>> -        i++;
>>> -    }
>>> -    alloc_len = (unsigned char *)(one_lun + i) - arr;
>>> -    return fill_from_dev_buffer(scp, arr,
>>> -                    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
>>> +
>>> +    /* report w_lun */
>>> +    if (select_report == 0x01 || select_report == 0x02)
>>> +        wlun_cnt = 1;
>>> +
>>> +    tlun_cnt = lun_cnt + wlun_cnt;
>>> +    /* can produce response with up to 16k luns (lun 0 to lun
>>> 16383) */
>>> +    arr = kzalloc((tlun_cnt * sizeof(lun_p->scsi_lun)) + 8,
>>> GFP_ATOMIC);
>>> +    if (!arr) {
>>> +        pr_warn("No space for report luns response\n");
>>> +        mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
>>> +                INSUFF_RES_ASCQ);
>>> +        return check_condition_result;
>>> +    }
>>> +    pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
>>> +         select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
>>> +
>>> +    lun = 0LL;
>>> +    /* luns start at offset 8 after the byte length */
>>> +    lun_p = (struct scsi_lun *)&arr[8];
>>> +
>>> +    /* skip lun 0 */
>>> +    if (sdebug_no_lun_0)
>>> +        lun++;
>>> +    /*
>>> +     * Address method (we use Peripherial = 00b)
>>> +     * 10b - Logical unit
>>> +     * 00b - Peripherial device - Use this one
>>> +     * 01b - Logical device
>>> +     * 11b - reserved
>>> +     */
>>> +    for (i = 0; i < lun_cnt; i++)
>>> +        int_to_scsilun(lun++, lun_p++);
>>> +
>>> +    /* report SCSI_W_LUN_REPORT_LUN */
>>> +    if (wlun_cnt)
>>> +        int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++);
>>> +
>>> +    rlen = tlun_cnt * sizeof(struct scsi_lun);
>>> +
>>> +    put_unaligned_be32(rlen, &arr[0]);
>>> +
>>> +    res = fill_from_dev_buffer(scp, arr, rlen + 8);
>>> +    kfree(arr);
>>> +    return res;
>>>   }
>>>
>>>   static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned
>>> long long lba,
>>> @@ -4299,6 +4335,10 @@ static ssize_t max_luns_store(struct
>>> device_driver *ddp, const char *buf,
>>>       bool changed;
>>>
>>>       if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
>>> +        if (n > 16383) {
>>> +            pr_warn("max_luns can be no more than 16383\n");
>>> +            return -EINVAL;
>>> +        }
>>>           changed = (sdebug_max_luns != n);
>>>           sdebug_max_luns = n;
>>>           sdebug_max_tgts_luns();
>>> @@ -4643,6 +4683,10 @@ static int __init scsi_debug_init(void)
>>>           pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
>>>           return -EINVAL;
>>>       }
>>> +    if (sdebug_max_luns > 16383) {
>>> +        pr_warn("max_luns can be no more than 16383, use
>>> default\n");
>>> +        sdebug_max_luns = DEF_MAX_LUNS;
>>> +    }
>>>
>>>       if (sdebug_lowest_aligned > 0x3fff) {
>>>           pr_err("lowest_aligned too big: %u\n",
>>> sdebug_lowest_aligned);
>>>
>> Hmm.
>>
>> Have you actually checked this?
> 
> Yes I did and it worked!! It took 13 minutes on my laptop with
> 'max_luns=16383' and after that I could access various LUs across
> that range. You can try it yourself :-)
> 
Oh, I do not doubt that it'll be able to create LUNs with these
numbers. The point being that the LUN numbers beyond 255 generated
with this simple algorithm are non-standard.
>> Thing is, only LUNs 0-255 are numbered sequentially; any higher LUNs
>> has to use one of the various encoding schemes, at which point the
>> sequentiality (sp?) breaks down.
> 
> I checked sam6r01.pdf clause 4.7.5 and you are correct. So the
> comment inherited from Tomas's patch about 16k luns is wrong.
> 
>> So to be correct you probably should be using a loop from 0-255 to
>> generate the low-order LUNs, and another loop from 255 - lun_cnt to
>> construct the higher-order LUNs from the address method + lun number.
> 
> So should I scale max_luns back to no more than 256 (which should
> produce LUNs 0...255 (or if no_lun_0=1 produce LUNs 1...255)), or
> switch to flat space addressing (address_method=1) at LUN 256
> through 16383?
> 
Switch to flat space addressing, please.
(Or, even better, have a flag allowing to select the addressing
method). There is no need to arbitrary restrict ourselves to 256
LUNs (we got plenty of 'real' SCSI targets with do exactly this).
What we need is the ability to validate the SCSI stack (and OS
tooling) against LUN numbers higher than 256, possibly using some of
the more exotic LUN enumeration schemes.
Cheers,
Hannes
-- 
Dr. Hannes Reinecke		   Teamlead Storage & Networking
hare@suse.de			               +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
next prev parent reply	other threads:[~2016-04-27  5:58 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-25 16:16 [PATCH 00/12] scsi_debug: multiple queue support and cleanup Douglas Gilbert
2016-04-25 16:16 ` [PATCH 01/12] scsi_debug: cleanup naming and bit crunching Douglas Gilbert
2016-04-26  6:14   ` Hannes Reinecke
2016-04-26 18:13   ` Bart Van Assche
2016-04-26 18:27     ` James Bottomley
2016-04-27  5:25     ` Douglas Gilbert
2016-04-25 16:16 ` [PATCH 02/12] scsi_debug: ignore host lock option Douglas Gilbert
2016-04-26  6:15   ` Hannes Reinecke
2016-04-25 16:16 ` [PATCH 03/12] scsi_debug: replace jiffy timers with hr timers Douglas Gilbert
2016-04-26  6:17   ` Hannes Reinecke
2016-04-26 18:38   ` Bart Van Assche
2016-04-25 16:16 ` [PATCH 04/12] scsi_debug: make jiffy delay name clearer Douglas Gilbert
2016-04-26  6:17   ` Hannes Reinecke
2016-04-25 16:16 ` [PATCH 05/12] scsi_debug: replace tasklet with work queue Douglas Gilbert
2016-04-26  6:20   ` Hannes Reinecke
2016-04-25 16:16 ` [PATCH 06/12] scsi_debug: re-order file scope declarations Douglas Gilbert
2016-04-26  6:21   ` Hannes Reinecke
2016-04-26 20:55   ` Bart Van Assche
2016-04-25 16:16 ` [PATCH 07/12] scsi_debug: use likely hints on fast path Douglas Gilbert
2016-04-26  6:22   ` Hannes Reinecke
2016-04-26 22:14   ` Bart Van Assche
2016-04-27  5:25     ` Douglas Gilbert
2016-04-27  5:33       ` Bart Van Assche
2016-04-27 14:29       ` Bart Van Assche
2016-04-25 16:16 ` [PATCH 08/12] scsi_debug: rework resp_report_luns Douglas Gilbert
2016-04-26  6:26   ` Hannes Reinecke
2016-04-27  4:08     ` Douglas Gilbert
2016-04-27  5:58       ` Hannes Reinecke [this message]
2016-04-26  7:33   ` Winkler, Tomas
2016-04-27 23:09   ` Bart Van Assche
2016-04-25 16:16 ` [PATCH 09/12] scsi_debug: add multiple queue support Douglas Gilbert
2016-04-26  6:29   ` Hannes Reinecke
2016-04-26 22:19   ` Bart Van Assche
2016-04-25 16:16 ` [PATCH 10/12] scsi_debug: vpd and mode page work Douglas Gilbert
2016-04-26  6:29   ` Hannes Reinecke
2016-04-25 16:16 ` [PATCH 11/12] scsi_debug: uuid for lu name Douglas Gilbert
2016-04-26  6:30   ` Hannes Reinecke
2016-04-25 16:16 ` [PATCH 12/12] scsi_debug: use locally assigned naa Douglas Gilbert
2016-04-26  6:31   ` Hannes Reinecke
2016-04-29 23:53 ` [PATCH 00/12] scsi_debug: multiple queue support and cleanup Martin K. Petersen
2016-04-30  2:06   ` Douglas Gilbert
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox
  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):
  git send-email \
    --in-reply-to=57205516.4030809@suse.de \
    --to=hare@suse.de \
    --cc=dgilbert@interlog.com \
    --cc=emilne@redhat.com \
    --cc=linux-scsi@vger.kernel.org \
    --cc=martin.petersen@oracle.com \
    --cc=tomas.winkler@intel.com \
    /path/to/YOUR_REPLY
  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
  Be sure your reply has a Subject: header at the top and a blank line
  before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).