Subversion Repositories Kolibri OS

Rev

Rev 9131 | Rev 9135 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9020 rgimad 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
 
9134 rgimad 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
 
9023 rgimad 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
9020 rgimad 35
 
9023 rgimad 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
9020 rgimad 39
 
9023 rgimad 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
 
9065 rgimad 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
 
9130 rgimad 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
 
9074 rgimad 54
bit_AHCI_H2D_FLAG_CMD    = 7
55
 
9037 rgimad 56
AHCI_HBA_PxSSTS_DET         = 0xF
57
AHCI_HBA_PORT_IPM_ACTIVE    = 1
58
AHCI_HBA_PxSSTS_DET_PRESENT = 3
59
 
9023 rgimad 60
AHCI_MAX_PORTS = 32        ;
9064 rgimad 61
;HBA_MEMORY_SIZE = 0x1100
9020 rgimad 62
 
9064 rgimad 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
 
9020 rgimad 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
9064 rgimad 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
9020 rgimad 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
9064 rgimad 89
        cap2                  dd ?                    ; 0x24, Host capabilities extended
9020 rgimad 90
        bohc                  dd ?                    ; 0x28, BIOS/OS handoff control and status
9072 rgimad 91
        reserved              rb (0xA0-HBA_MEM.reserved)        ; 0x2C - 0x9F, Reserved
92
        vendor                rb (0x100-HBA_MEM.vendor)         ; 0xA0 - 0xFF, Vendor specific
9023 rgimad 93
        ports                 rb (sizeof.HBA_PORT*AHCI_MAX_PORTS) ; 0x100 - 0x10FF, Port control registers, max AHCI_MAX_PORTS
9020 rgimad 94
ends
95
 
96
; Port Control registers
97
struct HBA_PORT
9064 rgimad 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
9020 rgimad 117
ends
118
 
9074 rgimad 119
; Command header structure, size = 32 bytes
9068 rgimad 120
struct HBA_CMD_HDR
9131 rgimad 121
    flags1       db ? ; 0bPWACCCCC, P - Prefetchable, W - Write (1: H2D, 0: D2H)
9068 rgimad 122
                       ; A - ATAPI, C - Command FIS length in DWORDS, 2 ~ 16
123
 
9131 rgimad 124
    flags2       db ? ; 0bPPPPRCB(Re), P - Port multiplier port, R - Reserved,
9068 rgimad 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
9072 rgimad 131
                  rd 4 ; Reserved
9068 rgimad 132
ends
133
 
9074 rgimad 134
; Physical region descriptor table entry, size = 16 bytes
9069 rgimad 135
struct HBA_PRDT_ENTRY
136
    dba           dd ?  ; Data base address
137
    dbau          dd ?  ; Data base address upper 32 bits
9072 rgimad 138
                  dd ?  ; Reserved
9131 rgimad 139
    flags        dd ?  ; 0bIR..RD..D, I (1 bit) - Interrupt on completion,
9069 rgimad 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
9072 rgimad 146
                  rb 48 ; 0x50, Reserved
9069 rgimad 147
    prdt_entry    HBA_PRDT_ENTRY  ; 0x80, Physical region descriptor table entries, 0 ~ 65535
148
                        ; so, this structure is variable-length
149
ends
150
 
9068 rgimad 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
9074 rgimad 157
    portno        dd ? ; port index, 0..31
9134 rgimad 158
    drive_type    db ? ; drive type
9068 rgimad 159
ends
160
 
9064 rgimad 161
; Register FIS – Host to Device
162
struct FIS_REG_H2D
163
        fis_type      db ?       ; FIS_TYPE_REG_H2D
9131 rgimad 164
        flags        db ?       ; 0bCRRRPPPP, C - 1: Command, 0: Control
9064 rgimad 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
 
9072 rgimad 185
                      rb 4       ; Reserved
9064 rgimad 186
ends
187
 
188
; Register FIS – Device to Host
189
struct FIS_REG_D2H
190
    fis_type      db ?           ; FIS_TYPE_REG_D2H
191
 
9131 rgimad 192
    flags        db ?           ; 0bRIRPPPP, P - Port multiplier, R - Reserved
9064 rgimad 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
9072 rgimad 206
                  db ?           ; Reserved
9064 rgimad 207
 
208
    countl        db ?           ; Count register, 7:0
209
    counth        db ?           ; Count register, 15:8
9072 rgimad 210
                  rb 2           ; Reserved
