Subversion Repositories Kolibri OS

Rev

Rev 9142 | Rev 9145 | 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
9140 rgimad 27
ATA_IDENTIFY        = 0xEC
28
ATA_CMD_READ_DMA_EX = 0x25
9134 rgimad 29
 
9139 rgimad 30
; ATA constants
31
ATA_DEV_BUSY    = 0x80
32
ATA_DEV_DRQ     = 0x08
33
 
9134 rgimad 34
; ATAPI commands
35
ATAPI_IDENTIFY  = 0xA1
36
 
9023 rgimad 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
9020 rgimad 40
 
9023 rgimad 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
9020 rgimad 44
 
9023 rgimad 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
 
9065 rgimad 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
9139 rgimad 53
bit_AHCI_HBA_PxIS_TFES   = 30
9065 rgimad 54
 
9130 rgimad 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
 
9074 rgimad 60
bit_AHCI_H2D_FLAG_CMD    = 7
61
 
9037 rgimad 62
AHCI_HBA_PxSSTS_DET         = 0xF
63
AHCI_HBA_PORT_IPM_ACTIVE    = 1
64
AHCI_HBA_PxSSTS_DET_PRESENT = 3
65
 
9023 rgimad 66
AHCI_MAX_PORTS = 32        ;
9064 rgimad 67
;HBA_MEMORY_SIZE = 0x1100
9020 rgimad 68
 
9139 rgimad 69
AHCI_PORT_TIMEOUT = 1000000
70
 
9064 rgimad 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
 
9020 rgimad 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
9064 rgimad 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
9020 rgimad 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
9064 rgimad 97
        cap2                  dd ?                    ; 0x24, Host capabilities extended
9020 rgimad 98
        bohc                  dd ?                    ; 0x28, BIOS/OS handoff control and status
9072 rgimad 99
        reserved              rb (0xA0-HBA_MEM.reserved)        ; 0x2C - 0x9F, Reserved
100
        vendor                rb (0x100-HBA_MEM.vendor)         ; 0xA0 - 0xFF, Vendor specific
9023 rgimad 101
        ports                 rb (sizeof.HBA_PORT*AHCI_MAX_PORTS) ; 0x100 - 0x10FF, Port control registers, max AHCI_MAX_PORTS
9020 rgimad 102
ends
103
 
104
; Port Control registers
105
struct HBA_PORT
9064 rgimad 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
9020 rgimad 125
ends
126
 
9074 rgimad 127
; Command header structure, size = 32 bytes
9068 rgimad 128
struct HBA_CMD_HDR
9131 rgimad 129
    flags1       db ? ; 0bPWACCCCC, P - Prefetchable, W - Write (1: H2D, 0: D2H)
9068 rgimad 130
                       ; A - ATAPI, C - Command FIS length in DWORDS, 2 ~ 16
131
 
9131 rgimad 132
    flags2       db ? ; 0bPPPPRCB(Re), P - Port multiplier port, R - Reserved,
9068 rgimad 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
9072 rgimad 139
                  rd 4 ; Reserved
9068 rgimad 140
ends
141
 
9074 rgimad 142
; Physical region descriptor table entry, size = 16 bytes
9069 rgimad 143
struct HBA_PRDT_ENTRY
144
    dba           dd ?  ; Data base address
145
    dbau          dd ?  ; Data base address upper 32 bits
9072 rgimad 146
                  dd ?  ; Reserved
9131 rgimad 147
    flags        dd ?  ; 0bIR..RD..D, I (1 bit) - Interrupt on completion,
9069 rgimad 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
9072 rgimad 154
                  rb 48 ; 0x50, Reserved
9069 rgimad 155
    prdt_entry    HBA_PRDT_ENTRY  ; 0x80, Physical region descriptor table entries, 0 ~ 65535
156
                        ; so, this structure is variable-length
157
ends
158
 
9068 rgimad 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
9074 rgimad 165
    portno        dd ? ; port index, 0..31
9134 rgimad 166
    drive_type    db ? ; drive type
9140 rgimad 167
    sector_count  dq ? ; number of sectors
9068 rgimad 168
ends
169
 
9064 rgimad 170
; Register FIS – Host to Device
171
struct FIS_REG_H2D
172
        fis_type      db ?       ; FIS_TYPE_REG_H2D
9131 rgimad 173
        flags        db ?       ; 0bCRRRPPPP, C - 1: Command, 0: Control
9064 rgimad 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
 
9072 rgimad 194
                      rb 4       ; Reserved
9064 rgimad 195
ends
196
 
197
; Register FIS – Device to Host
198
struct FIS_REG_D2H
199
    fis_type      db ?           ; FIS_TYPE_REG_D2H
200
 
9131 rgimad 201
    flags        db ?           ; 0bRIRPPPP, P - Port multiplier, R - Reserved
9064 rgimad 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
9072 rgimad 215
                  db ?           ; Reserved
9064 rgimad 216
 
217
    countl        db ?           ; Count register, 7:0
218
    counth        db ?           ; Count register, 15:8
9072 rgimad 219
                  rb 2           ; Reserved
9064 rgimad 220
 
9072 rgimad 221
                  rb 4           ; Reserved
9064 rgimad 222
ends
223
 
224
; Data FIS – Bidirectional
225
struct FIS_DATA
226
    fis_type      db ?           ; FIS_TYPE_DATA
9131 rgimad 227
    flags        db ?           ; 0bRRRRPPPP, R - Reserved, P - Port multiplier
9072 rgimad 228
                  rb 2           ; Reserved
9064 rgimad 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
 
9131 rgimad 237
    flags        db ?           ; 0bRIDRPPPP, P - Port multiplier, R - Reserved
9064 rgimad 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
9072 rgimad 251
                  db ?           ; Reserved
9064 rgimad 252
 
253
    countl        db ?           ; Count register, 7:0
254
    counth        db ?           ; Count register, 15:8
9072 rgimad 255
                  db ?           ; Reserved
9064 rgimad 256
    e_status      db ?           ; New value of status register
257
 
258
    tc            dw ?           ; Transfer count
9072 rgimad 259
                  rb 2           ; Reserved
9064 rgimad 260
ends
261
 
262
; DMA Setup – Device to Host
263
struct FIS_DMA_SETUP
264
    fis_type      db ?           ; FIS_TYPE_DMA_SETUP
9131 rgimad 265
    flags        db ?           ; 0bAIDRPPPP, A - Auto-activate. Specifies if DMA Activate FIS is needed,
9064 rgimad 266
                                 ; I - Interrupt bit, D - Data transfer direction, 1 - device to host,
267
                                 ; R - Reserved, P - Port multiplier
268
 
9072 rgimad 269
                  rb 2           ; Reserved
9064 rgimad 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
 
