aboutsummaryrefslogtreecommitdiff
path: root/hw/scsi/emulation.c
blob: 06d62f3c3875a5588135fb497f225bdeaffa69a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/bswap.h"
#include "hw/scsi/emulation.h"

int scsi_emulate_block_limits(uint8_t *outbuf, const SCSIBlockLimits *bl)
{
    /* required VPD size with unmap support */
    memset(outbuf, 0, 0x3c);

    outbuf[0] = bl->wsnz; /* wsnz */

    if (bl->max_io_sectors) {
        /* optimal transfer length granularity.  This field and the optimal
         * transfer length can't be greater than maximum transfer length.
         */
        stw_be_p(outbuf + 2, MIN(bl->min_io_size, bl->max_io_sectors));

        /* maximum transfer length */
        stl_be_p(outbuf + 4, bl->max_io_sectors);

        /* optimal transfer length */
        stl_be_p(outbuf + 8, MIN(bl->opt_io_size, bl->max_io_sectors));
    } else {
        stw_be_p(outbuf + 2, bl->min_io_size);
        stl_be_p(outbuf + 8, bl->opt_io_size);
    }

    /* max unmap LBA count */
    stl_be_p(outbuf + 16, bl->max_unmap_sectors);

    /* max unmap descriptors */
    stl_be_p(outbuf + 20, bl->max_unmap_descr);

    /* optimal unmap granularity; alignment is zero */
    stl_be_p(outbuf + 24, bl->unmap_sectors);

    /* max write same size, make it the same as maximum transfer length */
    stl_be_p(outbuf + 36, bl->max_io_sectors);

    return 0x3c;
}