9064 rgimad 211
 
9072 rgimad 212
                  rb 4           ; Reserved
9064 rgimad 213
ends
214
 
215
; Data FIS – Bidirectional
216
struct FIS_DATA
217
    fis_type      db ?           ; FIS_TYPE_DATA
9131 rgimad 218
    flags        db ?           ; 0bRRRRPPPP, R - Reserved, P - Port multiplier
9072 rgimad 219
                  rb 2           ; Reserved
9064 rgimad 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
 
9131 rgimad 228
    flags        db ?           ; 0bRIDRPPPP, P - Port multiplier, R - Reserved
9064 rgimad 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
9072 rgimad 242
                  db ?           ; Reserved
9064 rgimad 243
 
244
    countl        db ?           ; Count register, 7:0
245
    counth        db ?           ; Count register, 15:8
9072 rgimad 246
                  db ?           ; Reserved
9064 rgimad 247
    e_status      db ?           ; New value of status register
248
 
249
    tc            dw ?           ; Transfer count
9072 rgimad 250
                  rb 2           ; Reserved
9064 rgimad 251
ends
252
 
253
; DMA Setup – Device to Host
254
struct FIS_DMA_SETUP
255
    fis_type      db ?           ; FIS_TYPE_DMA_SETUP
9131 rgimad 256
    flags        db ?           ; 0bAIDRPPPP, A - Auto-activate. Specifies if DMA Activate FIS is needed,
9064 rgimad 257
                                 ; I - Interrupt bit, D - Data transfer direction, 1 - device to host,
258
                                 ; R - Reserved, P - Port multiplier
259
 
9072 rgimad 260
                  rb 2           ; Reserved
9064 rgimad 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
 
9072 rgimad 266
                  dd ?           ; Reserved
267
    DMAbufOffset  dd ?           ; Byte offset into buffer. First 2 bits must be 0
9064 rgimad 268
    TransferCount dd ?           ; Number of bytes to transfer. Bit 0 must be 0
9072 rgimad 269
                  dd ?           ; Reserved
9064 rgimad 270
ends
271
 
272
; Set device bits FIS - device to host
273
struct FIS_DEV_BITS
274
    fis_type      db ?           ; FIS_TYPE_DEV_BITS
9131 rgimad 275
    flags        db ?           ; 0bNIRRPPPP, N - Notification, I - Interrupt,
9064 rgimad 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
 
9069 rgimad 284
struct HBA_FIS
285
    dsfis         FIS_DMA_SETUP  ; 0x00, DMA Setup FIS
9072 rgimad 286
                  rb 4           ; padding
9069 rgimad 287
 
288
    psfis         FIS_PIO_SETUP  ; 0x20, PIO Setup FIS
9072 rgimad 289
                  rb 12          ; padding
9069 rgimad 290
 
291
    rfis          FIS_REG_D2H    ; 0x40, Register - Device to Host FIS
9072 rgimad 292
                  rb 4           ; padding
9069 rgimad 293
 
294
    sdbfis        FIS_DEV_BITS   ; 0x58, Set Device Bit FIS
295
 
296
    ufis          rb 64          ; 0x60
297
 
9072 rgimad 298
                  rb (0x100 - 0xA0) ; 0xA0, Reserved
9069 rgimad 299
ends
300
 
9064 rgimad 301
; --------------------------------------------------
9020 rgimad 302
uglobal
303
align 4
304
        ahci_controller AHCI_DATA
9068 rgimad 305
        port_data_arr   rb (sizeof.PORT_DATA*AHCI_MAX_PORTS)
9020 rgimad 306
endg
307
 
9064 rgimad 308
; -----------------------------------------------------------------------
9020 rgimad 309
; detect ahci controller and initialize
310
align 4
9068 rgimad 311
ahci_init:
9020 rgimad 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
 
9023 rgimad 340
        ; get BAR5 value, it is physical address
9037 rgimad 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
9020 rgimad 346
 
9037 rgimad 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
9020 rgimad 356
        mov     [ahci_controller + AHCI_DATA.abar], eax
357
        DEBUGF  1, "K: AHCI controller BAR5 mapped to virtual addr %x\n", eax
358
 
9037 rgimad 359
        ; Restore the original BAR5 value
360
        stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, edi
361
 
9023 rgimad 362
        ; Enable dma bus mastering, memory space access, clear the "disable interrupts" bit
363
        ; Usually, it is already done before us
9024 rgimad 364
        movzx   ebx, [esi + PCIDEV.bus]
365
        movzx   ebp, [esi + PCIDEV.devfn]
366
        stdcall pci_read32, ebx, ebp, PCI_REG_STATUS_COMMAND
9020 rgimad 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
9024 rgimad 371
        stdcall pci_write32, ebx, ebp, PCI_REG_STATUS_COMMAND, eax
9020 rgimad 372
 
9023 rgimad 373
        ; ; Print some register values to debug board
374
        ; mov     esi, [ahci_controller + AHCI_DATA.abar]
9064 rgimad 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]
9020 rgimad 376
 
9023 rgimad 377
        ;-------------------------------------------------------
378
        ; Request BIOS/OS ownership handoff, if supported. (TODO check correctness)
379
        mov     esi, [ahci_controller + AHCI_DATA.abar]
9064 rgimad 380
        ;mov     ebx, [esi + HBA_MEM.cap2]
9023 rgimad 381
        ;DEBUGF  1, "K: AHCI: HBA_MEM.cap2 = %x\n", ebx
9064 rgimad 382
        bt      [esi + HBA_MEM.cap2], bit_AHCI_HBA_CAP2_BOH
9020 rgimad 383
        jnc     .end_handoff
9023 rgimad 384
        DEBUGF  1, "K: AHCI: requesting AHCI ownership change...\n"
9024 rgimad 385
        bts     [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_OOS
9020 rgimad 386
 
387
.wait_not_bos:
9024 rgimad 388
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BOS
9020 rgimad 389
        jc      .wait_not_bos
390
 
391
        mov     ebx, 3
392
        call    delay_hs
393
 
9023 rgimad 394
        ; if Bios Busy is still set after 30 mS, wait 2 seconds.
9024 rgimad 395
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BB
9020 rgimad 396
        jnc     @f
397
 
398
        mov     ebx, 200
399
        call    delay_hs
400
@@:
9023 rgimad 401
        DEBUGF  1, "K: AHCI: ownership change completed.\n"
9020 rgimad 402
 
403
.end_handoff:
9023 rgimad 404
        ;-------------------------------------------------------
9020 rgimad 405
 
9023 rgimad 406
        ; enable the AHCI and reset it
9064 rgimad 407
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
408
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
9020 rgimad 409
 
9023 rgimad 410
        ; wait for reset to complete
411
.wait_reset:
9064 rgimad 412
        bt      [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
9023 rgimad 413
        jc      .wait_reset
9020 rgimad 414
 
9023 rgimad 415
        ; enable the AHCI and interrupts
9064 rgimad 416
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
417
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_INTERRUPT_ENABLE
9023 rgimad 418
        mov     ebx, 2
419
        call    delay_hs
420
 
9064 rgimad 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]
9020 rgimad 422
 
9037 rgimad 423
        ; TODO:
424
        ; calculate irq line
425
        ; ahciHBA->ghc |= AHCI_GHC_IE;
426
        ; IDT::RegisterInterruptHandler(irq, InterruptHandler);
9064 rgimad 427
        ; ahciHBA->is = 0xffffffff;
9037 rgimad 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
9064 rgimad 435
        mov     ecx, [esi + HBA_MEM.pi]
9037 rgimad 436
        bt      ecx, ebx
437
        jnc     .continue_detect_drives
438
 
439
        mov     edi, ebx
9074 rgimad 440
        imul    edi, sizeof.HBA_PORT
9037 rgimad 441
        add     edi, HBA_MEM.ports
442
        add     edi, esi
443
        ; now edi - base of HBA_MEM.ports[ebx]
444
 
9130 rgimad 445
        DEBUGF  1, "K: AHCI: port %d, cmd = %x, ssts = %x\n", ebx, [edi + HBA_PORT.command], [edi + HBA_PORT.sata_status]
9037 rgimad 446
 
9130 rgimad 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
9134 rgimad 474
        DEBUGF  1, "Supports Staggered Spin-up, spinning up the port..\n"
9130 rgimad 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
 
9037 rgimad 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
9068 rgimad 496
        jne     .continue_detect_drives
9037 rgimad 497
 
9134 rgimad 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]
9037 rgimad 499
 
9068 rgimad 500
        mov     ecx, ebx
9074 rgimad 501
        imul    ecx, sizeof.PORT_DATA
9068 rgimad 502
        add     ecx, port_data_arr