9072 rgimad 275
                  dd ?           ; Reserved
276
    DMAbufOffset  dd ?           ; Byte offset into buffer. First 2 bits must be 0
9064 rgimad 277
    TransferCount dd ?           ; Number of bytes to transfer. Bit 0 must be 0
9072 rgimad 278
                  dd ?           ; Reserved
9064 rgimad 279
ends
280
 
281
; Set device bits FIS - device to host
282
struct FIS_DEV_BITS
283
    fis_type      db ?           ; FIS_TYPE_DEV_BITS
9131 rgimad 284
    flags        db ?           ; 0bNIRRPPPP, N - Notification, I - Interrupt,
9064 rgimad 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
 
9069 rgimad 293
struct HBA_FIS
294
    dsfis         FIS_DMA_SETUP  ; 0x00, DMA Setup FIS
9072 rgimad 295
                  rb 4           ; padding
9069 rgimad 296
 
297
    psfis         FIS_PIO_SETUP  ; 0x20, PIO Setup FIS
9072 rgimad 298
                  rb 12          ; padding
9069 rgimad 299
 
300
    rfis          FIS_REG_D2H    ; 0x40, Register - Device to Host FIS
9072 rgimad 301
                  rb 4           ; padding
9069 rgimad 302
 
303
    sdbfis        FIS_DEV_BITS   ; 0x58, Set Device Bit FIS
304
 
305
    ufis          rb 64          ; 0x60
306
 
9072 rgimad 307
                  rb (0x100 - 0xA0) ; 0xA0, Reserved
9069 rgimad 308
ends
309
 
9064 rgimad 310
; --------------------------------------------------
9020 rgimad 311
uglobal
312
align 4
313
        ahci_controller AHCI_DATA
9068 rgimad 314
        port_data_arr   rb (sizeof.PORT_DATA*AHCI_MAX_PORTS)
9140 rgimad 315
        ahci_mutex      MUTEX
9020 rgimad 316
endg
317
 
9140 rgimad 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
9143 rgimad 325
    dd  ahci_read
9140 rgimad 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
 
9064 rgimad 334
; -----------------------------------------------------------------------
9020 rgimad 335
; detect ahci controller and initialize
336
align 4
9068 rgimad 337
ahci_init:
9140 rgimad 338
        mov     ecx, ahci_mutex
339
        call    mutex_init
340
 
9020 rgimad 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
 
9023 rgimad 369
        ; get BAR5 value, it is physical address
9037 rgimad 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
9020 rgimad 375
 
9037 rgimad 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
9020 rgimad 385
        mov     [ahci_controller + AHCI_DATA.abar], eax
386
        DEBUGF  1, "K: AHCI controller BAR5 mapped to virtual addr %x\n", eax
387
 
9037 rgimad 388
        ; Restore the original BAR5 value
389
        stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, edi
390
 
9023 rgimad 391
        ; Enable dma bus mastering, memory space access, clear the "disable interrupts" bit
392
        ; Usually, it is already done before us
9024 rgimad 393
        movzx   ebx, [esi + PCIDEV.bus]
394
        movzx   ebp, [esi + PCIDEV.devfn]
395
        stdcall pci_read32, ebx, ebp, PCI_REG_STATUS_COMMAND
9020 rgimad 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
9024 rgimad 400
        stdcall pci_write32, ebx, ebp, PCI_REG_STATUS_COMMAND, eax
9020 rgimad 401
 
9023 rgimad 402
        ; ; Print some register values to debug board
403
        ; mov     esi, [ahci_controller + AHCI_DATA.abar]
9064 rgimad 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]
9020 rgimad 405
 
9023 rgimad 406
        ;-------------------------------------------------------
407
        ; Request BIOS/OS ownership handoff, if supported. (TODO check correctness)
408
        mov     esi, [ahci_controller + AHCI_DATA.abar]
9064 rgimad 409
        ;mov     ebx, [esi + HBA_MEM.cap2]
9023 rgimad 410
        ;DEBUGF  1, "K: AHCI: HBA_MEM.cap2 = %x\n", ebx
9064 rgimad 411
        bt      [esi + HBA_MEM.cap2], bit_AHCI_HBA_CAP2_BOH
9020 rgimad 412
        jnc     .end_handoff
9023 rgimad 413
        DEBUGF  1, "K: AHCI: requesting AHCI ownership change...\n"
9024 rgimad 414
        bts     [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_OOS
9020 rgimad 415
 
416
.wait_not_bos:
9024 rgimad 417
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BOS
9020 rgimad 418
        jc      .wait_not_bos
419
 
420
        mov     ebx, 3
421
        call    delay_hs
422
 
9023 rgimad 423
        ; if Bios Busy is still set after 30 mS, wait 2 seconds.
9024 rgimad 424
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BB
9020 rgimad 425
        jnc     @f
426
 
427
        mov     ebx, 200
428
        call    delay_hs
429
@@:
9023 rgimad 430
        DEBUGF  1, "K: AHCI: ownership change completed.\n"
9020 rgimad 431
 
432
.end_handoff:
9023 rgimad 433
        ;-------------------------------------------------------
9020 rgimad 434
 
9023 rgimad 435
        ; enable the AHCI and reset it
9064 rgimad 436
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
437
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
9020 rgimad 438
 
9023 rgimad 439
        ; wait for reset to complete
440
.wait_reset:
9064 rgimad 441
        bt      [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
9023 rgimad 442
        jc      .wait_reset
9020 rgimad 443
 
9023 rgimad 444
        ; enable the AHCI and interrupts
9064 rgimad 445
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
446
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_INTERRUPT_ENABLE
9023 rgimad 447
        mov     ebx, 2
448
        call    delay_hs
449
 
9064 rgimad 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]
9020 rgimad 451
 
9037 rgimad 452
        ; TODO:
453
        ; calculate irq line
454
        ; ahciHBA->ghc |= AHCI_GHC_IE;
455
        ; IDT::RegisterInterruptHandler(irq, InterruptHandler);
9064 rgimad 456
        ; ahciHBA->is = 0xffffffff;
9037 rgimad 457
 
9140 rgimad 458
        mov     [hd_counter], 0
9037 rgimad 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
9064 rgimad 465
        mov     ecx, [esi + HBA_MEM.pi]
9037 rgimad 466
        bt      ecx, ebx
467
        jnc     .continue_detect_drives
468
 
469
        mov     edi, ebx
9074 rgimad 470
        imul    edi, sizeof.HBA_PORT
9037 rgimad 471
        add     edi, HBA_MEM.ports
472
        add     edi, esi
473
        ; now edi - base of HBA_MEM.ports[ebx]
474
 
9130 rgimad 475
        DEBUGF  1, "K: AHCI: port %d, cmd = %x, ssts = %x\n", ebx, [edi + HBA_PORT.command], [edi + HBA_PORT.sata_status]
9037 rgimad 476
 
9130 rgimad 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
9134 rgimad 504
        DEBUGF  1, "Supports Staggered Spin-up, spinning up the port..\n"
9130 rgimad 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
 
9037 rgimad 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
9068 rgimad 526
        jne     .continue_detect_drives
9037 rgimad 527
 
9134 rgimad 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]
9037 rgimad 529
 
