Subversion Repositories Kolibri OS

Rev

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