SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,

                          uint8_t *buf, void *hba_private)

{

    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);

    SCSIRequest *req;

    SCSICommand cmd;



    if (scsi_req_parse(&cmd, d, buf) != 0) {

        trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);

        req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private);

    } else {

        trace_scsi_req_parsed(d->id, lun, tag, buf[0],

                              cmd.mode, cmd.xfer);

        if (req->cmd.lba != -1) {

            trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0],

                                      cmd.lba);

        }



        if ((d->unit_attention.key == UNIT_ATTENTION ||

             bus->unit_attention.key == UNIT_ATTENTION) &&

            (buf[0] != INQUIRY &&

             buf[0] != REPORT_LUNS &&

             buf[0] != GET_CONFIGURATION &&

             buf[0] != GET_EVENT_STATUS_NOTIFICATION)) {

            req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun,

                                 hba_private);

        } else if (lun != d->lun ||

            buf[0] == REPORT_LUNS ||

            buf[0] == REQUEST_SENSE) {

            req = scsi_req_alloc(&reqops_target_command, d, tag, lun,

                                 hba_private);

        } else {

            req = d->info->alloc_req(d, tag, lun, hba_private);

        }

    }



    req->cmd = cmd;

    switch (buf[0]) {

    case INQUIRY:

        trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]);

        break;

    case TEST_UNIT_READY:

        trace_scsi_test_unit_ready(d->id, lun, tag);

        break;

    case REPORT_LUNS:

        trace_scsi_report_luns(d->id, lun, tag);

        break;

    case REQUEST_SENSE:

        trace_scsi_request_sense(d->id, lun, tag);

        break;

    default:

        break;

    }



    return req;

}