9068 rgimad 530
        mov     ecx, ebx
9074 rgimad 531
        imul    ecx, sizeof.PORT_DATA
9068 rgimad 532
        add     ecx, port_data_arr
533
        stdcall ahci_port_rebase, edi, ebx, ecx
534
 
9134 rgimad 535
        ; DEBUGF  1, "K: AHCI: After REBASING, signature = 0x%x\n", [edi + HBA_PORT.signature]
536
 
9135 rgimad 537
        ; Determine drive type by checking port signature
9134 rgimad 538
.switch_sig:
539
        cmp     [edi + HBA_PORT.signature], SATA_SIG_ATA
9135 rgimad 540
        mov     eax, AHCI_DEV_SATA
541
        jz      .end_switch_sig
542
 
9134 rgimad 543
        cmp     [edi + HBA_PORT.signature], SATA_SIG_ATAPI
9135 rgimad 544
        mov     eax, AHCI_DEV_SATAPI
545
        jz      .end_switch_sig
546
 
9134 rgimad 547
        cmp     [edi + HBA_PORT.signature], SATA_SIG_SEMB
9135 rgimad 548
        mov     eax, AHCI_DEV_SEMB
549
        jz      .end_switch_sig
550
 
9134 rgimad 551
        cmp     [edi + HBA_PORT.signature], SATA_SIG_PM
9135 rgimad 552
        mov     eax, AHCI_DEV_PM
553
        jz      .end_switch_sig
554
 
9134 rgimad 555
        DEBUGF  1, "Unknown device signature\n"
9135 rgimad 556
        mov     eax, AHCI_DEV_NULL
9134 rgimad 557
.end_switch_sig:
9136 rgimad 558
        mov     [ecx + PORT_DATA.drive_type], al
9134 rgimad 559
 
560
        DEBUGF  1, "K: AHCI: found drive on port %u: TYPE = %u\n", ebx, [ecx + PORT_DATA.drive_type]
561
 
9074 rgimad 562
        stdcall ahci_port_identify, ecx
563
 
9140 rgimad 564
        cmp     [ecx + PORT_DATA.drive_type], AHCI_DEV_SATA
565
        jne     .after_add_disk ; skip adding disk code
566
        ; register disk in system:
9143 rgimad 567
 
568
        ;stdcall ahci_read_first_sector, ecx
9141 rgimad 569
 
9142 rgimad 570
        push    ecx
9140 rgimad 571
        mov     eax, [hd_counter]
572
        xor     edx, edx
573
        mov     ecx, 10
574
        div     ecx ; eax = hd_counter / 10, edx = hd_counter % 10
575
        test    eax, eax
576
        jz      .concat_one
577
        add     al, '0'
578
        mov     byte [hd_name + 2], al
579
        add     dl, '0'
580
        mov     byte [hd_name + 3], dl
581
        jmp     .endif1
582
.concat_one:
583
        add     dl, '0'
584
        mov     byte [hd_name + 2], dl
585
.endif1:
9142 rgimad 586
        pop     ecx
9140 rgimad 587
 
588
        DEBUGF  1, "adding '%s'\n", hd_name
589
 
9142 rgimad 590
        push    ecx
9140 rgimad 591
        stdcall disk_add, ahci_callbacks, hd_name, ecx, 0
9142 rgimad 592
        pop     ecx
9140 rgimad 593
        test    eax, eax
594
        jz      .disk_add_fail
9142 rgimad 595
        push    ecx
9140 rgimad 596
        stdcall disk_media_changed, eax, 1 ; system will scan for partitions on disk
9142 rgimad 597
        pop     ecx
9141 rgimad 598
 
9140 rgimad 599
        jmp     .after_add_disk
600
 
601
.disk_add_fail:
602
        DEBUGF  1, "Failed to add disk\n"
603
.after_add_disk:
604
 
9037 rgimad 605
.continue_detect_drives:
606
        inc     ebx
607
        jmp     .detect_drives
608
 
9064 rgimad 609
 
9037 rgimad 610
 
611
.end_detect_drives:
612
 
613
 
9020 rgimad 614
        ret
9065 rgimad 615
; -------------------------------------------------
9020 rgimad 616
 
9074 rgimad 617
modelstr  rb 42
618
; Identify drive on port ; TODO check
619
; in: pdata - address of PORT_DATA structure
620
proc ahci_port_identify stdcall, pdata: dword
621
        locals
622
            cmdslot dd ?
623
            cmdheader dd ?
624
            cmdtable  dd ?
625
            buf_phys  dd ?
626
            buf_virt  dd ?
627
        endl
628
 
629
        pushad
630
 
631
        mov     esi, [pdata] ; esi - address of PORT_DATA struct of port
632
        mov     edi, [esi + PORT_DATA.port] ; edi - address of HBA_PORT struct of port
633
 
634
        mov     eax, edi
635
        call    ahci_find_cmdslot
636
 
637
        cmp     eax, -1
638
        jne      .cmdslot_found
639
 
640
        DEBUGF  1, "No free cmdslot on port %u\n", [esi + PORT_DATA.portno]
9140 rgimad 641
        jmp     .ret
9074 rgimad 642
 
643
.cmdslot_found:
644
        mov     [cmdslot], eax
9134 rgimad 645
        ; DEBUGF  1, "Found free cmdslot %u on port %u\n", [cmdslot], [esi + PORT_DATA.portno]
9074 rgimad 646
 
647
        shl     eax, BSF sizeof.HBA_CMD_HDR
648
        add     eax, [esi + PORT_DATA.clb]
649
        mov     [cmdheader], eax ; address of virtual mapping of command header
650
        mov     eax, [cmdslot]
651
        mov     eax, [esi + eax*4 + PORT_DATA.ctba_arr]
652
        mov     [cmdtable], eax ; address of virtual mapping of command table of command header
653
 
654
        stdcall _memset, eax, 0, sizeof.HBA_CMD_TBL
655
 
656
        call    alloc_page
657
        mov     [buf_phys], eax
658
 
659
        stdcall map_io_mem, eax, 4096, PG_NOCACHE + PG_SWR  ; map to virt memory so we can work with it
660
        mov     [buf_virt], eax
661
 
662
        mov     eax, [cmdtable]
663
        mov     ebx, [buf_phys]
664
        mov     dword [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.dba], ebx
