static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)

{

    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);

    int buflen = 0;

    int start;



    if (req->cmd.buf[1] & 0x1) {

        /* Vital product data */

        uint8_t page_code = req->cmd.buf[2];



        outbuf[buflen++] = s->qdev.type & 0x1f;

        outbuf[buflen++] = page_code ; // this page

        outbuf[buflen++] = 0x00;

        outbuf[buflen++] = 0x00;

        start = buflen;



        switch (page_code) {

        case 0x00: /* Supported page codes, mandatory */

        {

            DPRINTF("Inquiry EVPD[Supported pages] "

                    "buffer size %zd\n", req->cmd.xfer);

            outbuf[buflen++] = 0x00; // list of supported pages (this page)

            if (s->serial) {

                outbuf[buflen++] = 0x80; // unit serial number

            }

            outbuf[buflen++] = 0x83; // device identification

            if (s->qdev.type == TYPE_DISK) {

                outbuf[buflen++] = 0xb0; // block limits

                outbuf[buflen++] = 0xb2; // thin provisioning

            }

            break;

        }

        case 0x80: /* Device serial number, optional */

        {

            int l;



            if (!s->serial) {

                DPRINTF("Inquiry (EVPD[Serial number] not supported\n");

                return -1;

            }



            l = strlen(s->serial);

            if (l > 20) {

                l = 20;

            }



            DPRINTF("Inquiry EVPD[Serial number] "

                    "buffer size %zd\n", req->cmd.xfer);

            memcpy(outbuf+buflen, s->serial, l);

            buflen += l;

            break;

        }



        case 0x83: /* Device identification page, mandatory */

        {

            const char *str = s->serial ?: bdrv_get_device_name(s->qdev.conf.bs);

            int max_len = s->serial ? 20 : 255 - 8;

            int id_len = strlen(str);



            if (id_len > max_len) {

                id_len = max_len;

            }

            DPRINTF("Inquiry EVPD[Device identification] "

                    "buffer size %zd\n", req->cmd.xfer);



            outbuf[buflen++] = 0x2; // ASCII

            outbuf[buflen++] = 0;   // not officially assigned

            outbuf[buflen++] = 0;   // reserved

            outbuf[buflen++] = id_len; // length of data following

            memcpy(outbuf+buflen, str, id_len);

            buflen += id_len;



            if (s->wwn) {

                outbuf[buflen++] = 0x1; // Binary

                outbuf[buflen++] = 0x3; // NAA

                outbuf[buflen++] = 0;   // reserved

                outbuf[buflen++] = 8;

                stq_be_p(&outbuf[buflen], s->wwn);

                buflen += 8;

            }

            break;

        }

        case 0xb0: /* block limits */

        {

            unsigned int unmap_sectors =

                    s->qdev.conf.discard_granularity / s->qdev.blocksize;

            unsigned int min_io_size =

                    s->qdev.conf.min_io_size / s->qdev.blocksize;

            unsigned int opt_io_size =

                    s->qdev.conf.opt_io_size / s->qdev.blocksize;



            if (s->qdev.type == TYPE_ROM) {

                DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",

                        page_code);

                return -1;

            }

            /* required VPD size with unmap support */

            buflen = 0x40;

            memset(outbuf + 4, 0, buflen - 4);



            /* optimal transfer length granularity */

            outbuf[6] = (min_io_size >> 8) & 0xff;

            outbuf[7] = min_io_size & 0xff;



            /* optimal transfer length */

            outbuf[12] = (opt_io_size >> 24) & 0xff;

            outbuf[13] = (opt_io_size >> 16) & 0xff;

            outbuf[14] = (opt_io_size >> 8) & 0xff;

            outbuf[15] = opt_io_size & 0xff;



            /* optimal unmap granularity */

            outbuf[28] = (unmap_sectors >> 24) & 0xff;

            outbuf[29] = (unmap_sectors >> 16) & 0xff;

            outbuf[30] = (unmap_sectors >> 8) & 0xff;

            outbuf[31] = unmap_sectors & 0xff;

            break;

        }

        case 0xb2: /* thin provisioning */

        {

            buflen = 8;

            outbuf[4] = 0;

            outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */

            outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;

            outbuf[7] = 0;

            break;

        }

        default:

            return -1;

        }

        /* done with EVPD */

        assert(buflen - start <= 255);

        outbuf[start - 1] = buflen - start;

        return buflen;

    }



    /* Standard INQUIRY data */

    if (req->cmd.buf[2] != 0) {

        return -1;

    }



    /* PAGE CODE == 0 */

    buflen = req->cmd.xfer;

    if (buflen > SCSI_MAX_INQUIRY_LEN) {

        buflen = SCSI_MAX_INQUIRY_LEN;

    }

    memset(outbuf, 0, buflen);



    outbuf[0] = s->qdev.type & 0x1f;

    outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0;



    strpadcpy((char *) &outbuf[16], 16, s->product, ' ');

    strpadcpy((char *) &outbuf[8], 8, s->vendor, ' ');



    memset(&outbuf[32], 0, 4);

    memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version)));

    /*

     * We claim conformance to SPC-3, which is required for guests

     * to ask for modern features like READ CAPACITY(16) or the

     * block characteristics VPD page by default.  Not all of SPC-3

     * is actually implemented, but we're good enough.

     */

    outbuf[2] = 5;

    outbuf[3] = 2 | 0x10; /* Format 2, HiSup */



    if (buflen > 36) {

        outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */

    } else {

        /* If the allocation length of CDB is too small,

               the additional length is not adjusted */

        outbuf[4] = 36 - 5;

    }



    /* Sync data transfer and TCQ.  */

    outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);

    return buflen;

}

