@@ -33,6 +33,7 @@
/* SCSI Inquiry Pages */
#define SCSI_INQUIRY_STANDARD_NONE 0x00U
#define SCSI_INQUIRY_EVPD_SUPPORTED_PAGES 0x00U
+#define SCSI_INQUIRY_EVPD_BLOCK_LIMITS 0xb0U
union ScsiLun {
uint64_t v64; /* numeric shortcut */
@@ -87,6 +88,19 @@ struct ScsiInquiryEvpdPages {
} __attribute__((packed));
typedef struct ScsiInquiryEvpdPages ScsiInquiryEvpdPages;
+struct ScsiInquiryEvpdBl {
+ uint8_t peripheral_qdt; /* b0, use (b0 & 0x1f) to get SCSI_INQ_RDT */
+ uint8_t page_code;
+ uint16_t page_length;
+ uint8_t b4;
+ uint8_t b5;
+ uint16_t b6;
+ uint32_t max_transfer; /* b8 */
+ uint32_t b12[7]; /* b12..b43 (defined fields) */
+ uint32_t b44[5]; /* b44..b63 (reserved fields) */
+} __attribute__((packed));
+typedef struct ScsiInquiryEvpdBl ScsiInquiryEvpdBl;
+
struct ScsiCdbInquiry {
uint8_t command; /* b0, == 0x12 */
uint8_t b1; /* b1, |= 0x01 (evpd) */
@@ -20,6 +20,7 @@ static VirtioScsiCmdResp resp;
static uint8_t scsi_inquiry_std_response[256];
static ScsiInquiryEvpdPages scsi_inquiry_evpd_pages_response;
+static ScsiInquiryEvpdBl scsi_inquiry_evpd_bl_response;
static inline void vs_assert(bool term, const char **msgs)
{
@@ -262,9 +263,11 @@ int virtio_scsi_read_many(VDev *vdev,
int sector_count;
int f = vdev->blk_factor;
unsigned int data_size;
+ unsigned int max_transfer = MIN_NON_ZERO(vdev->config.scsi.max_sectors,
+ vdev->max_transfer);
do {
- sector_count = MIN_NON_ZERO(sec_num, vdev->config.scsi.max_sectors);
+ sector_count = MIN_NON_ZERO(sec_num, max_transfer);
data_size = sector_count * virtio_get_block_size() * f;
if (!scsi_read_10(vdev, sector * f, sector_count * f, load_addr,
data_size)) {
@@ -321,6 +324,7 @@ void virtio_scsi_setup(VDev *vdev)
uint8_t data[256];
uint32_t data_size = sizeof(data);
ScsiInquiryEvpdPages *evpd = &scsi_inquiry_evpd_pages_response;
+ ScsiInquiryEvpdBl *evpd_bl = &scsi_inquiry_evpd_bl_response;
int i;
vdev->scsi_device = &default_scsi_device;
@@ -378,6 +382,21 @@ void virtio_scsi_setup(VDev *vdev)
for (i = 0; i <= evpd->page_length; i++) {
debug_print_int("supported EVPD page", evpd->byte[i]);
+
+ if (evpd->byte[i] != SCSI_INQUIRY_EVPD_BLOCK_LIMITS) {
+ continue;
+ }
+
+ if (!scsi_inquiry(vdev,
+ SCSI_INQUIRY_EVPD,
+ SCSI_INQUIRY_EVPD_BLOCK_LIMITS,
+ evpd_bl,
+ sizeof(*evpd_bl))) {
+ virtio_scsi_verify_response(&resp, "virtio-scsi:setup:blocklimits");
+ }
+
+ debug_print_int("max transfer", evpd_bl->max_transfer);
+ vdev->max_transfer = evpd_bl->max_transfer;
}
if (!scsi_read_capacity(vdev, data, data_size)) {
@@ -277,6 +277,7 @@ struct VDev {
bool scsi_device_selected;
ScsiDevice selected_scsi_device;
uint64_t netboot_start_addr;
+ uint32_t max_transfer;
};
typedef struct VDev VDev;