Subversion Repositories Kolibri OS

Rev

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