static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)

{

    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);

    int buflen = 0;

    int start;



    if (req->cmd.buf[1] & 0x1) {

        

        uint8_t page_code = req->cmd.buf[2];



        outbuf[buflen++] = s->qdev.type & 0x1f;

        outbuf[buflen++] = page_code ; 

        outbuf[buflen++] = 0x00;

        outbuf[buflen++] = 0x00;

        start = buflen;



        switch (page_code) {

        case 0x00: 

        {

            DPRINTF("Inquiry EVPD[Supported pages] "

                    "buffer size %zd\n", req->cmd.xfer);

            outbuf[buflen++] = 0x00; 

            if (s->serial) {

                outbuf[buflen++] = 0x80; 

            }

            outbuf[buflen++] = 0x83; 

            if (s->qdev.type == TYPE_DISK) {

                outbuf[buflen++] = 0xb0; 

                outbuf[buflen++] = 0xb2; 

            }

            break;

        }

        case 0x80: 

        {

            int l;



            if (!s->serial) {

                DPRINTF("Inquiry (EVPD[Serial number] not supported\n");

                return -1;

            }



            l = strlen(s->serial);

            if (l > 20) {

                l = 20;

            }



            DPRINTF("Inquiry EVPD[Serial number] "

                    "buffer size %zd\n", req->cmd.xfer);

            memcpy(outbuf+buflen, s->serial, l);

            buflen += l;

            break;

        }



        case 0x83: 

        {

            const char *str = s->serial ?: bdrv_get_device_name(s->qdev.conf.bs);

            int max_len = s->serial ? 20 : 255 - 8;

            int id_len = strlen(str);



            if (id_len > max_len) {

                id_len = max_len;

            }

            DPRINTF("Inquiry EVPD[Device identification] "

                    "buffer size %zd\n", req->cmd.xfer);



            outbuf[buflen++] = 0x2; 

            outbuf[buflen++] = 0;   

            outbuf[buflen++] = 0;   

            outbuf[buflen++] = id_len; 

            memcpy(outbuf+buflen, str, id_len);

            buflen += id_len;



            if (s->wwn) {

                outbuf[buflen++] = 0x1; 

                outbuf[buflen++] = 0x3; 

                outbuf[buflen++] = 0;   

                outbuf[buflen++] = 8;

                stq_be_p(&outbuf[buflen], s->wwn);

                buflen += 8;

            }

            break;

        }

        case 0xb0: 

        {

            unsigned int unmap_sectors =

                    s->qdev.conf.discard_granularity / s->qdev.blocksize;

            unsigned int min_io_size =

                    s->qdev.conf.min_io_size / s->qdev.blocksize;

            unsigned int opt_io_size =

                    s->qdev.conf.opt_io_size / s->qdev.blocksize;



            if (s->qdev.type == TYPE_ROM) {

                DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",

                        page_code);

                return -1;

            }

            

            buflen = 0x40;

            memset(outbuf + 4, 0, buflen - 4);



            

            outbuf[6] = (min_io_size >> 8) & 0xff;

            outbuf[7] = min_io_size & 0xff;



            

            outbuf[12] = (opt_io_size >> 24) & 0xff;

            outbuf[13] = (opt_io_size >> 16) & 0xff;

            outbuf[14] = (opt_io_size >> 8) & 0xff;

            outbuf[15] = opt_io_size & 0xff;



            

            outbuf[28] = (unmap_sectors >> 24) & 0xff;

            outbuf[29] = (unmap_sectors >> 16) & 0xff;

            outbuf[30] = (unmap_sectors >> 8) & 0xff;

            outbuf[31] = unmap_sectors & 0xff;

            break;

        }

        case 0xb2: 

        {

            buflen = 8;

            outbuf[4] = 0;

            outbuf[5] = 0xe0; 

            outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;

            outbuf[7] = 0;

            break;

        }

        default:

            return -1;

        }

        

        assert(buflen - start <= 255);

        outbuf[start - 1] = buflen - start;

        return buflen;

    }



    

    if (req->cmd.buf[2] != 0) {

        return -1;

    }



    

    buflen = req->cmd.xfer;

    if (buflen > SCSI_MAX_INQUIRY_LEN) {

        buflen = SCSI_MAX_INQUIRY_LEN;

    }

    memset(outbuf, 0, buflen);



    outbuf[0] = s->qdev.type & 0x1f;

    outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0;



    strpadcpy((char *) &outbuf[16], 16, s->product, ' ');

    strpadcpy((char *) &outbuf[8], 8, s->vendor, ' ');



    memset(&outbuf[32], 0, 4);

    memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version)));

    











    outbuf[2] = 5;

    outbuf[3] = 2 | 0x10; 



    if (buflen > 36) {

        outbuf[4] = buflen - 5; 

    } else {

        



        outbuf[4] = 36 - 5;

    }



    

    outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);

    return buflen;

}

    memset(outbuf, 0, buflen);