665
        mov     dword [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.dbau], 0
9131 rgimad 666
        and     [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], not 0x3FFFFF ; zero out lower 22 bits, they used for byte count
667
        or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 512 - 1 ; reason why -1 see in spec on this field
668
        ; or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 1 shl 31 ; enable interrupt on completion
669
 
9074 rgimad 670
        mov     eax, [cmdheader]
9131 rgimad 671
        and     [eax + HBA_CMD_HDR.flags1], not 0x1F ; zero out lower 5 bits, they will be used for cfl
672
        or      [eax + HBA_CMD_HDR.flags1], (sizeof.FIS_REG_H2D / 4) ; set command fis length in dwords
673
        movzx   bx, [eax + HBA_CMD_HDR.flags1]
674
        btr     bx, 6 ; flag W = 0
675
        mov     [eax + HBA_CMD_HDR.flags1], bl
676
        movzx   bx, [eax + HBA_CMD_HDR.flags2]
677
        btr     bx, 2 ; flag C = 0
678
        mov     [eax + HBA_CMD_HDR.flags2], bl
9074 rgimad 679
        mov     [eax + HBA_CMD_HDR.prdtl], 1
680
 
681
        mov     eax, [cmdtable]
682
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.fis_type], FIS_TYPE_REG_H2D
9131 rgimad 683
        movzx   ebx, byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags]
9074 rgimad 684
        bts     ebx, bit_AHCI_H2D_FLAG_CMD ; Set Command bit in H2D FIS.
9131 rgimad 685
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags], bl
9134 rgimad 686
 
687
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.command], ATA_IDENTIFY
688
        cmp     [esi + PORT_DATA.drive_type], AHCI_DEV_SATAPI
689
        jne     @f
690
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.command], ATAPI_IDENTIFY
691
@@:
9074 rgimad 692
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.device], 0
693
 
9139 rgimad 694
        ; Wait on previous command to complete, before issuing new command.
695
        stdcall ahci_port_wait, edi, AHCI_PORT_TIMEOUT
696
        ; DEBUGF  1, "eax = %x\n", eax
697
        ; TODO check eax error value
9074 rgimad 698
 
699
        mov     eax, [cmdslot]
700
        bts     [edi + HBA_PORT.command_issue], eax ; Issue the command
701
 
9139 rgimad 702
        ; Wait for command completion
703
        stdcall ahci_port_cmd_wait, edi, eax;, AHCI_PORT_CMD_TIMEOUT
704
        ; DEBUGF  1, " eax = %x\n", eax
705
        ; TODO check eax error value
9074 rgimad 706
 
9134 rgimad 707
        ; DEBUGF  1, "sata_error register = 0x%x\n", [edi + HBA_PORT.sata_error]
9130 rgimad 708
 
709
        mov     esi, [buf_virt]
9074 rgimad 710
        add     esi, 27*2
711
        mov     edi, modelstr
712
        mov     ecx, ((46-27)+1)*2
713
        cld
714
        rep movsb
715
        mov     byte [edi], 0
716
 
9138 rgimad 717
        stdcall swap_bytes_in_words, modelstr, (46-27)+1
9131 rgimad 718
        DEBUGF  1, "IDENTIFICATION RESULT: MODEL = %s\n", modelstr
9074 rgimad 719
 
9138 rgimad 720
        mov     esi, [buf_virt]
721
        mov     eax, [esi + 200]
722
        mov     edx, [esi + 200 + 4]
723
        DEBUGF 1, "lba48 mode sector count = 0x%x:%x\n", edx, eax
724
 
725
        shrd    eax, edx, 11 ; i.e *512 / 1024 / 1024, 512 - sector size
726
        DEBUGF  1, "disk capacity = %u MiB ", eax
727
        shrd    eax, edx, 10 ; / 1024
728
        DEBUGF  1, "= %u GiB\n", eax
9074 rgimad 729
.ret:
730
        popad
731
        ret
732
endp
733
 
9140 rgimad 734
proc ahci_querymedia stdcall, pdata, mediainfo
735
        push    ecx edx
736
        mov     eax, [mediainfo]
737
        mov     edx, [pdata]
738
        mov     [eax + DISKMEDIAINFO.Flags], 0
739
        mov     [eax + DISKMEDIAINFO.SectorSize], 512
740
        mov     ecx, dword[edx + PORT_DATA.sector_count]
741
        mov     dword [eax + DISKMEDIAINFO.Capacity], ecx
742
        mov     ecx, dword[edx + PORT_DATA.sector_count + 4]
743
        mov     dword [eax + DISKMEDIAINFO.Capacity + 4], ecx
744
        pop     edx ecx
745
        xor     eax, eax
746
        ret
747
endp
9134 rgimad 748
 
9141 rgimad 749
;------------------------TEST-------------------------------
750
 
751
proc ahci_read_first_sector stdcall pdata: dword
9140 rgimad 752
        locals
753
            cmdslot dd ?
754
            cmdheader dd ?
755
            cmdtable  dd ?
9141 rgimad 756
            buf_phys  dd ?
757
            buf_virt  dd ?
758
            ;numsectors dd ?
9140 rgimad 759
        endl
760
 
761
        pushad
762
        mov     ecx, ahci_mutex
763
        call    mutex_lock
764
 
765
        mov     esi, [pdata] ; esi - address of PORT_DATA struct of port
766
        mov     edi, [esi + PORT_DATA.port] ; edi - address of HBA_PORT struct of port
767
        mov     eax, edi
768
        call    ahci_find_cmdslot
769
        cmp     eax, -1
770
        jne      .cmdslot_found
771
 
772
        DEBUGF  1, "No free cmdslot on port %u\n", [esi + PORT_DATA.portno]
773
        jmp     .ret
774
 
775
.cmdslot_found:
776
        mov     [cmdslot], eax
9141 rgimad 777
        DEBUGF  1, "Found free cmdslot %u on port %u\n", [cmdslot], [esi + PORT_DATA.portno]
9140 rgimad 778
 
779
        shl     eax, BSF sizeof.HBA_CMD_HDR
780
        add     eax, [esi + PORT_DATA.clb]
781
        mov     [cmdheader], eax ; address of virtual mapping of command header
782
        mov     eax, [cmdslot]
783
        mov     eax, [esi + eax*4 + PORT_DATA.ctba_arr]
784
        mov     [cmdtable], eax ; address of virtual mapping of command table of command header
785
 
786
        mov     eax, [cmdheader]
787
        and     [eax + HBA_CMD_HDR.flags1], not 0x1F ; zero out lower 5 bits, they will be used for cfl
788
        or      [eax + HBA_CMD_HDR.flags1], (sizeof.FIS_REG_H2D / 4) ; set command fis length in dwords