503
        stdcall ahci_port_rebase, edi, ebx, ecx
504
 
9134 rgimad 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
 
9074 rgimad 533
        stdcall ahci_port_identify, ecx
534
 
9037 rgimad 535
.continue_detect_drives:
536
        inc     ebx
537
        jmp     .detect_drives
538
 
9064 rgimad 539
 
9037 rgimad 540
 
541
.end_detect_drives:
542
 
543
 
9020 rgimad 544
        ret
9065 rgimad 545
; -------------------------------------------------
9020 rgimad 546
 
9074 rgimad 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
9134 rgimad 574
        ; DEBUGF  1, "Found free cmdslot %u on port %u\n", [cmdslot], [esi + PORT_DATA.portno]
9074 rgimad 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
9131 rgimad 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
 
9074 rgimad 599
        mov     eax, [cmdheader]
9131 rgimad 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
9074 rgimad 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
9131 rgimad 612
        movzx   ebx, byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags]
9074 rgimad 613
        bts     ebx, bit_AHCI_H2D_FLAG_CMD ; Set Command bit in H2D FIS.
9131 rgimad 614
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags], bl
9134 rgimad 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
@@:
9074 rgimad 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
 
9134 rgimad 634
        ; DEBUGF  1, "sata_error register = 0x%x\n", [edi + HBA_PORT.sata_error]
9130 rgimad 635
 
9131 rgimad 636
;         mov     ecx, ecx
637
;         mov     esi, [buf_virt]
638
; .print_ident:
639
;         cmp     ecx, 512 - 1 ; why -1 ?
640
;         jae     .end_print_ident
9130 rgimad 641
 
9131 rgimad 642
;         mov     al, byte [esi + ecx]
643
;         mov     byte [modelstr], al
644
;         mov     byte [modelstr + 1], 0
645
;         DEBUGF  1, "(%s) ", modelstr
9130 rgimad 646
 
9131 rgimad 647
;         inc     ecx
648
;         jmp     .print_ident
649
; .end_print_ident:
650
        ; DEBUGF  1, "\n"
9130 rgimad 651
 
9134 rgimad 652
        ; DEBUGF  1, "after identification: signature = 0x%x\n", [edi + HBA_PORT.signature]
653
 
9130 rgimad 654
        mov     esi, [buf_virt]
9074 rgimad 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:
9131 rgimad 673
        DEBUGF  1, "IDENTIFICATION RESULT: MODEL = %s\n", modelstr
9074 rgimad 674
 
675
.ret:
676
        popad
677
        ret
678
endp
679
 
9134 rgimad 680
 
9065 rgimad 681
; Start command engine
682
; in: eax - address of HBA_PORT structure
9068 rgimad 683
ahci_start_cmd:
9065 rgimad 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
9068 rgimad 691
        ; maybe here call ahci flush cmd ? TODO (see seakernel)
9065 rgimad 692
        ret
693
 
694
; Stop command engine
695
; in: eax - address of HBA_PORT structure
9068 rgimad 696
ahci_stop_cmd:
9065 rgimad 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
 
9068 rgimad 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
9065 rgimad 714
 
9068 rgimad 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
9065 rgimad 725
 
9068 rgimad 726
        call    ahci_flush_cmd
727
        pop     ecx
728
        ret
9065 rgimad 729
 
9068 rgimad 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
9074 rgimad 771
        mov     eax, [portno]               ; set pdata->portno
772
        mov     [edi + PORT_DATA.portno], eax
9068 rgimad 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
9069 rgimad 819
        lea     eax, [ecx*4 + edi + PORT_DATA.ctba_arr] ; eax = pdata->ctba_arr[ecx]
9068 rgimad 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
 
9069 rgimad 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
9068 rgimad 849
 
9069 rgimad 850
        mov     esi, [ahci_controller + AHCI_DATA.abar]
851
        mov     edx, [esi + HBA_MEM.cap]
852
        shr     edx, 8
853
        and     edx, 0xf
9134 rgimad 854
        ; DEBUGF  1, "Number of Command Slots on each port = %u\n", edx
9069 rgimad 855
        xor     ecx, ecx
856
.for1:
857
        cmp     ecx, edx
858
        jae     .for1_end
9068 rgimad 859
 
9069 rgimad 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
 
9068 rgimad 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]
9069 rgimad 885
        rep stosb
9068 rgimad 886
        pop     edi ecx eax
887
        ret
888
endp