static int FUNC_0(SCSIRequest *VAR_0, uint8_t *VAR_1)

{

    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, VAR_0->dev);

    int VAR_2 = 0;

    int VAR_3;



    if (VAR_0->cmd.buf[1] & 0x1) {

        

        uint8_t page_code = VAR_0->cmd.buf[2];



        VAR_1[VAR_2++] = s->qdev.type & 0x1f;

        VAR_1[VAR_2++] = page_code ; 

        VAR_1[VAR_2++] = 0x00;

        VAR_1[VAR_2++] = 0x00;

        VAR_3 = VAR_2;



        switch (page_code) {

        case 0x00: 

        {

            DPRINTF("Inquiry EVPD[Supported pages] "

                    "buffer size %zd\n", VAR_0->cmd.xfer);

            VAR_1[VAR_2++] = 0x00; 

            if (s->serial) {

                VAR_1[VAR_2++] = 0x80; 

            }

            VAR_1[VAR_2++] = 0x83; 

            if (s->qdev.type == TYPE_DISK) {

                VAR_1[VAR_2++] = 0xb0; 

                VAR_1[VAR_2++] = 0xb2; 

            }

            break;

        }

        case 0x80: 

        {

            int VAR_4;



            if (!s->serial) {

                DPRINTF("Inquiry (EVPD[Serial number] not supported\n");

                return -1;

            }



            VAR_4 = strlen(s->serial);

            if (VAR_4 > 20) {

                VAR_4 = 20;

            }



            DPRINTF("Inquiry EVPD[Serial number] "

                    "buffer size %zd\n", VAR_0->cmd.xfer);

            memcpy(VAR_1+VAR_2, s->serial, VAR_4);

            VAR_2 += VAR_4;

            break;

        }



        case 0x83: 

        {

            const char *VAR_5 = s->serial ?: bdrv_get_device_name(s->qdev.conf.bs);

            int VAR_6 = s->serial ? 20 : 255 - 8;

            int VAR_7 = strlen(VAR_5);



            if (VAR_7 > VAR_6) {

                VAR_7 = VAR_6;

            }

            DPRINTF("Inquiry EVPD[Device identification] "

                    "buffer size %zd\n", VAR_0->cmd.xfer);



            VAR_1[VAR_2++] = 0x2; 

            VAR_1[VAR_2++] = 0;   

            VAR_1[VAR_2++] = 0;   

            VAR_1[VAR_2++] = VAR_7; 

            memcpy(VAR_1+VAR_2, VAR_5, VAR_7);

            VAR_2 += VAR_7;



            if (s->wwn) {

                VAR_1[VAR_2++] = 0x1; 

                VAR_1[VAR_2++] = 0x3; 

                VAR_1[VAR_2++] = 0;   

                VAR_1[VAR_2++] = 8;

                stq_be_p(&VAR_1[VAR_2], s->wwn);

                VAR_2 += 8;

            }

            break;

        }

        case 0xb0: 

        {

            unsigned int VAR_8 =

                    s->qdev.conf.discard_granularity / s->qdev.blocksize;

            unsigned int VAR_9 =

                    s->qdev.conf.VAR_9 / s->qdev.blocksize;

            unsigned int VAR_10 =

                    s->qdev.conf.VAR_10 / s->qdev.blocksize;



            if (s->qdev.type == TYPE_ROM) {

                DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",

                        page_code);

                return -1;

            }

            

            VAR_2 = 0x40;

            memset(VAR_1 + 4, 0, VAR_2 - 4);



            

            VAR_1[6] = (VAR_9 >> 8) & 0xff;

            VAR_1[7] = VAR_9 & 0xff;



            

            VAR_1[12] = (VAR_10 >> 24) & 0xff;

            VAR_1[13] = (VAR_10 >> 16) & 0xff;

            VAR_1[14] = (VAR_10 >> 8) & 0xff;

            VAR_1[15] = VAR_10 & 0xff;



            

            VAR_1[28] = (VAR_8 >> 24) & 0xff;

            VAR_1[29] = (VAR_8 >> 16) & 0xff;

            VAR_1[30] = (VAR_8 >> 8) & 0xff;

            VAR_1[31] = VAR_8 & 0xff;

            break;

        }

        case 0xb2: 

        {

            VAR_2 = 8;

            VAR_1[4] = 0;

            VAR_1[5] = 0xe0; 

            VAR_1[6] = s->qdev.conf.discard_granularity ? 2 : 1;

            VAR_1[7] = 0;

            break;

        }

        default:

            return -1;

        }

        

        assert(VAR_2 - VAR_3 <= 255);

        VAR_1[VAR_3 - 1] = VAR_2 - VAR_3;

        return VAR_2;

    }



    

    if (VAR_0->cmd.buf[2] != 0) {

        return -1;

    }



    

    VAR_2 = VAR_0->cmd.xfer;

    if (VAR_2 > SCSI_MAX_INQUIRY_LEN) {

        VAR_2 = SCSI_MAX_INQUIRY_LEN;

    }

    memset(VAR_1, 0, VAR_2);



    VAR_1[0] = s->qdev.type & 0x1f;

    VAR_1[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0;



    strpadcpy((char *) &VAR_1[16], 16, s->product, ' ');

    strpadcpy((char *) &VAR_1[8], 8, s->vendor, ' ');



    memset(&VAR_1[32], 0, 4);

    memcpy(&VAR_1[32], s->version, MIN(4, strlen(s->version)));

    











    VAR_1[2] = 5;

    VAR_1[3] = 2 | 0x10; 



    if (VAR_2 > 36) {

        VAR_1[4] = VAR_2 - 5; 

    } else {

        



        VAR_1[4] = 36 - 5;

    }



    

    VAR_1[7] = 0x10 | (VAR_0->bus->info->tcq ? 0x02 : 0);

    return VAR_2;

}

