Subversion Repositories Kolibri OS

Rev

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