Subversion Repositories Kolibri OS

Rev

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