Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- uint32_t sata_cmd_dma( SataDev *dev, uint8_t cmd, uint32_t start, uint32_t count, uint8_t *buf ) {
- uint8_t ncs = 0; // Number of Command Slots (NCS)
- uint32_t slot = 0; // Номер слота в списке команд
- uint32_t i;
- HBA_CMD_HEADER *cmdheader = 0;
- HBA_CMD_TBL *cmdtbl = 0;
- FIS_REG_H2D *cmdfis = 0;
- // Определим, сколько командных слотов есть
- ncs =( ( dev -> abar -> cap ) & 0x00001F00 ) >> 8; // Выделяем количество ncs
- printf( "ncs = %d\n\r", ncs );
- // Найдем свободный хедер
- slot = dev -> abar -> ports[ dev -> portNumber ].sact | dev -> abar -> ports[ dev -> portNumber ].ci;
- for( i = 0; i < ncs; ++i ) {
- if( ( slot & 1 ) == 0 ) {
- break;
- }
- slot >>= 1;
- }
- // Проверим, найден ли свободный слот
- if( i == ncs ) {
- #ifdef DEBUG
- printf( "Cannot find free command list entry\n\r" );
- #endif
- return DEVICE_IS_BUSY;
- }
- slot = i;
- // Слот определили, настраиваем указатели
- // Настроимся на наш слот
- cmdheader = ( HBA_CMD_HEADER* )dev -> abar -> ports[ dev -> portNumber ].clb;
- cmdheader += slot;
- // Устанавливаем в нем все необходимые поля
- cmdheader -> cfl = sizeof( FIS_REG_H2D ) / sizeof( uint32_t ); // Размер структуры запроса в двойных словах
- cmdheader -> w = ( cmd == ATA_CMD_WRITE_DMA_EXT ? 1 : 0 ); // Направление обмена данными 1: H2D, 0: D2H
- cmdheader -> prdtl = ( uint16_t )( ( count - 1 ) >> 4 ) + 1; // Формула получения количества записей
- // Настраиваем таблицу команд, состоящую из заголовка и записей (0-64535)
- cmdtbl = ( HBA_CMD_TBL* )( cmdheader -> ctba );
- memset( cmdtbl, 0, sizeof( HBA_CMD_TBL ) + ( cmdheader -> prdtl - 1 ) * sizeof( HBA_PRDT_ENTRY ) );
- // Устанавливаем команду в структуру H2D
- cmdfis = ( FIS_REG_H2D* )( &cmdtbl -> cfis );
- memset( cmdfis, 0, sizeof( FIS_REG_H2D ) );
- cmdfis -> fis_type = FIS_TYPE_REG_H2D; // Структура Register FIS - host to device
- cmdfis -> cmd_reg = cmd; // Устанавливаем команду
- cmdfis -> cmd = 1; // Работаем с командным регистром
- // Если это команды с данными, то грузим LBA и буфер
- printf( "cmdheader -> prdtl - 1 = %d\n\r", cmdheader -> prdtl - 1 );
- if( cmd == ATA_CMD_READ_DMA_EXT || cmd == ATA_CMD_WRITE_DMA_EXT ) {
- // Загружаем данные
- for( i = 0; i < cmdheader -> prdtl - 1; ++i ) {
- cmdtbl -> prdt_entry[ i ].dba = ( uint32_t )buf; // Устанавливаем указатель на буфер
- cmdtbl -> prdt_entry[ i ].dbc = 8 * 1024; // Размер блока данных
- cmdtbl -> prdt_entry[ i ].i = 1; // И включаем прерывания
- buf += 8 * 1024; // Корректируем указатель на буфер
- count -= 16; // Корректируем размер оставшихся данных
- }
- printf( "Count = %d\n\r", count );
- // Здесь еще надо обработать последнюю запись
- cmdtbl -> prdt_entry[ i ].dba = ( uint32_t )buf; // Устанавливаем указатель на буфер
- cmdtbl -> prdt_entry[ i ].dbc = count << 9; // Размер блока данных
- cmdtbl -> prdt_entry[ i ].i = 1; // И включаем прерывания
- // Загружаем LBA
- cmdfis -> lba0 = ( uint8_t )start; // LBA low
- cmdfis -> lba1 = ( uint8_t )( start >> 8 ); // LBA mid
- cmdfis -> lba2 = ( uint8_t )( start >> 16 ); // LBA high
- cmdfis -> count_l = count; // Количество секторов
- cmdfis -> device = 1 << 6; // Режим адресации - LBA
- }
- if( cmd == ATA_CMD_IDENTIFY ) {
- cmdtbl -> prdt_entry[ i ].dba = ( uint32_t )buf; // Устанавливаем указатель на буфер
- cmdtbl -> prdt_entry[ i ].dbc = count << 9; // Размер блока данных
- cmdtbl -> prdt_entry[ i ].i = 1; // И включаем прерывания
- // Загружаем LBA
- cmdfis -> count_l = count; // Количество секторов
- cmdfis -> device = 1 << 6; // Режим адресации - LBA
- }
- // Ну и собственно выполняем команду
- dev -> abar -> ports[ dev -> portNumber ].ci = 1 << slot; // Issue command
- // Ждем пока на нашем порту произойдет прерывание
- while( 1 ) {
- if( dev -> abar -> is & ( 1 << dev -> portNumber ) ) {
- printf( "IS.IPS[ %d ] done\n\r", dev -> portNumber );
- break;
- }
- }
- // Читаем теперь читаем PxIS
- printf( "(is): " );
- binary( dev -> abar -> ports[ dev -> portNumber ].is, D );
- if( dev -> abar -> ports[ dev -> portNumber ].is != 0x00000001 ) {
- printf( "Error while doing operation (serr): " );
- binary( dev -> abar -> ports[ dev -> portNumber ].serr, D );
- return DEVICE_ERROR;
- }
- // Очищаем IS
- dev -> abar -> ports[ dev -> portNumber ].is = 0;
- // Очищаем IS.IPS
- dev -> abar -> is &= ( ~( 1 << dev -> portNumber ) );
- printf( "IS.IPS cleared\n\r" );
- // Дождемся выполнения команды
- while( 1 ) {
- // Если бит сброшен, то команда выполнена
- if( ( dev -> abar -> ports[ dev -> portNumber ].ci & ( 1 << slot ) ) == 0 ) {
- break;
- }
- }
- return DONE;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement