Ожидание готовности HDD

Тема в разделе "WASM.OS.DEVEL", создана пользователем drem1lin, 3 май 2011.

  1. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Доброго времени суток, возник вопрос с корректным вклинивание в очередь команд hdd. То есть, есть некий хард работающий в режиме PIO, и происходит обмен информацией между ним и ОС. Нужно в случайный момент времени выполнить мою команду, как правильно дождаться что б hdd был готов к исполнению команды? У меня есть 2 варианта, этот я взял из книги Кулакова:
    Код (Text):
    1.   debug 15h
    2. @@WaitHDReady:
    3.     ; Проверить время ожидания
    4.     mov     EAX,ds:[046Ch]
    5.     sub     EAX,ds:[OPERATION_TIMER]
    6.     cmp     EAX,BSY_WAIT_TIME
    7.     ja @@Err1 ;ошибка тайм-аута
    8.     ; Прочитать регистр состояния
    9.     in      AL,DX
    10.     ; Проверить состояние сигнала BSY
    11.     test    AL,80h
    12.     jnz     @@WaitHDReady
    13.     ; Проверить состояние сигнала DRQ
    14.     test    AL,08h
    15.     jnz     @@WaitHDReady
    16.     debug 16h
    Этот я написал опираясь на спецификацию ATA:
    Код (Text):
    1.     debug 15h
    2.     push 500h
    3. @@WaitHDReady:
    4.     ; Проверить время ожидания
    5.     pop eax
    6.     dec eax
    7.     cmp EAX, 0
    8.     je @@Error1 ;ошибка тайм-аута
    9.     push eax
    10.     ; Прочитать регистр состояния
    11.     in      AL,DX
    12.     ; Проверить состояние сигнала BSY
    13.     test    AL,80h
    14.     jnz     @@WaitHDReady
    15.     ;Проверить состояние сигнала DRDY
    16.     test    AL,40h
    17.     jz     @@WaitHDReady
    18.     pop eax
    19.     debug 16h
    Какой из них более верный, или как это ожидание надо организовывать в принципе? Просто просматривая форум я не нашел однозначного ответа, нашел много споров как надо, а результат выцепить не смог(
     
  2. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    Второй точно не правильный. Читай спецификацию внимательно. Советую обратить внимание на 9 главу.
     
  3. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Сегодня почитаю, а в чем код не правильный? по логике я жду установки флага готовности устройства к приему команды. А выполнение цикла 500 раз это ограничение что бы не зависало, потом вставлю что нибудь более адекватное, просто int 15h я не могу, а другие варианты пока даже не искал
     
  4. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Я почитал 9 главу, сложно конечно, но мои вопросы она не особо убрала. Зачада чуть чуть видо изменилась: необходимо определить момент когда хард не занят и тогда его использовать. А какое состояние флагов этому соответствует? BSY = 0 & DRQ = 0 & DRDY = 1? И как определить что диск работате в UDMA и что он свободен?
     
  5. T800

    T800 Member

    Публикаций:
    0
    Регистрация:
    7 дек 2006
    Сообщения:
    293
    Адрес:
    Moscow
    drem1lin
    Можно глянуть в исходники UniATA драйвера.
    Вот быстренько набросал:
    Код (Text):
    1. // Файл  id_probe.cpp
    2.  
    3. CheckDevice
    4.  
    5.   SelectDrive(chan, deviceNumber);
    6.     //AtapiWritePort1(chan, IDX_IO1_o_DriveSelect, (unit) ? IDE_DRIVE_SELECT_2 : IDE_DRIVE_SELECT_1);
    7.     // Пишем в порт (cmd_port + HD_CURRENT) значение (deviceNumber << 4).
    8.  
    9.   UniataAnybodyHome
    10.     // метод определения существования устройства на контроллере от автора UniATA
    11.    
    12.   statusByte = WaitOnBaseBusyLong(chan);
    13.     // ожидаем в цикле статуса IDE_STATUS_BUSY
    14.     //GetBaseStatus
    15.     // Читаем из порта (cmd_port + HD_STATUS) и ожидаем бита IDE_STATUS_BUSY
    16.     //AtapiStallExecution
    17.     // Вызов функции ScsiPortStallExecution (ХЗ чем её можно заменить)
    18.    
    19.   GetBaseStatus(chan, statusByte);
    20.   // Читаем из порта (cmd_port + HD_STATUS)
    21.  
    22.   if (SATA_Controller) UniataSataClearErr ......
    23.   // с SATA пока не разбирался ...
    24.    
    25.   if(((statusByte | IDE_STATUS_BUSY) == 0xff) || (statusByte & IDE_STATUS_BUSY)) {
    26.     KdPrint2((PRINT_PREFIX "CheckDevice: busy => return\n"));
    27.     UniataForgetDevice(LunExt);  // LunExt->DeviceFlags &= DFLAGS_HIDDEN;
    28.     return 0;
    29.   }
    30.  
    31.   // Читаем из HD_LCYL и HD_HCYL и по "магическим" значениям отличаем ATAPI от IDE.
    32.   // Впервые вижу такой кодес
    33.   signatureLow = AtapiReadPort1(chan, IDX_IO1_i_CylinderLow);
    34.   signatureHigh = AtapiReadPort1(chan, IDX_IO1_i_CylinderHigh);
    35.   if (signatureLow == ATAPI_MAGIC_LSB && signatureHigh == ATAPI_MAGIC_MSB) {
    36.     KdPrint2((PRINT_PREFIX "CheckDevice: ATAPI signature found\n"));
    37.     ...
    38.     ...
    39.   } else {
    40.     KdPrint2((PRINT_PREFIX "CheckDevice: IDE device check\n"));
    41.     if (IssueIdentify(hw, deviceNumber, lChannel, IDE_COMMAND_IDENTIFY, FALSE) {
    42.       // Indicate IDE - not ATAPI device.
    43.       RetVal = DFLAGS_DEVICE_PRESENT;
    44.     }
    45.     GetBaseStatus(chan, statusByte);
    46.   }
    47.  
    48. --------------------------
    49.  
    50. //Файл  id_ata.cpp
    51.  
    52. IssueIdentify
    53.  
    54.   SelectDrive(chan, deviceNumber);
    55.   AtapiStallExecution(10);
    56.   statusByte = WaitOnBusyLong(chan);
    57.  
    58.   // Check that the status register makes sense.
    59.   GetBaseStatus(chan, statusByte2);
    60.  
    61.   UniataDumpATARegs(chan);
    62.   // ещё не осмыслил ....
    63.  
    64.   if (Command == IDE_COMMAND_IDENTIFY) {
    65.     statusByte = UniataIsIdle(deviceExtension, statusByte & ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX));
    66.  
    67.     if(statusByte != IDE_STATUS_IDLE) {
    68.       SelectDrive(chan, deviceNumber);
    69.       WaitOnBusyLong(chan);
    70.       // тут опять магическая проверка на ATAPI устройство
    71.  
    72.       // We really should wait up to 31 seconds
    73.       // The ATA spec. allows device 0 to come back from BUSY in 31 seconds!
    74.       // (30 seconds for device 1)
    75.       do {
    76.         // Wait for Busy to drop.
    77.         AtapiStallExecution(100);
    78.         GetStatus(chan, statusByte);
    79.         // Читаем из порта (cmd_port + HD_ALTSTATUS)
    80.       } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
    81.  
    82.       GetBaseStatus(chan, statusByte2);
    83.       // Читаем из порта (cmd_port + HD_STATUS)
    84.      
    85.       SelectDrive(chan, DeviceNumber);
    86.     }
    87.     // и снова магическая проверка на ATAPI устройство
    88.    
    89.     statusByte = UniataIsIdle(deviceExtension, statusByte) & ~IDE_STATUS_INDEX;
    90.     if (statusByte != IDE_STATUS_IDLE) {
    91.       // Give up on this.
    92.       KdPrint2((PRINT_PREFIX "IssueIdentify: no dev (ldev %d)\n", ldev));
    93.       return FALSE;
    94.     }
    95.   }
    96.  
    97.   // Далее в цикле вызывается AtaCommand -> AtaCommand48 и куча всего прочего
    98.   // Тут много проверок на DRQ
    99.  
    100.   statusByte = WaitForDrq(chan);
    101.   // Читаем из порта (cmd_port + HD_ALTSTATUS) и ожидаем бита IDE_STATUS_DRQ
    102.   statusByte = WaitOnBusyLong(chan);
    103.   if (!(statusByte & IDE_STATUS_DRQ)) {
    104.     KdPrint2((PRINT_PREFIX "IssueIdentify: !IDE_STATUS_DRQ (2) (%#x)\n", statusByte));
    105.     GetBaseStatus(chan, statusByte);
    106.     return FALSE;
    107.   }
    108.   GetBaseStatus(chan, statusByte);
    109.  
    110.   // Ну а далее читают первый сектор
    111.   ReadBuffer(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256, PIO0_TIMING);
    112.   // ReadBuffer2(chan, (PUSHORT)&deviceExtension->FullIdentifyData, 256/2, PIO0_TIMING);
     
  6. MisHel64

    MisHel64 Member

    Публикаций:
    0
    Регистрация:
    9 мар 2011
    Сообщения:
    182
    Я жду 31 секунду, пока в альтернативном статусе не пропадет BSY флаг.
    И маленький прикол тебе. Если ОС работает с прерыванием от HDD, то тебя ждет большой сюрприз.
    И нужно быть уверенным, что винт не уснул. Это второй сюрприз.
     
  7. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Спасибо, посмотрю
     
  8. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    ну что винт не уснул я уверен, а вот что такое прерывания и с чем их едят я пока не нашел( Спецификация здоровая штука
     
  9. MisHel64

    MisHel64 Member

    Публикаций:
    0
    Регистрация:
    9 мар 2011
    Сообщения:
    182
    Обычное прерывание, точнее IRQ.
    Нужно быть уверенным, что ОС не ведет никаких операций с тем же винтом, но используя прерывания.
    А на счет сна, ты оптимистичен.
     
  10. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    ты имеешь ввиду int 13h и вроде 21h? Условия специфичны, хард спать не будет.
     
  11. MisHel64

    MisHel64 Member

    Публикаций:
    0
    Регистрация:
    9 мар 2011
    Сообщения:
    182
    Нет. IRQ14 в частности.
     
  12. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    которое назначает система? первичный канал 14, вторичный 15?
     
  13. MisHel64

    MisHel64 Member

    Публикаций:
    0
    Регистрация:
    9 мар 2011
    Сообщения:
    182
    Очень сложный, и не однозначный вопрос.
    Но цифры ты верно уловил.
    Правда к винтам, это ни как не относится, это в контролерах разбираться нужно.
     
  14. T800

    T800 Member

    Публикаций:
    0
    Регистрация:
    7 дек 2006
    Сообщения:
    293
    Адрес:
    Moscow
    Взял из UniATA функции CheckDevice,IssueIdentify,AtaCommand48,UniataAnybodyHome и добавил всё это дело в свою тестовую прожку (на Delphi).
    Читаю просто нулевой сектор.
    Работает этот CheckDevice намного лучше, чем старый код (позаимствованый у Pavia). Правда всё же на VIA чипсете удалось однажды словить зависон компа (на WinXP тестирую), но это пустяк.
    Но в функции IssueIdentify после чтения 512 байтиков есть вызов функции WaitForDrq (ожидание бита DRQ), которая в 90% случаев завершается по таймауту, и из-за этого "сканирование" выполняется не быстро.
    Поэтому у себя все выходы по таймауту сделал более "быстрыми".
     
  15. MisHel64

    MisHel64 Member

    Публикаций:
    0
    Регистрация:
    9 мар 2011
    Сообщения:
    182
    Шо это было?
     
  16. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Спасибо еще раз).
     
  17. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Это самый полный ответ был)
     
  18. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    А как определить в каком режиме работает хард? Просто мой код должен либо дождаться когда хард свободен, либо забить другие обращения к харду и выполнить мои. Это на данный момент основной вопрос.
     
  19. MisHel64

    MisHel64 Member

    Публикаций:
    0
    Регистрация:
    9 мар 2011
    Сообщения:
    182
    Все зависит от операционной системы.
    Или вы должны гарантировать, что операционная система не будет общаться с устройством, или должны пользоваться только средствами ОС.
     
  20. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Понятно, гарантии такие есть, если хард не используется ОС, то и не начнет, тут вопрос в том как это узнать, как узнать что хард не используется. Какие биты он ставит или какие еще признаки есть?