Emulation of the block limits VPD page called back into scsi-disk.c, which however expected the request to be for a SCSIDiskState and accessed a scsi-generic device outside the bounds of its struct (namely to retrieve s->max_unmap_size and s->max_io_size). To avoid this, move the emulation code to a separate function that takes a new SCSIBlockLimits struct and marshals it into the VPD response format. Reported-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
		
			
				
	
	
		
			43 lines
		
	
	
		
			1.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			43 lines
		
	
	
		
			1.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#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;
 | 
						|
}
 |