789
        movzx   bx, [eax + HBA_CMD_HDR.flags1]
790
        btr     bx, 6 ; flag W = 0
791
        mov     [eax + HBA_CMD_HDR.flags1], bl
792
        movzx   bx, [eax + HBA_CMD_HDR.flags2]
793
        btr     bx, 2 ; flag C = 0
794
        mov     [eax + HBA_CMD_HDR.flags2], bl
795
 
9141 rgimad 796
        mov     [eax + HBA_CMD_HDR.prdtl], 1
9140 rgimad 797
 
9141 rgimad 798
        ; zero out the command table
799
        stdcall _memset, [cmdtable], 0, sizeof.HBA_CMD_TBL
9140 rgimad 800
 
801
        DEBUGF  1, "  prdtl = %u\n", [eax + HBA_CMD_HDR.prdtl]:2
802
 
9141 rgimad 803
        call    alloc_page
804
        mov     [buf_phys], eax
9140 rgimad 805
 
9141 rgimad 806
        stdcall map_io_mem, eax, 4096, PG_NOCACHE + PG_SWR  ; map to virt memory so we can work with it
807
        mov     [buf_virt], eax
9140 rgimad 808
 
9141 rgimad 809
        mov     eax, [cmdtable]
810
        mov     ebx, [buf_phys]
811
        DEBUGF  1, "DBA = 0x%x\n", ebx
812
        mov     [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.dba], ebx
813
        mov     [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.dbau], 0
814
        and     [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], not 0x3FFFFF ; zero out lower 22 bits, they used for byte count
815
        or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 512 - 1 ; reason why -1 see in spec on this field
9140 rgimad 816
        ; or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 1 shl 31 ; enable interrupt on completion
817
 
818
        mov     eax, [cmdtable]
819
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.fis_type], FIS_TYPE_REG_H2D
820
        movzx   ebx, byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags]
821
        bts     ebx, bit_AHCI_H2D_FLAG_CMD ; Set Command bit in H2D FIS.
822
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags], bl
823
 
824
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.command], ATA_CMD_READ_DMA_EX
825
 
9141 rgimad 826
        mov     ebx, 0 ; start sector is 0
9140 rgimad 827
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba0], bl
828
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba1], bl
829
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba2], bl
830
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.device], 1 shl 6 ; LBA mode
831
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba3], bl
832
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba4], bl
833
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba5], bl
834
 
9141 rgimad 835
        ; num sectors to read  = 1
836
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.countl], 1
837
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.counth], 0
9140 rgimad 838
 
9141 rgimad 839
        ;mov     eax, [cmdheader]
840
        ;DEBUGF  1, "PRDBC = %u\n", [eax + HBA_CMD_HDR.prdbc]
841
 
9140 rgimad 842
        ; Wait on previous command to complete, before issuing new command.
843
        stdcall ahci_port_wait, edi, AHCI_PORT_TIMEOUT
844
 
845
        mov     eax, [cmdslot]
846
        bts     [edi + HBA_PORT.command_issue], eax ; Issue the command
847
 
9141 rgimad 848
        ; mov     ebx, 20
849
        ; call    delay_hs
9140 rgimad 850
        ; Wait for command completion
851
        stdcall ahci_port_cmd_wait, edi, eax;, AHCI_PORT_CMD_TIMEOUT
852
 
853
        DEBUGF  1, "sata_error register = 0x%x\n", [edi + HBA_PORT.sata_error]
854
 
855
        DEBUGF  1, "reading completed\n"
856
 
9141 rgimad 857
        ;mov     eax, [cmdheader]
858
        ;DEBUGF  1, "PRDBC = %u\n", [eax + HBA_CMD_HDR.prdbc]
859
 
9140 rgimad 860
        xor     ecx, ecx
9141 rgimad 861
        mov     esi, [buf_virt]
9140 rgimad 862
.print_data:
863
        cmp     ecx, 512
864
        jae     .end_print_data
865
 
866
        mov     al, byte [esi + ecx]
9141 rgimad 867
        mov     byte [tmpstr2], al
868
        mov     byte [tmpstr2 + 1], 0
869
        DEBUGF  1, "0x%x(%s) ", al:2, tmpstr2
9140 rgimad 870
 
871
        inc     ecx
872
        jmp     .print_data
873
.end_print_data:
874
        DEBUGF  1, "\n"
875
 
876
.ret:
877
        mov     ecx, ahci_mutex
878
        call    mutex_unlock
879
 
880
        popad
881
        xor     eax, eax
882
        ret
883
endp
9141 rgimad 884
tmpstr2    rb 16
885
;----------------------------------------------------------
9140 rgimad 886
 
9143 rgimad 887
 
888
; Read sectors
889
; return value: 0 = success, otherwise = error
890
proc ahci_read stdcall pdata: dword, buffer: dword, startsector: qword, numsectors_ptr:dword
891
        locals
892
            cmdslot dd ?
893
            cmdheader dd ?
894
            cmdtable  dd ?
895
            numsectors dd ?
896
            buffer_pos dd ?
897
            buffer_length dd ?
898
        endl
899
 
900
        pushad
901
 
902
        mov     ecx, ahci_mutex
903
        call    mutex_lock
904
 
905
;         xor     ecx, ecx
906
;         mov     esi, [buffer]
907
; .print_data:
908
;         cmp     ecx, 512
909
;         jae     .end_print_data
910
 
911
;         mov     al, byte [esi + ecx]
912
;         mov     byte [tmpstr], al
913
;         mov     byte [tmpstr + 1], 0
914
;         DEBUGF  1, "0x%x(%s) ", al:2, tmpstr
915
 
916
;         inc     ecx
917
;         jmp     .print_data
918
; .end_print_data:
919
;         DEBUGF  1, "\n"
920
 
921
        mov     eax, [numsectors_ptr]
922
        mov     eax, [eax]
923
        mov     [numsectors], eax
924
 
925
        DEBUGF  1, "  ahci_read: buffer = 0x%x, startsector = 0x%x:%x, numsectors = %u\n", [buffer], [startsector], [startsector + 4], eax
926
 
927
        mov     esi, [pdata] ; esi - address of PORT_DATA struct of port
928
        mov     edi, [esi + PORT_DATA.port] ; edi - address of HBA_PORT struct of port
929
        mov     eax, edi
930
        call    ahci_find_cmdslot
931
        cmp     eax, -1
932
        jne      .cmdslot_found
933
 
934
        DEBUGF  1, "No free cmdslot on port %u\n", [esi + PORT_DATA.portno]
935
        jmp     .ret
936
 
937
.cmdslot_found:
938
        mov     [cmdslot], eax
939
        DEBUGF  1, "Found free cmdslot %u on port %u\n", [cmdslot], [esi + PORT_DATA.portno]
