Subversion Repositories Kolibri OS

Rev

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