static int FUNC_0(SCSIRequest *VAR_0, uint8_t *VAR_1)
{ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, VAR_0->dev); int VAR_2 = 0; int VAR_3; if (VAR_0->cmd.buf[1] & 0x1) { uint8_t page_code = VAR_0->cmd.buf[2]; VAR_1[VAR_2++] = s->qdev.type & 0x1f; VAR_1[VAR_2++] = page_code ; VAR_1[VAR_2++] = 0x00; VAR_1[VAR_2++] = 0x00; VAR_3 = VAR_2; switch (page_code) { case 0x00:
{ DPRINTF("Inquiry EVPD[Supported pages] "
"buffer size %zd\n", VAR_0->cmd.xfer); VAR_1[VAR_2++] = 0x00; if (s->serial) { VAR_1[VAR_2++] = 0x80; } VAR_1[VAR_2++] = 0x83; if (s->qdev.type == TYPE_DISK) { VAR_1[VAR_2++] = 0xb0; VAR_1[VAR_2++] = 0xb2; } break; } case 0x80:
{ int VAR_4; if (!s->serial) { DPRINTF("Inquiry (EVPD[Serial number] not supported\n"); return -1; } VAR_4 = strlen(s->serial); if (VAR_4 > 20) { VAR_4 = 20; } DPRINTF("Inquiry EVPD[Serial number] "
"buffer size %zd\n", VAR_0->cmd.xfer); memcpy(VAR_1+VAR_2, s->serial, VAR_4); VAR_2 += VAR_4; break; } case 0x83:
{ const char *VAR_5 = s->serial ?: bdrv_get_device_name(s->qdev.conf.bs); int VAR_6 = s->serial ? 20 : 255 - 8; int VAR_7 = strlen(VAR_5); if (VAR_7 > VAR_6) { VAR_7 = VAR_6; } DPRINTF("Inquiry EVPD[Device identification] "
"buffer size %zd\n", VAR_0->cmd.xfer); VAR_1[VAR_2++] = 0x2; VAR_1[VAR_2++] = 0; VAR_1[VAR_2++] = 0; VAR_1[VAR_2++] = VAR_7; memcpy(VAR_1+VAR_2, VAR_5, VAR_7); VAR_2 += VAR_7; if (s->wwn) { VAR_1[VAR_2++] = 0x1; VAR_1[VAR_2++] = 0x3; VAR_1[VAR_2++] = 0; VAR_1[VAR_2++] = 8; stq_be_p(&VAR_1[VAR_2], s->wwn); VAR_2 += 8; } break; } case 0xb0:
{ unsigned int VAR_8 =
s->qdev.conf.discard_granularity / s->qdev.blocksize; unsigned int VAR_9 =
s->qdev.conf.VAR_9 / s->qdev.blocksize; unsigned int VAR_10 =
s->qdev.conf.VAR_10 / s->qdev.blocksize; if (s->qdev.type == TYPE_ROM) { DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
page_code); return -1; } VAR_2 = 0x40; memset(VAR_1 + 4, 0, VAR_2 - 4); VAR_1[6] = (VAR_9 >> 8) & 0xff; VAR_1[7] = VAR_9 & 0xff; VAR_1[12] = (VAR_10 >> 24) & 0xff; VAR_1[13] = (VAR_10 >> 16) & 0xff; VAR_1[14] = (VAR_10 >> 8) & 0xff; VAR_1[15] = VAR_10 & 0xff; VAR_1[28] = (VAR_8 >> 24) & 0xff; VAR_1[29] = (VAR_8 >> 16) & 0xff; VAR_1[30] = (VAR_8 >> 8) & 0xff; VAR_1[31] = VAR_8 & 0xff; break; } case 0xb2:
{ VAR_2 = 8; VAR_1[4] = 0; VAR_1[5] = 0xe0; VAR_1[6] = s->qdev.conf.discard_granularity ? 2 : 1; VAR_1[7] = 0; break; } default:
return -1; } assert(VAR_2 - VAR_3 <= 255); VAR_1[VAR_3 - 1] = VAR_2 - VAR_3; return VAR_2; } if (VAR_0->cmd.buf[2] != 0) { return -1; } VAR_2 = VAR_0->cmd.xfer; if (VAR_2 > SCSI_MAX_INQUIRY_LEN) { VAR_2 = SCSI_MAX_INQUIRY_LEN; } memset(VAR_1, 0, VAR_2); VAR_1[0] = s->qdev.type & 0x1f; VAR_1[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0; strpadcpy((char *) &VAR_1[16], 16, s->product, ' '); strpadcpy((char *) &VAR_1[8], 8, s->vendor, ' '); memset(&VAR_1[32], 0, 4); memcpy(&VAR_1[32], s->version, MIN(4, strlen(s->version))); VAR_1[2] = 5; VAR_1[3] = 2 | 0x10; if (VAR_2 > 36) { VAR_1[4] = VAR_2 - 5; } else { VAR_1[4] = 36 - 5; } VAR_1[7] = 0x10 | (VAR_0->bus->info->tcq ? 0x02 : 0); return VAR_2; }