libqos/ahci: add NCQ frame support
NCQ frames are generated a little differently than their non-NCQ cousins. Add support for them. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-id: 1435016308-6150-11-git-send-email-jsnow@redhat.com
This commit is contained in:
		
							parent
							
								
									40d29928ca
								
							
						
					
					
						commit
						cb45304108
					
				@ -695,19 +695,34 @@ static void command_header_init(AHCICommand *cmd)
 | 
				
			|||||||
static void command_table_init(AHCICommand *cmd)
 | 
					static void command_table_init(AHCICommand *cmd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    RegH2DFIS *fis = &(cmd->fis);
 | 
					    RegH2DFIS *fis = &(cmd->fis);
 | 
				
			||||||
 | 
					    uint16_t sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fis->fis_type = REG_H2D_FIS;
 | 
					    fis->fis_type = REG_H2D_FIS;
 | 
				
			||||||
    fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */
 | 
					    fis->flags = REG_H2D_FIS_CMD; /* "Command" bit */
 | 
				
			||||||
    fis->command = cmd->name;
 | 
					    fis->command = cmd->name;
 | 
				
			||||||
    cmd->fis.feature_low = 0x00;
 | 
					
 | 
				
			||||||
    cmd->fis.feature_high = 0x00;
 | 
					    if (cmd->props->ncq) {
 | 
				
			||||||
 | 
					        NCQFIS *ncqfis = (NCQFIS *)fis;
 | 
				
			||||||
 | 
					        /* NCQ is weird and re-uses FIS frames for unrelated data.
 | 
				
			||||||
 | 
					         * See SATA 3.2, 13.6.4.1 READ FPDMA QUEUED for an example. */
 | 
				
			||||||
 | 
					        ncqfis->sector_low = sect_count & 0xFF;
 | 
				
			||||||
 | 
					        ncqfis->sector_hi = (sect_count >> 8) & 0xFF;
 | 
				
			||||||
 | 
					        ncqfis->device = NCQ_DEVICE_MAGIC;
 | 
				
			||||||
 | 
					        /* Force Unit Access is bit 7 in the device register */
 | 
				
			||||||
 | 
					        ncqfis->tag = 0;  /* bits 3-7 are the NCQ tag */
 | 
				
			||||||
 | 
					        ncqfis->prio = 0; /* bits 6,7 are a prio tag */
 | 
				
			||||||
 | 
					        /* RARC bit is bit 0 of TAG field */
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        fis->feature_low = 0x00;
 | 
				
			||||||
 | 
					        fis->feature_high = 0x00;
 | 
				
			||||||
        if (cmd->props->lba28 || cmd->props->lba48) {
 | 
					        if (cmd->props->lba28 || cmd->props->lba48) {
 | 
				
			||||||
        cmd->fis.device = ATA_DEVICE_LBA;
 | 
					            fis->device = ATA_DEVICE_LBA;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE);
 | 
					        fis->count = (cmd->xbytes / AHCI_SECTOR_SIZE);
 | 
				
			||||||
    cmd->fis.icc = 0x00;
 | 
					    }
 | 
				
			||||||
    cmd->fis.control = 0x00;
 | 
					    fis->icc = 0x00;
 | 
				
			||||||
    memset(cmd->fis.aux, 0x00, ARRAY_SIZE(cmd->fis.aux));
 | 
					    fis->control = 0x00;
 | 
				
			||||||
 | 
					    memset(fis->aux, 0x00, ARRAY_SIZE(fis->aux));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AHCICommand *ahci_command_create(uint8_t command_name)
 | 
					AHCICommand *ahci_command_create(uint8_t command_name)
 | 
				
			||||||
@ -721,6 +736,7 @@ AHCICommand *ahci_command_create(uint8_t command_name)
 | 
				
			|||||||
    g_assert(!(props->lba28 && props->lba48));
 | 
					    g_assert(!(props->lba28 && props->lba48));
 | 
				
			||||||
    g_assert(!(props->read && props->write));
 | 
					    g_assert(!(props->read && props->write));
 | 
				
			||||||
    g_assert(!props->size || props->data);
 | 
					    g_assert(!props->size || props->data);
 | 
				
			||||||
 | 
					    g_assert(!props->ncq || (props->ncq && props->lba48));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Defaults and book-keeping */
 | 
					    /* Defaults and book-keeping */
 | 
				
			||||||
    cmd->props = props;
 | 
					    cmd->props = props;
 | 
				
			||||||
@ -789,6 +805,8 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
 | 
				
			|||||||
void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
 | 
					void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
 | 
				
			||||||
                            unsigned prd_size)
 | 
					                            unsigned prd_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    uint16_t sect_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Each PRD can describe up to 4MiB, and must not be odd. */
 | 
					    /* Each PRD can describe up to 4MiB, and must not be odd. */
 | 
				
			||||||
    g_assert_cmphex(prd_size, <=, 4096 * 1024);
 | 
					    g_assert_cmphex(prd_size, <=, 4096 * 1024);
 | 
				
			||||||
    g_assert_cmphex(prd_size & 0x01, ==, 0x00);
 | 
					    g_assert_cmphex(prd_size & 0x01, ==, 0x00);
 | 
				
			||||||
@ -796,7 +814,15 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
 | 
				
			|||||||
        cmd->prd_size = prd_size;
 | 
					        cmd->prd_size = prd_size;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    cmd->xbytes = xbytes;
 | 
					    cmd->xbytes = xbytes;
 | 
				
			||||||
    cmd->fis.count = (cmd->xbytes / AHCI_SECTOR_SIZE);
 | 
					    sect_count = (cmd->xbytes / AHCI_SECTOR_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (cmd->props->ncq) {
 | 
				
			||||||
 | 
					        NCQFIS *nfis = (NCQFIS *)&(cmd->fis);
 | 
				
			||||||
 | 
					        nfis->sector_low = sect_count & 0xFF;
 | 
				
			||||||
 | 
					        nfis->sector_hi = (sect_count >> 8) & 0xFF;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        cmd->fis.count = sect_count;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    cmd->header.prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size);
 | 
					    cmd->header.prdtl = size_to_prdtl(cmd->xbytes, cmd->prd_size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -291,8 +291,9 @@ enum {
 | 
				
			|||||||
#define CMDH_PMP      (0xF000)
 | 
					#define CMDH_PMP      (0xF000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ATA device register masks */
 | 
					/* ATA device register masks */
 | 
				
			||||||
#define ATA_DEVICE_MAGIC 0xA0
 | 
					#define ATA_DEVICE_MAGIC 0xA0 /* used in ata1-3 */
 | 
				
			||||||
#define ATA_DEVICE_LBA   0x40
 | 
					#define ATA_DEVICE_LBA   0x40
 | 
				
			||||||
 | 
					#define NCQ_DEVICE_MAGIC 0x40 /* for ncq device registers */
 | 
				
			||||||
#define ATA_DEVICE_DRIVE 0x10
 | 
					#define ATA_DEVICE_DRIVE 0x10
 | 
				
			||||||
#define ATA_DEVICE_HEAD  0x0F
 | 
					#define ATA_DEVICE_HEAD  0x0F
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -396,6 +397,32 @@ typedef struct RegH2DFIS {
 | 
				
			|||||||
    uint8_t aux[4];
 | 
					    uint8_t aux[4];
 | 
				
			||||||
} __attribute__((__packed__)) RegH2DFIS;
 | 
					} __attribute__((__packed__)) RegH2DFIS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Register host-to-device FIS structure, for NCQ commands.
 | 
				
			||||||
 | 
					 * Actually just a RegH2DFIS, but with fields repurposed.
 | 
				
			||||||
 | 
					 * Repurposed fields are annotated below.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					typedef struct NCQFIS {
 | 
				
			||||||
 | 
					    /* DW0 */
 | 
				
			||||||
 | 
					    uint8_t fis_type;
 | 
				
			||||||
 | 
					    uint8_t flags;
 | 
				
			||||||
 | 
					    uint8_t command;
 | 
				
			||||||
 | 
					    uint8_t sector_low; /* H2D: Feature 7:0 */
 | 
				
			||||||
 | 
					    /* DW1 */
 | 
				
			||||||
 | 
					    uint8_t lba_lo[3];
 | 
				
			||||||
 | 
					    uint8_t device;
 | 
				
			||||||
 | 
					    /* DW2 */
 | 
				
			||||||
 | 
					    uint8_t lba_hi[3];
 | 
				
			||||||
 | 
					    uint8_t sector_hi; /* H2D: Feature 15:8 */
 | 
				
			||||||
 | 
					    /* DW3 */
 | 
				
			||||||
 | 
					    uint8_t tag;       /* H2D: Count 0:7 */
 | 
				
			||||||
 | 
					    uint8_t prio;      /* H2D: Count 15:8 */
 | 
				
			||||||
 | 
					    uint8_t icc;
 | 
				
			||||||
 | 
					    uint8_t control;
 | 
				
			||||||
 | 
					    /* DW4 */
 | 
				
			||||||
 | 
					    uint8_t aux[4];
 | 
				
			||||||
 | 
					} __attribute__((__packed__)) NCQFIS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Command List entry structure.
 | 
					 * Command List entry structure.
 | 
				
			||||||
 * The command list contains between 1-32 of these structures.
 | 
					 * The command list contains between 1-32 of these structures.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user