940
 
941
        shl     eax, BSF sizeof.HBA_CMD_HDR
942
        add     eax, [esi + PORT_DATA.clb]
943
        mov     [cmdheader], eax ; address of virtual mapping of command header
944
        mov     eax, [cmdslot]
945
        mov     eax, [esi + eax*4 + PORT_DATA.ctba_arr]
946
        mov     [cmdtable], eax ; address of virtual mapping of command table of command header
947
 
948
        mov     eax, [cmdheader]
949
        and     [eax + HBA_CMD_HDR.flags1], not 0x1F ; zero out lower 5 bits, they will be used for cfl
950
        or      [eax + HBA_CMD_HDR.flags1], (sizeof.FIS_REG_H2D / 4) ; set command fis length in dwords
951
        movzx   bx, [eax + HBA_CMD_HDR.flags1]
952
        btr     bx, 6 ; flag W = 0
953
        mov     [eax + HBA_CMD_HDR.flags1], bl
954
        movzx   bx, [eax + HBA_CMD_HDR.flags2]
955
        btr     bx, 2 ; flag C = 0
956
        mov     [eax + HBA_CMD_HDR.flags2], bl
957
 
958
        mov     ebx, [numsectors]
959
        shl     ebx, 9 ; *= 512
960
        mov     [buffer_length], ebx
961
        dec     ebx
962
        shr     ebx, 12 ; /= 4096
963
        inc     ebx
964
        mov     [eax + HBA_CMD_HDR.prdtl], bx
965
        ;DEBUGF  1, "  prdtl = %u\n", [eax + HBA_CMD_HDR.prdtl]:2
966
 
967
        ; zero out the command table with its prdt entries
968
        dec     ebx
969
        shl     ebx, BSF sizeof.HBA_PRDT_ENTRY
970
        add     ebx, sizeof.HBA_CMD_TBL
971
        stdcall _memset, [cmdtable], 0, ebx
972
 
973
        DEBUGF  1, "  prdtl = %u\n", [eax + HBA_CMD_HDR.prdtl]:2
974
        ;jmp     .ret
975
 
976
        xor     ecx, ecx
977
        movzx   edx, [eax + HBA_CMD_HDR.prdtl]
978
        dec     edx
979
        mov     eax, [buffer]
980
        mov     [buffer_pos], eax
981
 
982
.prdt_fill:
983
        cmp     ecx, edx
984
        jae     .prdt_fill_end
985
 
986
        mov     ebx, [buffer_pos]
987
        and     ebx, 0xFFF
988
        call    get_pg_addr ; eax = phys addr
989
        add     eax, ebx
990
        DEBUGF  1, "  PHYS = 0x%x\n", eax
991
        mov     ebx, ecx
992
        shl     ebx, BSF sizeof.HBA_PRDT_ENTRY
993
        add     ebx, [cmdtable]
994
        add     ebx, HBA_CMD_TBL.prdt_entry ; now ebx - address of ecx'th prdt_entry
995
 
996
        mov     [ebx + HBA_PRDT_ENTRY.dba], eax
997
        mov     [ebx + HBA_PRDT_ENTRY.dbau], 0
998
        and     [ebx + HBA_PRDT_ENTRY.flags], not 0x3FFFFF ; zero out lower 22 bits, they used for byte count
999
        or      [ebx + HBA_PRDT_ENTRY.flags], 4096 - 1 ; reason why -1 see in spec on this field
1000
        ; or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 1 shl 31 ; enable interrupt on completion
1001
        add     [buffer_pos], 4096
1002
        sub     [buffer_length], 4096
1003
 
1004
        inc     ecx
1005
        jmp     .prdt_fill
1006
.prdt_fill_end:
1007
 
1008
        mov     ebx, [buffer_pos]
1009
        and     ebx, 0xFFF
1010
        call    get_pg_addr ; eax = phys addr
1011
        add     eax, ebx
1012
        DEBUGF  1, "  PHYS. = 0x%x\n", eax
1013
        DEBUGF  1, "  ecx = 0x%x\n", ecx
1014
        mov     ebx, ecx
1015
        shl     ebx, BSF sizeof.HBA_PRDT_ENTRY
1016
        add     ebx, [cmdtable]
1017
        add     ebx, HBA_CMD_TBL.prdt_entry ; now ebx - address of ecx'th prdt_entry
1018
        mov     [ebx + HBA_PRDT_ENTRY.dba], eax
1019
        mov     [ebx + HBA_PRDT_ENTRY.dbau], 0
1020
        and     [ebx + HBA_PRDT_ENTRY.flags], not 0x3FFFFF ; zero out lower 22 bits, they used for byte count
1021
        mov     eax, [buffer_length]
1022
        dec     eax
1023
        DEBUGF  1, " DBC. = %u\n", eax
1024
        or      [ebx + HBA_PRDT_ENTRY.flags], eax ; reason why -1 see in spec on this field
1025
        ; or      [eax + HBA_CMD_TBL.prdt_entry + HBA_PRDT_ENTRY.flags], 1 shl 31 ; enable interrupt on completion
1026
 
1027
        mov     eax, [cmdtable]
1028
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.fis_type], FIS_TYPE_REG_H2D
1029
        movzx   ebx, byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags]
1030
        bts     ebx, bit_AHCI_H2D_FLAG_CMD ; Set Command bit in H2D FIS.
1031
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.flags], bl
1032
 
1033
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.command], ATA_CMD_READ_DMA_EX
1034
 
1035
        mov     ebx, dword [startsector]
1036
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba0], bl
1037
        shr     ebx, 8
1038
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba1], bl
1039
        shr     ebx, 8
1040
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba2], bl
1041
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.device], 1 shl 6 ; LBA mode
1042
        shr     ebx, 8
1043
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba3], bl
1044
        mov     ebx, dword [startsector + 4]
1045
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba4], bl
1046
        shr     ebx, 8
1047
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.lba5], bl
1048
 
1049
        mov     ebx, [numsectors]
1050
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.countl], bl
1051
        shr     ebx, 8
1052
        mov     byte [eax + HBA_CMD_TBL.cfis + FIS_REG_H2D.counth], bl
1053
 
1054
        ; Wait on previous command to complete, before issuing new command.
1055
        stdcall ahci_port_wait, edi, AHCI_PORT_TIMEOUT
1056
 
1057
        mov     eax, [cmdslot]
1058
        bts     [edi + HBA_PORT.command_issue], eax ; Issue the command
1059
 
1060
        ; Wait for command completion
1061
        stdcall ahci_port_cmd_wait, edi, eax;, AHCI_PORT_CMD_TIMEOUT
1062
 
1063
        DEBUGF  1, "sata_error register = 0x%x\n", [edi + HBA_PORT.sata_error]
