Subversion Repositories Kolibri OS

Rev

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