Subversion Repositories Kolibri OS

Rev

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