1064
 
1065
        DEBUGF  1, "reading completed\n"
1066
 
1067
        xor     ecx, ecx
1068
        mov     esi, [buffer]
1069
.print_data:
1070
        cmp     ecx, 512
1071
        jae     .end_print_data
1072
 
1073
        mov     al, byte [esi + ecx]
1074
        mov     byte [tmpstr], al
1075
        mov     byte [tmpstr + 1], 0
1076
        DEBUGF  1, "0x%x(%s) ", al:2, tmpstr
1077
 
1078
        inc     ecx
1079
        jmp     .print_data
1080
.end_print_data:
1081
        DEBUGF  1, "\n"
1082
 
1083
.ret:
1084
        mov     ecx, ahci_mutex
1085
        call    mutex_unlock
1086
 
1087
        popad
1088
        xor     eax, eax
1089
        ret
1090
endp
1091
tmpstr    rb 16
1092
 
9065 rgimad 1093
; Start command engine
1094
; in: eax - address of HBA_PORT structure
9068 rgimad 1095
ahci_start_cmd:
9065 rgimad 1096
.wait_cr: ; Wait until CR (bit15) is cleared
1097
        bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
1098
        jc      .wait_cr
1099
 
1100
        ; Set FRE (bit4) and ST (bit0)
1101
        bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE
1102
        bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST
9068 rgimad 1103
        ; maybe here call ahci flush cmd ? TODO (see seakernel)
9065 rgimad 1104
        ret
1105
 
1106
; Stop command engine
1107
; in: eax - address of HBA_PORT structure
9068 rgimad 1108
ahci_stop_cmd:
9065 rgimad 1109
        btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST ; Clear ST (bit0)
1110
        btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE ; Clear FRE (bit4)
1111
.wait_fr_cr: ; Wait until FR (bit14), CR (bit15) are cleared
1112
        bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FR
1113
        jc      .wait_fr_cr
1114
        bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
1115
        jc      .wait_fr_cr
1116
 
1117
        ret
1118
 
9139 rgimad 1119
; waits until the port is no longer busy before issuing a new command
1120
; in: [port] - address of HBA_PORT structure
1121
; [timeout] - timeout (in iterations)
1122
; out: eax = 0 if success, 1 if timeout expired
1123
proc ahci_port_wait stdcall, port: dword, timeout: dword
1124
        push    ebx ecx
1125
        mov     ebx, [port]
1126
        xor     ecx, ecx
1127
.wait:
1128
        cmp     ecx, [timeout]
1129
        jae     .wait_end
1130
        mov     eax, [ebx + HBA_PORT.task_file_data]
1131
        and     eax, ATA_DEV_BUSY or ATA_DEV_DRQ
1132
        test    eax, eax
1133
        jz      .wait_end
1134
        inc     ecx
1135
        jmp     .wait
1136
.wait_end:
1137
        xor     eax, eax
1138
        DEBUGF  1, "port wait counter = %u\n", ecx
1139
        cmp     ecx, [timeout] ; if they equal it means port is hung
1140
        setz    al
1141
        pop     ecx ebx
9068 rgimad 1142
        ret
9139 rgimad 1143
endp
9065 rgimad 1144
 
1145
 
9139 rgimad 1146
; Wait for command completion
1147
; in: [port] - address of HBA_PORT structure
1148
;     [cmdslot] - number of command slot
1149
; out: eax = 0 if success, 1 if error
1150
proc ahci_port_cmd_wait stdcall, port: dword, cmdslot: dword ;, timeout: dword
1151
        push    ebx ecx edx
1152
        mov     ebx, [port]
1153
        mov     edx, [cmdslot]
1154
        xor     eax, eax
1155
        xor     ecx, ecx
1156
.wait:
1157
        bt      [ebx + HBA_PORT.command_issue], edx
1158
        jnc     .wait_end
1159
        bt      [ebx + HBA_PORT.interrupt_status], bit_AHCI_HBA_PxIS_TFES ; check for Task File Error
1160
        jc      .error
1161
        inc     ecx
1162
        jmp     .wait
1163
.wait_end:
1164
        DEBUGF  1, "port cmd wait counter = %u\n", ecx
1165
        bt      [ebx + HBA_PORT.interrupt_status], bit_AHCI_HBA_PxIS_TFES ; check for Task File Error
1166
        jc      .error
1167
        jmp     .ret
1168
.error:
1169
        mov     eax, 1
1170
.ret:
1171
        pop     edx ecx ebx
9068 rgimad 1172
        ret
9139 rgimad 1173
endp
9065 rgimad 1174
 
9139 rgimad 1175
; ; The commands may not take effect until the command
1176
; ; register is read again by software, because reasons.
1177
; ; in: eax - address of HBA_PORT structure
1178
; ; out: eax - command register value
1179
; ahci_flush_cmd:
1180
;         mov     eax, [eax + HBA_PORT.command]
1181
;         ret
1182
 
1183
; ; Send command to port
1184
; ; in: eax - address of HBA_PORT structure
1185
; ;     ebx - index of command slot
1186
; ahci_send_cmd:
1187
;         push    ecx
1188
;         mov     [eax + HBA_PORT.interrupt_status], 0xFFFFFFFF
1189
 
1190
;         mov     cl, bl
1191
;         mov     [eax + HBA_PORT.command_issue], 1
1192
;         shl     [eax + HBA_PORT.command_issue], cl
1193
 
1194
;         call    ahci_flush_cmd
1195
;         pop     ecx
1196
;         ret
1197
 
9068 rgimad 1198
; ---------------------------------------------------------------------------
1199
; in: port - address of HBA_PORT structure
1200
;     portno - port index (0..31)
1201
;     pdata - address of PORT_DATA structure
1202
proc ahci_port_rebase stdcall, port: dword, portno: dword, pdata: dword
1203
        locals
1204
            phys_page1  dd ?
1205
            virt_page1  dd ?
1206
            phys_page23 dd ?
1207
            virt_page23 dd ?
1208
            tmp         dd ?
1209
        endl
1210
 
1211
        pushad
1212
 
1213
        DEBUGF  1, "Rebasing port %u\n", [portno]
1214
 
1215
        mov     eax, [port]
1216
        call    ahci_stop_cmd
1217
 
1218
        ; Command list entry size = 32
1219
        ; Command list entry maxim count = 32
1220
        ; Command list maxim size = 32*32 = 1K per port
1221
        call    alloc_page
1222
        mov     [phys_page1], eax
1223
 
1224
        stdcall map_io_mem, eax, 4096, PG_NOCACHE + PG_SWR  ; map to virt memory so we can work with it
1225
        mov     [virt_page1], eax
1226
 
1227
        mov     esi, [port]
1228
        mov     ebx, [phys_page1]
