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; }