Subversion Repositories Kolibri OS

Rev

Rev 6650 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 6842 $
  9.  
  10. ; HDD driver
  11.  
  12. struct HD_DATA
  13. hdpos   dw  ?
  14. hdid    dw  ?
  15. hdbase  dw  ?
  16. hd48    dw  ?
  17. sectors dq  ?
  18. ends
  19. ;-----------------------------------------------------------------
  20. iglobal
  21. align 4
  22. ide_callbacks:
  23.     dd  ide_callbacks.end - ide_callbacks
  24.     dd  0   ; no close function
  25.     dd  0   ; no closemedia function
  26.     dd  ide_querymedia
  27.     dd  ide_read
  28.     dd  ide_write
  29.     dd  0   ; no flush function
  30.     dd  0   ; use default cache size
  31. .end:
  32.  
  33. hd0_data    HD_DATA     1,  0
  34. hd1_data    HD_DATA     2,  16
  35. hd2_data    HD_DATA     3,  0
  36. hd3_data    HD_DATA     4,  16
  37. hd4_data    HD_DATA     5,  0
  38. hd5_data    HD_DATA     6,  16
  39. hd6_data    HD_DATA     7,  0
  40. hd7_data    HD_DATA     8,  16
  41. hd8_data    HD_DATA     9,  0
  42. hd9_data    HD_DATA     10, 16
  43. hd10_data   HD_DATA     11, 0
  44. hd11_data   HD_DATA     12, 16
  45.  
  46. ide_mutex_table:
  47.     dd  ide_channel1_mutex
  48.     dd  ide_channel2_mutex
  49.     dd  ide_channel3_mutex
  50.     dd  ide_channel4_mutex
  51.     dd  ide_channel5_mutex
  52.     dd  ide_channel6_mutex
  53. endg
  54. ;-----------------------------------------------------------------
  55. uglobal
  56. ide_mutex               MUTEX
  57. ide_channel1_mutex      MUTEX
  58. ide_channel2_mutex      MUTEX
  59. ide_channel3_mutex      MUTEX
  60. ide_channel4_mutex      MUTEX
  61. ide_channel5_mutex      MUTEX
  62. ide_channel6_mutex      MUTEX
  63. blockSize:
  64. rb 4
  65. sector:
  66. rb 6
  67. allow_dma_access        db ?
  68. IDE_common_irq_param    db ?
  69. eventPointer            dd ?
  70. eventID                 dd ?
  71. endg
  72. ;-----------------------------------------------------------------
  73. ide_read:
  74.         mov     al, 25h     ; READ DMA EXT
  75.         jmp     ide_read_write
  76.  
  77. ide_write:
  78.         mov     al, 35h     ; WRITE DMA EXT
  79. proc ide_read_write stdcall uses esi edi ebx, \
  80.         hd_data, buffer, startsector:qword, numsectors
  81.         ; hd_data = pointer to hd*_data
  82.         ; buffer = pointer to buffer with/for data
  83.         ; startsector = 64-bit start sector
  84.         ; numsectors = pointer to number of sectors on input,
  85.         ;  must be filled with number of sectors really read/written
  86. locals
  87. sectors_todo    dd      ?
  88. channel_lock    dd      ?
  89. endl
  90.         mov     bl, al
  91. ; get number of requested sectors and say that no sectors were read yet
  92.         mov     ecx, [numsectors]
  93.         mov     eax, [ecx]
  94.         mov     dword [ecx], 0
  95.         mov     [sectors_todo], eax
  96. ; acquire the global lock
  97.         mov     ecx, ide_mutex
  98.         call    mutex_lock
  99.         mov     ecx, [hd_data]
  100.         movzx   ecx, [ecx+HD_DATA.hdpos]
  101.         dec     ecx
  102.         shr     ecx, 1
  103.         shl     ecx, 2
  104.         mov     ecx, [ecx + ide_mutex_table]
  105.         mov     [channel_lock], ecx
  106.         call    mutex_lock
  107. ; prepare worker procedures variables
  108.         mov     esi, [buffer]
  109.         mov     edi, esi
  110.         mov     ecx, [hd_data]
  111.         movzx   eax, [ecx+HD_DATA.hdbase]
  112.         mov     [hdbase], eax
  113.         mov     ax, [ecx+HD_DATA.hdid]
  114.         mov     [hdid], eax
  115.         mov     eax, dword [startsector]
  116.         mov     [sector], eax
  117.         cmp     [ecx+HD_DATA.hd48], 0
  118.         jz      .LBA28
  119.         mov     ax, word [startsector+4]
  120.         mov     [sector+4], ax
  121.         movzx   ecx, [ecx+HD_DATA.hdpos]
  122.         mov     [hdpos], ecx
  123.         dec     ecx
  124.         shr     ecx, 2
  125.         imul    ecx, sizeof.IDE_DATA
  126.         add     ecx, IDE_controller_1
  127.         mov     [IDE_controller_pointer], ecx
  128.         mov     eax, [hdpos]
  129.         dec     eax
  130.         and     eax, 11b
  131.         shr     eax, 1
  132.         add     eax, ecx
  133.         cmp     [eax+IDE_DATA.dma_hdd_channel_1], 1
  134.         jz      .next
  135.         dec     ebx     ; READ/WRITE SECTOR(S) EXT
  136. ; LBA48 supports max 10000h sectors per time
  137. ; loop until all sectors will be processed
  138. .next:
  139.         mov     ecx, 8000h
  140.         cmp     ecx, [sectors_todo]
  141.         jbe     @f
  142.         mov     ecx, [sectors_todo]
  143. @@:
  144.         mov     [blockSize], ecx
  145.         push    ecx
  146.         call    IDE_transfer
  147.         pop     ecx
  148.         jc      .out
  149.         mov     eax, [numsectors]
  150.         add     [eax], ecx
  151.         sub     [sectors_todo], ecx
  152.         jz      .out
  153.         add     [sector], ecx
  154.         adc     word [sector+4], 0
  155.         jmp     .next
  156.  
  157. .LBA28:
  158.         add     eax, [sectors_todo]
  159.         add     eax, 0xF0000000
  160.         jc      .out
  161.         sub     bl, 5   ; READ/WRITE SECTOR(S)
  162. ; LBA28 supports max 256 sectors per time
  163. ; loop until all sectors will be processed
  164. .next28:
  165.         mov     ecx, 256
  166.         cmp     ecx, [sectors_todo]
  167.         jbe     @f
  168.         mov     ecx, [sectors_todo]
  169. @@:
  170.         mov     [blockSize], ecx
  171.         push    ecx
  172.         call    IDE_transfer.LBA28
  173.         pop     ecx
  174.         jc      .out
  175.         mov     eax, [numsectors]
  176.         add     [eax], ecx
  177.         sub     [sectors_todo], ecx
  178.         jz      .out
  179.         add     [sector], ecx
  180.         jmp     .next28
  181.  
  182. ; loop is done, either due to error or because everything is done
  183. ; release the global lock and return the corresponding status
  184. .out:
  185.         sbb     eax, eax
  186.         push    eax
  187.         mov     ecx, [channel_lock]
  188.         call    mutex_unlock
  189.         mov     ecx, ide_mutex
  190.         call    mutex_unlock
  191.         pop     eax
  192.         ret
  193. endp
  194. ;-----------------------------------------------------------------
  195. proc ide_querymedia stdcall, hd_data, mediainfo
  196.         mov     eax, [mediainfo]
  197.         mov     edx, [hd_data]
  198.         mov     [eax+DISKMEDIAINFO.Flags], 0
  199.         mov     [eax+DISKMEDIAINFO.SectorSize], 512
  200.         mov     ecx, dword[edx+HD_DATA.sectors]
  201.         mov     dword[eax+DISKMEDIAINFO.Capacity], ecx
  202.         mov     ecx, dword[edx+HD_DATA.sectors+4]
  203.         mov     dword[eax+DISKMEDIAINFO.Capacity+4], ecx
  204.         xor     eax, eax
  205.         ret
  206. endp
  207. ;-----------------------------------------------------------------
  208. ; input: esi -> buffer, bl = command, [sector], [blockSize]
  209. ; output: esi -> next block in buffer
  210. ; for pio read esi equal edi
  211. IDE_transfer:
  212.         mov     edx, [hdbase]
  213.         add     edx, 6
  214.         mov     al, byte [hdid]
  215.         add     al, 224
  216.         out     dx, al  ; select the desired drive
  217.         call    save_hd_wait_timeout
  218.         inc     edx
  219. @@:
  220.         call    check_hd_wait_timeout
  221.         jc      .hd_error
  222.         in      al, dx
  223.         test    al, 128 ; ready for command?
  224.         jnz     @b
  225.         pushfd          ; fill the ports
  226.         cli
  227.         mov     edx, [hdbase]
  228.         inc     edx
  229.         inc     edx
  230.         mov     al, [blockSize+1]
  231.         out     dx, al  ; Sector count (15:8)
  232.         inc     edx
  233.         mov     eax, [sector+3]
  234.         out     dx, al  ; LBA (31:24)
  235.         inc     edx
  236.         shr     eax, 8
  237.         out     dx, al  ; LBA (39:32)
  238.         inc     edx
  239.         shr     eax, 8
  240.         out     dx, al  ; LBA (47:40)
  241.         sub     edx, 3
  242.         mov     al, [blockSize]
  243.         out     dx, al  ; Sector count (7:0)
  244.         inc     edx
  245.         mov     eax, [sector]
  246.         out     dx, al  ; LBA (7:0)
  247.         inc     edx
  248.         shr     eax, 8
  249.         out     dx, al  ; LBA (15:8)
  250.         inc     edx
  251.         shr     eax, 8
  252.         out     dx, al  ; LBA (23:16)
  253.         inc     edx
  254.         mov     al, byte [hdid]
  255.         add     al, 224
  256.         out     dx, al
  257.         test    bl, 1
  258.         jz      .PIO
  259. ; DMA
  260.         mov     dword [esp], 0x1000
  261.         call    kernel_alloc
  262.         mov     edi, eax
  263.         push    eax
  264.         shl     dword [blockSize], 9
  265.         mov     eax, esi
  266.         add     eax, [blockSize]
  267.         push    eax
  268. ; check buffer pages physical addresses and fill the scatter-gather list
  269. ; buffer may be not aligned and may have size not divisible by page size
  270. ; [edi] = block physical address, [edi+4] = block size in bytes
  271. ; block addresses can not cross 10000h borders
  272.         mov     ecx, esi
  273.         and     ecx, 0xFFF
  274.         jz      .aligned
  275.         mov     eax, esi
  276.         call    get_pg_addr
  277.         add     eax, ecx
  278.         neg     ecx
  279.         add     ecx, 0x1000
  280.         mov     [edi], eax
  281.         cmp     ecx, [blockSize]
  282.         jnc     .end
  283.         mov     [edi+4], ecx
  284.         add     esi, 0x1000
  285.         add     edi, 8
  286.         sub     [blockSize], ecx
  287. .aligned:
  288.         mov     eax, esi
  289.         call    get_pg_addr
  290.         mov     ecx, eax
  291.         mov     [edi], eax
  292.         and     ecx, 0xFFFF
  293.         neg     ecx
  294.         add     ecx, 0x10000
  295.         cmp     [blockSize], ecx
  296.         jnc     @f
  297.         mov     ecx, [blockSize]
  298.         and     ecx, 0xF000
  299.         jz      .end
  300. @@:
  301.         push    ecx
  302. @@:
  303.         add     esi, 0x1000
  304.         add     eax, 0x1000
  305.         sub     ecx, 0x1000
  306.         jz      @f
  307.         mov     edx, eax
  308.         mov     eax, esi
  309.         call    get_pg_addr
  310.         cmp     eax, edx
  311.         jz      @b
  312. @@:
  313.         pop     edx
  314.         sub     edx, ecx
  315.         mov     [edi+4], edx
  316.         add     edi, 8
  317.         sub     [blockSize], edx
  318.         jnz     .aligned
  319.         sub     edi, 8
  320.         jmp     @f
  321.  
  322. .end:
  323.         mov     ecx, [blockSize]
  324.         mov     [edi+4], ecx
  325. @@:
  326.         mov     byte [edi+7], 80h   ; list end
  327.         pop     esi
  328.         pop     edi
  329. ; select controller Primary or Secondary
  330.         mov     ecx, [IDE_controller_pointer]
  331.         mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
  332.         mov     eax, [hdpos]
  333.         dec     eax
  334.         test    eax, 10b
  335.         jz      @f
  336.         add     edx, 8
  337. @@:
  338.         add     edx, 2      ; Bus Master IDE Status register
  339.         mov     al, 6
  340.         out     dx, al      ; clear Error bit and Interrupt bit
  341.  
  342.         add     edx, 2      ; Bus Master IDE PRD Table Address
  343.         mov     eax, edi
  344.         call    get_pg_addr
  345.         out     dx, eax     ; send scatter-gather list physical address
  346.  
  347.         push    edx
  348.         mov     edx, [hdbase]
  349.         add     edx, 7      ; ATACommand
  350.         mov     al, bl
  351.         out     dx, al      ; Start hard drive
  352.         pop     edx
  353.  
  354.         sub     edx, 4      ; Bus Master IDE Command register
  355.         mov     al, 1       ; set direction
  356.         cmp     bl, 35h     ; write
  357.         jz      @f
  358.         add     al, 8       ; read
  359. @@:
  360.         out     dx, al      ; Start Bus Master
  361.         mov     [IDE_common_irq_param], 14
  362.         mov     eax, [hdpos]
  363.         dec     eax
  364.         test    eax, 10b
  365.         jz      @f
  366.         inc     [IDE_common_irq_param]
  367. @@:
  368.         push    edi esi ebx
  369.         xor     ecx, ecx
  370.         xor     esi, esi
  371.         call    create_event
  372.         mov     [eventPointer], eax
  373.         mov     [eventID], edx
  374.         sti
  375.         mov     ebx, edx
  376.         mov     ecx, 300
  377.         call    wait_event_timeout
  378.         test    eax, eax
  379.         jnz     @f
  380.         dbgstr 'IDE DMA IRQ timeout'
  381.         mov     [IDE_common_irq_param], 0
  382.         mov     eax, [eventPointer]
  383.         mov     ebx, [eventID]
  384.         call    destroy_event
  385.         mov     [eventPointer], 0
  386. @@:
  387.         pop     ebx esi
  388.         call    kernel_free
  389.         cmp     [eventPointer], 0
  390.         jz      .hd_error
  391.         ret
  392.  
  393. .LBA28:
  394.         mov     edx, [hdbase]
  395.         add     edx, 6
  396.         mov     al, byte [hdid]
  397.         add     al, 224
  398.         out     dx, al  ; select the desired drive
  399.         call    save_hd_wait_timeout
  400.         inc     edx
  401. @@:
  402.         call    check_hd_wait_timeout
  403.         jc      .hd_error
  404.         in      al, dx
  405.         test    al, 128 ; ready for command?
  406.         jnz     @b
  407.         pushfd          ; fill the ports
  408.         cli
  409.         mov     edx, [hdbase]
  410.         inc     edx
  411.         inc     edx
  412.         mov     al, [blockSize]
  413.         out     dx, al  ; Sector count (7:0)
  414.         inc     edx
  415.         mov     eax, [sector]
  416.         out     dx, al  ; LBA (7:0)
  417.         inc     edx
  418.         shr     eax, 8
  419.         out     dx, al  ; LBA (15:8)
  420.         inc     edx
  421.         shr     eax, 8
  422.         out     dx, al  ; LBA (23:16)
  423.         inc     edx
  424.         shr     eax, 8
  425.         add     al, byte [hdid]
  426.         add     al, 224
  427.         out     dx, al  ; LBA (27:24)
  428. .PIO:
  429.         inc     edx     ; ATACommand
  430.         mov     al, bl
  431.         out     dx, al  ; Start hard drive
  432.         popfd
  433. .sectorTransfer:
  434.         call    save_hd_wait_timeout
  435.         in      al, dx
  436.         in      al, dx
  437.         in      al, dx
  438.         in      al, dx
  439. @@:
  440.         call    check_hd_wait_timeout
  441.         jc      .hd_error
  442.         in      al, dx
  443.         test    al, 8   ; ready for transfer?
  444.         jz      @b
  445.         cmp     [hd_setup], 1   ; do not mark error for setup request
  446.         jz      @f
  447.         test    al, 1   ; previous command ended up with an error
  448.         jnz     .pio_error
  449. @@:
  450.         pushfd
  451.         cli
  452.         cld
  453.         mov     ecx, 256
  454.         mov     edx, [hdbase]
  455.         cmp     bl, 30h
  456.         jnc     .write
  457.         rep insw
  458.         jmp     @f
  459.  
  460. .write:
  461.         rep outsw
  462. @@:
  463.         popfd
  464.         add     edx, 7
  465.         dec     dword [blockSize]
  466.         jnz     .sectorTransfer
  467.         ret
  468.  
  469. .pio_error:
  470.         dbgstr 'IDE PIO transfer error'
  471. .hd_error:
  472.         cmp     bl, 30h
  473.         jnc     hd_write_error
  474. ;-----------------------------------------------------------------
  475. hd_read_error:
  476.         dbgstr 'HD read error'
  477.         stc
  478.         ret
  479. ;-----------------------------------------------------------------
  480. hd_write_error:
  481.         dbgstr 'HD write error'
  482.         stc
  483.         ret
  484. ;-----------------------------------------------------------------
  485. save_hd_wait_timeout:
  486.         mov     eax, [timer_ticks]
  487.         add     eax, 300        ; 3 sec timeout
  488.         mov     [hd_wait_timeout], eax
  489.         ret
  490. ;-----------------------------------------------------------------
  491. check_hd_wait_timeout:
  492.         mov     eax, [timer_ticks]
  493.         cmp     [hd_wait_timeout], eax
  494.         jc      @f
  495.         ret
  496.  
  497. @@:
  498.         dbgstr 'IDE device timeout'
  499.         stc
  500.         ret
  501. ;-----------------------------------------------------------------
  502. align 4
  503. IDE_irq_14_handler:
  504. IDE_irq_15_handler:
  505. IDE_common_irq_handler:
  506. ; Most of the time, we are here because we have requested
  507. ; a DMA transfer for the corresponding drive.
  508. ; However,
  509. ; a) we can be here because IDE IRQ is shared with some other device,
  510. ;    that device has actually raised IRQ,
  511. ;    it has nothing to do with IDE;
  512. ; b) we can be here because IDE controller just does not want
  513. ;    to be silent and reacts to something even though
  514. ;    we have, in theory, disabled IRQs.
  515. ; If the interrupt corresponds to our current request,
  516. ; remove the interrupt request and raise the event for the waiting code.
  517. ; In the case a), just return zero - not our interrupt.
  518. ; In the case b), remove the interrupt request and hope for the best.
  519. ; DEBUGF 1, 'K : IDE_irq_handler %x\n', [IDE_common_irq_param]:2
  520.         mov     ecx, [esp+4]
  521.         mov     dx, [ecx+IDE_DATA.RegsBaseAddres]
  522.         add     edx, 2  ; Bus Master IDE Status register
  523.         in      al, dx
  524.         test    al, 4
  525.         jnz     .interrupt_from_primary
  526.         add     edx, 8
  527.         in      al, dx
  528.         test    al, 4
  529.         jnz     .interrupt_from_secondary
  530.         xor     eax, eax ; not our interrupt
  531.         ret
  532.  
  533. .interrupt_from_primary:
  534.         out     dx, al  ; clear Interrupt bit
  535.         sub     edx, 2
  536.         xor     eax, eax
  537.         out     dx, al  ; clear Bus Master IDE Command register
  538.         mov     dx, [ecx+IDE_DATA.BAR0_val]
  539.         add     edx, 7
  540.         in      al, dx  ; read status register
  541.         cmp     [IDE_common_irq_param], 14
  542.         jz      .raise
  543. .exit_our:
  544.         mov     al, 1
  545.         ret
  546.  
  547. .interrupt_from_secondary:
  548.         out     dx, al  ; clear Interrupt bit
  549.         sub     edx, 2
  550.         xor     eax, eax
  551.         out     dx, al  ; clear Bus Master IDE Command register
  552.         mov     dx, [ecx+IDE_DATA.BAR2_val]
  553.         add     edx, 7
  554.         in      al, dx  ; read status register
  555.         cmp     [IDE_common_irq_param], 15
  556.         jnz     .exit_our
  557. .raise:
  558.         cmp     ecx, [IDE_controller_pointer]
  559.         jnz     .exit_our
  560.         pushad
  561.         mov     eax, [eventPointer]
  562.         mov     ebx, [eventID]
  563.         xor     edx, edx
  564.         xor     esi, esi
  565.         call    raise_event
  566.         popad
  567.         mov     al, 1   ; remove the interrupt request
  568.         ret
  569.