1229
        mov     [esi + HBA_PORT.command_list_base_l], ebx ; set the command list base
1230
        mov     [esi + HBA_PORT.command_list_base_h], 0  ; zero upper 32 bits of addr cause we are 32 bit os
1231
 
1232
        mov     edi, [pdata]
1233
        mov     ebx, [virt_page1]
1234
        mov     [edi + PORT_DATA.clb], ebx ; set pdata->clb
1235
 
1236
        mov     eax, [port]
1237
        mov     [edi + PORT_DATA.port], eax ; set pdata->port
9074 rgimad 1238
        mov     eax, [portno]               ; set pdata->portno
1239
        mov     [edi + PORT_DATA.portno], eax
9068 rgimad 1240
 
1241
        stdcall _memset, ebx, 0, 1024 ; zero out the command list
1242
 
1243
        ; FIS entry size = 256 bytes per port
1244
        mov     eax, [phys_page1]
1245
        add     eax, 1024
1246
        mov     [esi + HBA_PORT.fis_base_l], eax
1247
        mov     [esi + HBA_PORT.fis_base_h], 0
1248
 
1249
        mov     eax, [virt_page1]
1250
        add     eax, 1024
1251
        mov     [edi + PORT_DATA.fb], eax ; set pdata->fb
1252
        stdcall _memset, eax, 0, 256 ; zero out
1253
 
1254
        stdcall alloc_pages, 2
1255
        mov     [phys_page23], eax
1256
        stdcall map_io_mem, eax, 2*4096, PG_NOCACHE + PG_SWR
1257
        mov     [virt_page23], eax
1258
 
1259
        ; Command table size = 256*32 = 8K per port
1260
        mov     edx, [edi + PORT_DATA.clb] ; cmdheader array base
1261
        xor     ecx, ecx
1262
 
1263
.for1:
1264
        cmp     ecx, 32
1265
        jae     .for1_end
1266
 
1267
        mov     ebx, ecx
1268
        shl     ebx, BSF sizeof.HBA_CMD_HDR
1269
        add     ebx, edx ; ebx = cmdheader[ecx]
1270
 
1271
        mov     [ebx + HBA_CMD_HDR.prdtl], 8 ; 8 prdt entries per command table
1272
 
1273
        ; 256 bytes per command table, 64+16+48+16*8
1274
 
1275
        push    edx
1276
 
1277
        ; cmdheader[ecx].ctba = phys_page23 + ecx*256
1278
        mov     [ebx + HBA_CMD_HDR.ctba], ecx
1279
        shl     [ebx + HBA_CMD_HDR.ctba], BSF 256 ; *= 256
1280
        mov     eax, [ebx + HBA_CMD_HDR.ctba]
1281
        mov     edx, [phys_page23]
1282
        add     [ebx + HBA_CMD_HDR.ctba], edx
1283
 
1284
        add     eax, [virt_page23]
1285
        mov     [tmp], eax  ; tmp = virt_page23 + ecx*256
9069 rgimad 1286
        lea     eax, [ecx*4 + edi + PORT_DATA.ctba_arr] ; eax = pdata->ctba_arr[ecx]
9068 rgimad 1287
        mov     edx, [tmp]
1288
        mov     [eax], edx  ; pdata->ctba_arr[ecx] = virt_page23 + ecx*256
1289
 
1290
        pop     edx
1291
 
1292
        mov     [ebx + HBA_CMD_HDR.ctbau], 0
1293
        stdcall _memset, [eax], 0, 256 ; zero out
1294
 
1295
        inc     ecx
1296
        jmp     .for1
1297
.for1_end:
1298
 
1299
        mov     eax, [port]
1300
        call    ahci_start_cmd
1301
 
1302
        DEBUGF  1, "End rebasing port %u\n", [portno]
1303
        popad
1304
        ret
1305
endp
1306
 
9069 rgimad 1307
; ----------------------------------------------------------- ; TODO check
1308
; Find a free command list slot
1309
; in: eax - address of HBA_PORT structure
1310
; out: eax - if not found -1, else slot index
1311
ahci_find_cmdslot:
1312
        push    ebx ecx edx esi
1313
        ; If not set in SACT and CI, the slot is free
1314
        mov     ebx, [eax + HBA_PORT.sata_active]
1315
        or      ebx, [eax + HBA_PORT.command_issue] ; ebx = slots
9068 rgimad 1316
 
9069 rgimad 1317
        mov     esi, [ahci_controller + AHCI_DATA.abar]
1318
        mov     edx, [esi + HBA_MEM.cap]
1319
        shr     edx, 8
1320
        and     edx, 0xf
9134 rgimad 1321
        ; DEBUGF  1, "Number of Command Slots on each port = %u\n", edx
9069 rgimad 1322
        xor     ecx, ecx
1323
.for1:
1324
        cmp     ecx, edx
1325
        jae     .for1_end
9068 rgimad 1326
 
9069 rgimad 1327
        ; if ((slots&1) == 0) return i;
1328
        bt      ebx, 0
1329
        jc      .cont1
1330
 
1331
        mov     eax, ecx
1332
        jmp     .ret
1333
 
1334
.cont1:
1335
        shr     ebx, 1
1336
        inc     ecx
1337
        jmp     .for1
1338
.for1_end:
1339
        DEBUGF  1, "Cannot find free command list entry\n"
1340
        mov     eax, -1
1341
.ret:
1342
        pop     esi edx ecx ebx
1343
        ret
1344
 
1345
 
9068 rgimad 1346
proc _memset stdcall, dest:dword, val:byte, cnt:dword ; doesnt clobber any registers
1347
        ;DEBUGF  DBG_INFO, "memset(%x, %u, %u)\n", [dest], [val], [cnt]
1348
        push    eax ecx edi
1349
        mov     edi, dword [dest]
1350
        mov     al,  byte [val]
1351
        mov     ecx, dword [cnt]
9069 rgimad 1352
        rep stosb
9068 rgimad 1353
        pop     edi ecx eax
1354
        ret
1355
endp
9138 rgimad 1356
 
1357
; Swaps byte order in words
1358
; base - address of first word
1359
; len - how many words to swap bytes in
1360
; doesnt clobber any registers
1361
proc swap_bytes_in_words stdcall, base: dword, len: dword
1362
        push    eax ebx ecx
1363
        xor     ecx, ecx
1364
        mov     ebx, [base]
1365
.loop:
1366
        cmp     ecx, [len]
1367
        jae     .loop_end
1368
        mov     ax, word [ebx + ecx*2]
1369
        xchg    ah, al
1370
        mov     word [ebx + ecx*2], ax
1371
        inc     ecx
1372
        jmp     .loop
1373
.loop_end:
1374
        pop     ecx ebx eax
1375
        ret
1376
endp