Subversion Repositories Kolibri OS

Rev

Rev 9069 | Rev 9074 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision$
  9.  
  10. PCI_REG_STATUS_COMMAND = 0x0004
  11. PCI_REG_BAR5 = 0x0024
  12.  
  13. ; bit_ prefix means that its index of bit
  14. ; format: bit_AHCI_STR_REG_BIT
  15. bit_AHCI_HBA_CAP2_BOH   = 0        ; Supports BIOS/OS Handoff
  16.  
  17. bit_AHCI_HBA_BOHC_BOS  = 0         ; BIOS-Owned Semaphore (BIOS owns controller)
  18. bit_AHCI_HBA_BOHC_OOS  = 1         ; OS-Owned Semaphore (OS owns controller)
  19. bit_AHCI_HBA_BOHC_BB   = 4         ; BIOS Busy (polling bit while BIOS cleans up
  20.  
  21. bit_AHCI_HBA_GHC_AHCI_ENABLE      = 31  ; Enable AHCI mode
  22. bit_AHCI_HBA_GHC_RESET            = 0   ; Reset HBA
  23. bit_AHCI_HBA_GHC_INTERRUPT_ENABLE = 1   ; Enable interrupts from the HBA
  24.  
  25. bit_AHCI_HBA_PxCMD_ST    = 0
  26. bit_AHCI_HBA_PxCMD_FRE   = 4
  27. bit_AHCI_HBA_PxCMD_FR    = 14
  28. bit_AHCI_HBA_PxCMD_CR    = 15
  29.  
  30. AHCI_HBA_PxSSTS_DET         = 0xF
  31. AHCI_HBA_PORT_IPM_ACTIVE    = 1
  32. AHCI_HBA_PxSSTS_DET_PRESENT = 3
  33.  
  34. AHCI_MAX_PORTS = 32        ;
  35. ;HBA_MEMORY_SIZE = 0x1100
  36.  
  37. ; Frame Information Structure Types
  38. FIS_TYPE_REG_H2D    = 0x27 ; Register FIS - host to device
  39. FIS_TYPE_REG_D2H    = 0x34 ; Register FIS - device to host
  40. FIS_TYPE_DMA_ACT    = 0x39 ; DMA activate FIS - device to host
  41. FIS_TYPE_DMA_SETUP  = 0x41 ; DMA setup FIS - bidirectional
  42. FIS_TYPE_DATA       = 0x46 ; Data FIS - bidirectional
  43. FIS_TYPE_BIST       = 0x58 ; BIST activate FIS - bidirectional
  44. FIS_TYPE_PIO_SETUP  = 0x5F ; PIO setup FIS - device to host
  45. FIS_TYPE_DEV_BITS   = 0xA1 ; Set device bits FIS - device to host
  46.  
  47. struct AHCI_DATA
  48.         abar    dd ?       ; pointer to HBA Memory (BAR5) mapped to virtual kernelspace memory
  49.         pcidev  dd ?       ; pointer to corresponding PCIDEV structure
  50. ends
  51.  
  52. ; Generic Host Control registers
  53. struct HBA_MEM
  54.         cap                   dd ?                    ; 0x00, Host capabilities
  55.         ghc                   dd ?                    ; 0x04, Global host control
  56.         is                    dd ?                    ; 0x08, Interrupt status
  57.         pi                    dd ?                    ; 0x0C, Port implemented
  58.         version               dd ?                    ; 0x10, Version
  59.         ccc_ctl               dd ?                    ; 0x14, Command completion coalescing control
  60.         ccc_pts               dd ?                    ; 0x18, Command completion coalescing ports
  61.         em_loc                dd ?                    ; 0x1C, Enclosure management location
  62.         em_ctl                dd ?                    ; 0x20, Enclosure management control
  63.         cap2                  dd ?                    ; 0x24, Host capabilities extended
  64.         bohc                  dd ?                    ; 0x28, BIOS/OS handoff control and status
  65.         reserved              rb (0xA0-HBA_MEM.reserved)        ; 0x2C - 0x9F, Reserved
  66.         vendor                rb (0x100-HBA_MEM.vendor)         ; 0xA0 - 0xFF, Vendor specific
  67.         ports                 rb (sizeof.HBA_PORT*AHCI_MAX_PORTS) ; 0x100 - 0x10FF, Port control registers, max AHCI_MAX_PORTS
  68. ends
  69.  
  70. ; Port Control registers
  71. struct HBA_PORT
  72.         command_list_base_l      dd ?                 ; 0x00, command list base address, 1K-byte aligned
  73.         command_list_base_h      dd ?                 ; 0x04, command list base address upper 32 bits, used on 64 bit systems
  74.         fis_base_l               dd ?                 ; 0x08, FIS base address, 256-byte aligned
  75.         fis_base_h               dd ?                 ; 0x0C, FIS base address upper 32 bits, used on 64 bit systems
  76.         interrupt_status         dd ?                 ; 0x10
  77.         interrupt_enable         dd ?                 ; 0x14
  78.         command                  dd ?                 ; 0x18, command and status
  79.         reserved0                dd ?                 ; 0x1C
  80.         task_file_data           dd ?                 ; 0x20
  81.         signature                dd ?                 ; 0x24
  82.         sata_status              dd ?                 ; 0x28, SATA status (SCR0:SStatus)
  83.         sata_control             dd ?                 ; 0x2C, SATA control (SCR2:SControl)
  84.         sata_error               dd ?                 ; 0x30, SATA error (SCR1:SError)
  85.         sata_active              dd ?                 ; 0x34, SATA active (SCR3:SActive)
  86.         command_issue            dd ?                 ; 0x38
  87.         sata_notification        dd ?                 ; 0x3C, SATA notification (SCR4:SNotification)
  88.         fis_based_switch_control dd ?                 ; 0x40
  89.         reserved1                rd 11                ; 0x44 - 0x6F
  90.         vendor                   rd 4                 ; 0x70 - 0x7F, vendor specific
  91. ends
  92.  
  93. ; Command header structure
  94. struct HBA_CMD_HDR
  95.     _flags1       db ? ; 0bPWACCCCC, P - Prefetchable, W - Write (1: H2D, 0: D2H)
  96.                        ; A - ATAPI, C - Command FIS length in DWORDS, 2 ~ 16
  97.    
  98.     _flags2       db ? ; 0bPPPPRCB(Re), P - Port multiplier port, R - Reserved,
  99.                        ; C - Clear busy upon R_OK, B - BIST, Re - Reset
  100.    
  101.     prdtl         dw ? ; Physical region descriptor table length in entries
  102.     prdbc         dd ? ; Physical region descriptor byte count transferred
  103.     ctba          dd ? ; Command table descriptor base address
  104.     ctbau         dd ? ; Command table descriptor base address upper 32 bits
  105.                   rd 4 ; Reserved
  106. ends
  107.  
  108. struct HBA_PRDT_ENTRY
  109.     dba           dd ?  ; Data base address
  110.     dbau          dd ?  ; Data base address upper 32 bits
  111.                   dd ?  ; Reserved
  112.     _flags        dd ?  ; 0bIR..RD..D, I (1 bit) - Interrupt on completion,
  113.                         ; R (9 bits) - Reserved, D (22 bits) - Byte count, 4M max
  114. ends
  115.  
  116. struct HBA_CMD_TBL
  117.     cfis          rb 64 ; 0x00, Command FIS
  118.     acmd          rb 16 ; 0x40, ATAPI command, 12 or 16 bytes
  119.                   rb 48 ; 0x50, Reserved
  120.     prdt_entry    HBA_PRDT_ENTRY  ; 0x80, Physical region descriptor table entries, 0 ~ 65535
  121.                         ; so, this structure is variable-length
  122. ends
  123.  
  124. ; Contains virtual mappings for port phys memory regions
  125. struct PORT_DATA
  126.     clb           dd ? ; Command list base
  127.     fb            dd ? ; FIS base
  128.     ctba_arr      rd 32 ; ctba_arr[0] = clb[0].ctba, ... and so on.
  129.     port          dd ? ; address of correspoding HBA_PORT structure
  130. ends
  131.  
  132. ; Register FIS – Host to Device
  133. struct FIS_REG_H2D
  134.         fis_type      db ?       ; FIS_TYPE_REG_H2D
  135.         _flags        db ?       ; 0bCRRRPPPP, C - 1: Command, 0: Control
  136.                                  ; R - Reserved, P - Port multiplier
  137.  
  138.         command       db ?       ; Command register
  139.         featurel      db ?       ; Feature register, 7:0
  140.  
  141.         lba0          db ?       ; LBA low register, 7:0
  142.         lba1          db ?       ; LBA mid register, 15:8
  143.         lba2          db ?       ; LBA high register, 23:16
  144.         device        db ?       ; Device register
  145.  
  146.         lba3          db ?       ; LBA register, 31:24
  147.         lba4          db ?       ; LBA register, 39:32
  148.         lba5          db ?       ; LBA register, 47:40
  149.         featureh      db ?       ; Feature register, 15:8
  150.  
  151.         countl        db ?       ; Count register, 7:0
  152.         counth        db ?       ; Count register, 15:8
  153.         icc           db ?       ; Isochronous command completion
  154.         control       db ?       ; Control register
  155.  
  156.                       rb 4       ; Reserved
  157. ends
  158.  
  159. ; Register FIS – Device to Host
  160. struct FIS_REG_D2H
  161.     fis_type      db ?           ; FIS_TYPE_REG_D2H
  162.  
  163.     _flags        db ?           ; 0bRIRPPPP, P - Port multiplier, R - Reserved
  164.                                  ; I - Interrupt bit
  165.  
  166.     status        db ?           ; Status register
  167.     error         db ?           ; Error register
  168.  
  169.     lba0          db ?           ; LBA low register, 7:0
  170.     lba1          db ?           ; LBA mid register, 15:8
  171.     lba2          db ?           ; LBA high register, 23:16
  172.     device        db ?           ; Device register
  173.  
  174.     lba3          db ?           ; LBA register, 31:24
  175.     lba4          db ?           ; LBA register, 39:32
  176.     lba5          db ?           ; LBA register, 47:40
  177.                   db ?           ; Reserved
  178.  
  179.     countl        db ?           ; Count register, 7:0
  180.     counth        db ?           ; Count register, 15:8
  181.                   rb 2           ; Reserved
  182.  
  183.                   rb 4           ; Reserved
  184. ends
  185.  
  186. ; Data FIS – Bidirectional
  187. struct FIS_DATA
  188.     fis_type      db ?           ; FIS_TYPE_DATA
  189.     _flags        db ?           ; 0bRRRRPPPP, R - Reserved, P - Port multiplier
  190.                   rb 2           ; Reserved
  191.     ; DWORD 1 ~ N (?)
  192.     data          rd 1           ; Payload
  193. ends
  194.  
  195. ; PIO Setup – Device to Host
  196. struct FIS_PIO_SETUP
  197.     fis_type      db ?           ; FIS_TYPE_PIO_SETUP
  198.  
  199.     _flags        db ?           ; 0bRIDRPPPP, P - Port multiplier, R - Reserved
  200.                                  ; I - Interrupt bit, D - Data transfer direction, 1 - device to host
  201.  
  202.     status        db ?           ; Status register
  203.     error         db ?           ; Error register
  204.  
  205.     lba0          db ?           ; LBA low register, 7:0
  206.     lba1          db ?           ; LBA mid register, 15:8
  207.     lba2          db ?           ; LBA high register, 23:16
  208.     device        db ?           ; Device register
  209.  
  210.     lba3          db ?           ; LBA register, 31:24
  211.     lba4          db ?           ; LBA register, 39:32
  212.     lba5          db ?           ; LBA register, 47:40
  213.                   db ?           ; Reserved
  214.  
  215.     countl        db ?           ; Count register, 7:0
  216.     counth        db ?           ; Count register, 15:8
  217.                   db ?           ; Reserved
  218.     e_status      db ?           ; New value of status register
  219.  
  220.     tc            dw ?           ; Transfer count
  221.                   rb 2           ; Reserved
  222. ends
  223.  
  224. ; DMA Setup – Device to Host
  225. struct FIS_DMA_SETUP
  226.     fis_type      db ?           ; FIS_TYPE_DMA_SETUP
  227.     _flags        db ?           ; 0bAIDRPPPP, A - Auto-activate. Specifies if DMA Activate FIS is needed,
  228.                                  ; I - Interrupt bit, D - Data transfer direction, 1 - device to host,
  229.                                  ; R - Reserved, P - Port multiplier
  230.  
  231.                   rb 2           ; Reserved
  232.     DMAbufferID   dq ?           ; DMA Buffer Identifier.
  233.                                  ; Used to Identify DMA buffer in host memory.
  234.                                  ; SATA Spec says host specific and not in Spec.
  235.                                  ; Trying AHCI spec might work.
  236.  
  237.                   dd ?           ; Reserved
  238.     DMAbufOffset  dd ?           ; Byte offset into buffer. First 2 bits must be 0
  239.     TransferCount dd ?           ; Number of bytes to transfer. Bit 0 must be 0
  240.                   dd ?           ; Reserved
  241. ends
  242.  
  243. ; Set device bits FIS - device to host
  244. struct FIS_DEV_BITS
  245.     fis_type      db ?           ; FIS_TYPE_DEV_BITS
  246.     _flags        db ?           ; 0bNIRRPPPP, N - Notification, I - Interrupt,
  247.                                  ; R - Reserved, P - Port multiplier
  248.    
  249.     status        db ?           ; Status register
  250.     error         db ?           ; Error register
  251.    
  252.     protocol      dd ?           ; Protocol
  253. ends
  254.  
  255. struct HBA_FIS
  256.     dsfis         FIS_DMA_SETUP  ; 0x00, DMA Setup FIS
  257.                   rb 4           ; padding
  258.  
  259.     psfis         FIS_PIO_SETUP  ; 0x20, PIO Setup FIS
  260.                   rb 12          ; padding
  261.  
  262.     rfis          FIS_REG_D2H    ; 0x40, Register - Device to Host FIS
  263.                   rb 4           ; padding
  264.  
  265.     sdbfis        FIS_DEV_BITS   ; 0x58, Set Device Bit FIS
  266.  
  267.     ufis          rb 64          ; 0x60
  268.  
  269.                   rb (0x100 - 0xA0) ; 0xA0, Reserved
  270. ends
  271.  
  272. ; --------------------------------------------------
  273. uglobal
  274. align 4
  275.         ahci_controller AHCI_DATA
  276.         port_data_arr   rb (sizeof.PORT_DATA*AHCI_MAX_PORTS)
  277. endg
  278.  
  279. ; -----------------------------------------------------------------------
  280. ; detect ahci controller and initialize
  281. align 4
  282. ahci_init:
  283.         mov     ecx, ahci_controller
  284.         mov     esi, pcidev_list
  285. .find_ahci_ctr:
  286.         mov     esi, [esi + PCIDEV.fd]
  287.         cmp     esi, pcidev_list
  288.         jz      .ahci_ctr_not_found
  289.         mov     eax, [esi + PCIDEV.class]
  290.         ;DEBUGF  1, "K: device class = %x\n", eax
  291.         shr     eax, 8 ; shift right because lowest 8 bits if ProgIf field
  292.         cmp     eax, 0x0106 ; 0x01 - Mass Storage Controller class,  0x06 - Serial ATA Controller subclass
  293.         jz      .ahci_ctr_found
  294.         jmp     .find_ahci_ctr
  295.  
  296. .ahci_ctr_not_found:
  297.         DEBUGF  1, "K: AHCI controller not found\n"
  298.         ret
  299.  
  300. .ahci_ctr_found:
  301.         mov     [ahci_controller + AHCI_DATA.pcidev], esi
  302.  
  303.         mov     eax, [esi+PCIDEV.class]
  304.         movzx   ebx, byte [esi+PCIDEV.bus]
  305.         movzx   ecx, byte [esi+PCIDEV.devfn]
  306.         shr     ecx, 3 ; get rid of 3 lowest bits (function code), the rest bits is device code
  307.         movzx   edx, byte [esi+PCIDEV.devfn]
  308.         and     edx, 00000111b ; get only 3 lowest bits (function code)
  309.         DEBUGF  1, "K: found AHCI controller, (class, subcl, progif) = %x, bus = %x, device = %x, function = %x\n", eax, ebx, ecx, edx
  310.        
  311.         ; get BAR5 value, it is physical address
  312.         movzx   ebx, [esi + PCIDEV.bus]
  313.         movzx   ebp, [esi + PCIDEV.devfn]
  314.         stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
  315.         DEBUGF  1, "K: AHCI controller MMIO = %x\n", eax
  316.         mov     edi, eax
  317.  
  318.         ; get the size of MMIO region
  319.         stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, 0xFFFFFFFF
  320.         stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
  321.         not     eax
  322.         inc     eax
  323.         DEBUGF  1, "K: AHCI: MMIO region size = 0x%x bytes\n", eax
  324.  
  325.         ; Map MMIO region to virtual memory
  326.         stdcall map_io_mem, edi, eax, PG_SWR + PG_NOCACHE
  327.         mov     [ahci_controller + AHCI_DATA.abar], eax
  328.         DEBUGF  1, "K: AHCI controller BAR5 mapped to virtual addr %x\n", eax
  329.  
  330.         ; Restore the original BAR5 value
  331.         stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, edi
  332.  
  333.         ; Enable dma bus mastering, memory space access, clear the "disable interrupts" bit
  334.         ; Usually, it is already done before us
  335.         movzx   ebx, [esi + PCIDEV.bus]
  336.         movzx   ebp, [esi + PCIDEV.devfn]
  337.         stdcall pci_read32, ebx, ebp, PCI_REG_STATUS_COMMAND
  338.         DEBUGF  1, "K: AHCI: pci_status_command = %x\nEnabling interrupts, DMA bus mastering and memory space access\n", eax
  339.         or      eax, 0x06 ; pci.command |= 0x06 (dma bus mastering + memory space access)
  340.         btr     eax, 10 ; clear the "disable interrupts" bit
  341.         DEBUGF  1, "K: AHCI: pci_status_command = %x\n", eax
  342.         stdcall pci_write32, ebx, ebp, PCI_REG_STATUS_COMMAND, eax
  343.  
  344.         ; ; Print some register values to debug board
  345.         ; mov     esi, [ahci_controller + AHCI_DATA.abar]
  346.         ; DEBUGF  1, "K: AHCI: HBA.cap = %x, HBA.ghc = %x, HBA_MEM.version = %x\n", [esi + HBA_MEM.cap], [esi + HBA_MEM.ghc], [esi + HBA_MEM.version]
  347.  
  348.         ;-------------------------------------------------------
  349.         ; Request BIOS/OS ownership handoff, if supported. (TODO check correctness)
  350.         mov     esi, [ahci_controller + AHCI_DATA.abar]
  351.         ;mov     ebx, [esi + HBA_MEM.cap2]
  352.         ;DEBUGF  1, "K: AHCI: HBA_MEM.cap2 = %x\n", ebx
  353.         bt      [esi + HBA_MEM.cap2], bit_AHCI_HBA_CAP2_BOH
  354.         jnc     .end_handoff
  355.         DEBUGF  1, "K: AHCI: requesting AHCI ownership change...\n"
  356.         bts     [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_OOS
  357.  
  358. .wait_not_bos:
  359.         bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BOS
  360.         jc      .wait_not_bos
  361.  
  362.         mov     ebx, 3
  363.         call    delay_hs
  364.  
  365.         ; if Bios Busy is still set after 30 mS, wait 2 seconds.
  366.         bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BB
  367.         jnc     @f
  368.  
  369.         mov     ebx, 200
  370.         call    delay_hs
  371. @@:
  372.         DEBUGF  1, "K: AHCI: ownership change completed.\n"
  373.  
  374. .end_handoff:
  375.         ;-------------------------------------------------------
  376.  
  377.         ; enable the AHCI and reset it
  378.         bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
  379.         bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
  380.  
  381.         ; wait for reset to complete
  382. .wait_reset:
  383.         bt      [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
  384.         jc      .wait_reset
  385.  
  386.         ; enable the AHCI and interrupts
  387.         bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
  388.         bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_INTERRUPT_ENABLE
  389.         mov     ebx, 2
  390.         call    delay_hs
  391.        
  392.         DEBUGF  1, "K: AHCI: caps: %x %x, ver: %x, ghc: %x, pi: %x\n", [esi + HBA_MEM.cap], [esi + HBA_MEM.cap2], [esi + HBA_MEM.version], [esi + HBA_MEM.ghc], [esi + HBA_MEM.pi]
  393.  
  394.         ; TODO:
  395.         ; calculate irq line
  396.         ; ahciHBA->ghc |= AHCI_GHC_IE;
  397.         ; IDT::RegisterInterruptHandler(irq, InterruptHandler);
  398.         ; ahciHBA->is = 0xffffffff;
  399.  
  400.         xor     ebx, ebx
  401. .detect_drives:
  402.         cmp     ebx, AHCI_MAX_PORTS
  403.         jae     .end_detect_drives
  404.  
  405.         ; if port with index ebx is not implemented then go to next
  406.         mov     ecx, [esi + HBA_MEM.pi]
  407.         bt      ecx, ebx
  408.         jnc     .continue_detect_drives
  409.  
  410.         mov     edi, ebx
  411.         shl     edi, BSF sizeof.HBA_PORT
  412.         add     edi, HBA_MEM.ports
  413.         add     edi, esi
  414.         ; now edi - base of HBA_MEM.ports[ebx]
  415.  
  416.         DEBUGF  1, "K: AHCI: port %d, ssts = %x\n", ebx, [edi + HBA_PORT.sata_status]
  417.  
  418.         mov     ecx, [edi + HBA_PORT.sata_status]
  419.         shr     ecx, 8
  420.         and     ecx, 0x0F
  421.         cmp     ecx, AHCI_HBA_PORT_IPM_ACTIVE
  422.         jne     .continue_detect_drives
  423.  
  424.         mov     ecx, [edi + HBA_PORT.sata_status]
  425.         and     ecx, AHCI_HBA_PxSSTS_DET
  426.         cmp     ecx, AHCI_HBA_PxSSTS_DET_PRESENT
  427.         jne     .continue_detect_drives
  428.  
  429.         DEBUGF  1, "K: AHCI: found drive at port %d, signature = %x\n", ebx, [edi + HBA_PORT.signature]  
  430.  
  431.         mov     ecx, ebx
  432.         shl     ecx, BSF sizeof.PORT_DATA
  433.         add     ecx, port_data_arr
  434.         stdcall ahci_port_rebase, edi, ebx, ecx
  435.  
  436. .continue_detect_drives:
  437.         inc     ebx
  438.         jmp     .detect_drives
  439.  
  440.        
  441.  
  442. .end_detect_drives:
  443.        
  444.  
  445.         ret
  446. ; -------------------------------------------------
  447.  
  448. ; Start command engine
  449. ; in: eax - address of HBA_PORT structure
  450. ahci_start_cmd:
  451. .wait_cr: ; Wait until CR (bit15) is cleared
  452.         bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
  453.         jc      .wait_cr
  454.  
  455.         ; Set FRE (bit4) and ST (bit0)
  456.         bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE
  457.         bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST
  458.         ; maybe here call ahci flush cmd ? TODO (see seakernel)
  459.         ret
  460.  
  461. ; Stop command engine
  462. ; in: eax - address of HBA_PORT structure
  463. ahci_stop_cmd:
  464.         btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST ; Clear ST (bit0)
  465.         btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE ; Clear FRE (bit4)
  466. .wait_fr_cr: ; Wait until FR (bit14), CR (bit15) are cleared
  467.         bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FR
  468.         jc      .wait_fr_cr
  469.         bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
  470.         jc      .wait_fr_cr
  471.  
  472.         ret
  473.  
  474. ; The commands may not take effect until the command
  475. ; register is read again by software, because reasons.
  476. ; in: eax - address of HBA_PORT structure
  477. ; out: eax - command register value
  478. ahci_flush_cmd:
  479.         mov     eax, [eax + HBA_PORT.command]
  480.         ret
  481.  
  482. ; Send command to port
  483. ; in: eax - address of HBA_PORT structure
  484. ;     ebx - index of command slot
  485. ahci_send_cmd:
  486.         push    ecx
  487.         mov     [eax + HBA_PORT.interrupt_status], 0xFFFFFFFF
  488.        
  489.         mov     cl, bl
  490.         mov     [eax + HBA_PORT.command_issue], 1
  491.         shl     [eax + HBA_PORT.command_issue], cl
  492.  
  493.         call    ahci_flush_cmd
  494.         pop     ecx
  495.         ret
  496.  
  497. ; ---------------------------------------------------------------------------
  498. ; TODO: check correctness
  499. ; in: port - address of HBA_PORT structure
  500. ;     portno - port index (0..31)
  501. ;     pdata - address of PORT_DATA structure
  502. proc ahci_port_rebase stdcall, port: dword, portno: dword, pdata: dword
  503.         locals
  504.             phys_page1  dd ?
  505.             virt_page1  dd ?
  506.             phys_page23 dd ?
  507.             virt_page23 dd ?
  508.             tmp         dd ?
  509.         endl
  510.  
  511.         pushad
  512.  
  513.         DEBUGF  1, "Rebasing port %u\n", [portno]
  514.  
  515.         mov     eax, [port]
  516.         call    ahci_stop_cmd
  517.  
  518.         ; Command list entry size = 32
  519.         ; Command list entry maxim count = 32
  520.         ; Command list maxim size = 32*32 = 1K per port
  521.         call    alloc_page
  522.         mov     [phys_page1], eax
  523.  
  524.         stdcall map_io_mem, eax, 4096, PG_NOCACHE + PG_SWR  ; map to virt memory so we can work with it
  525.         mov     [virt_page1], eax
  526.  
  527.         mov     esi, [port]
  528.         mov     ebx, [phys_page1]
  529.         mov     [esi + HBA_PORT.command_list_base_l], ebx ; set the command list base
  530.         mov     [esi + HBA_PORT.command_list_base_h], 0  ; zero upper 32 bits of addr cause we are 32 bit os
  531.  
  532.         mov     edi, [pdata]
  533.         mov     ebx, [virt_page1]
  534.         mov     [edi + PORT_DATA.clb], ebx ; set pdata->clb
  535.  
  536.         mov     eax, [port]
  537.         mov     [edi + PORT_DATA.port], eax ; set pdata->port
  538.  
  539.         stdcall _memset, ebx, 0, 1024 ; zero out the command list
  540.        
  541.         ; FIS entry size = 256 bytes per port
  542.         mov     eax, [phys_page1]
  543.         add     eax, 1024
  544.         mov     [esi + HBA_PORT.fis_base_l], eax
  545.         mov     [esi + HBA_PORT.fis_base_h], 0
  546.  
  547.         mov     eax, [virt_page1]
  548.         add     eax, 1024
  549.         mov     [edi + PORT_DATA.fb], eax ; set pdata->fb
  550.         stdcall _memset, eax, 0, 256 ; zero out
  551.        
  552.         stdcall alloc_pages, 2
  553.         mov     [phys_page23], eax
  554.         stdcall map_io_mem, eax, 2*4096, PG_NOCACHE + PG_SWR
  555.         mov     [virt_page23], eax
  556.  
  557.         ; Command table size = 256*32 = 8K per port
  558.         mov     edx, [edi + PORT_DATA.clb] ; cmdheader array base
  559.         xor     ecx, ecx
  560.  
  561. .for1:
  562.         cmp     ecx, 32
  563.         jae     .for1_end
  564.  
  565.         mov     ebx, ecx
  566.         shl     ebx, BSF sizeof.HBA_CMD_HDR
  567.         add     ebx, edx ; ebx = cmdheader[ecx]
  568.  
  569.         mov     [ebx + HBA_CMD_HDR.prdtl], 8 ; 8 prdt entries per command table
  570.  
  571.         ; 256 bytes per command table, 64+16+48+16*8
  572.  
  573.         push    edx
  574.        
  575.         ; cmdheader[ecx].ctba = phys_page23 + ecx*256
  576.         mov     [ebx + HBA_CMD_HDR.ctba], ecx
  577.         shl     [ebx + HBA_CMD_HDR.ctba], BSF 256 ; *= 256
  578.         mov     eax, [ebx + HBA_CMD_HDR.ctba]
  579.         mov     edx, [phys_page23]
  580.         add     [ebx + HBA_CMD_HDR.ctba], edx
  581.  
  582.         add     eax, [virt_page23]
  583.         mov     [tmp], eax  ; tmp = virt_page23 + ecx*256
  584.         lea     eax, [ecx*4 + edi + PORT_DATA.ctba_arr] ; eax = pdata->ctba_arr[ecx]
  585.         mov     edx, [tmp]
  586.         mov     [eax], edx  ; pdata->ctba_arr[ecx] = virt_page23 + ecx*256
  587.  
  588.         pop     edx
  589.  
  590.         mov     [ebx + HBA_CMD_HDR.ctbau], 0
  591.         stdcall _memset, [eax], 0, 256 ; zero out
  592.  
  593.         inc     ecx
  594.         jmp     .for1
  595. .for1_end:
  596.        
  597.         mov     eax, [port]
  598.         call    ahci_start_cmd
  599.  
  600.         DEBUGF  1, "End rebasing port %u\n", [portno]
  601.         popad
  602.         ret    
  603. endp
  604.  
  605. ; ----------------------------------------------------------- ; TODO check
  606. ; Find a free command list slot
  607. ; in: eax - address of HBA_PORT structure
  608. ; out: eax - if not found -1, else slot index
  609. ahci_find_cmdslot:
  610.         push    ebx ecx edx esi
  611.         ; If not set in SACT and CI, the slot is free
  612.         mov     ebx, [eax + HBA_PORT.sata_active]
  613.         or      ebx, [eax + HBA_PORT.command_issue] ; ebx = slots
  614.  
  615.         mov     esi, [ahci_controller + AHCI_DATA.abar]
  616.         mov     edx, [esi + HBA_MEM.cap]
  617.         shr     edx, 8
  618.         and     edx, 0xf
  619.         DEBUGF  1, "Number of Command Slots on each port = %u\n", edx
  620.         xor     ecx, ecx
  621. .for1:
  622.         cmp     ecx, edx
  623.         jae     .for1_end
  624.  
  625.         ; if ((slots&1) == 0) return i;
  626.         bt      ebx, 0
  627.         jc      .cont1
  628.  
  629.         mov     eax, ecx
  630.         jmp     .ret
  631.  
  632. .cont1:
  633.         shr     ebx, 1
  634.         inc     ecx
  635.         jmp     .for1
  636. .for1_end:
  637.         DEBUGF  1, "Cannot find free command list entry\n"
  638.         mov     eax, -1
  639. .ret:
  640.         pop     esi edx ecx ebx
  641.         ret
  642.  
  643.  
  644. proc _memset stdcall, dest:dword, val:byte, cnt:dword ; doesnt clobber any registers
  645.         ;DEBUGF  DBG_INFO, "memset(%x, %u, %u)\n", [dest], [val], [cnt]
  646.         push    eax ecx edi
  647.         mov     edi, dword [dest]
  648.         mov     al,  byte [val]
  649.         mov     ecx, dword [cnt]
  650.         rep stosb  
  651.         pop     edi ecx eax
  652.         ret
  653. endp
  654.