Subversion Repositories Kolibri OS

Rev

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

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