@@ -37,6 +37,18 @@ static inline void ahci_unlock_port_io(int portno)
3737 __sync_lock_release (& ahci_port_io_lock [portno ]);
3838}
3939
40+ static int ahci_find_free_slot (ahci_port_t * port )
41+ {
42+ uint32_t slots = port -> sact | port -> ci ;
43+
44+ for (int i = 0 ; i < 32 ; i ++ ) {
45+ if (!(slots & (1 << i )))
46+ return i ;
47+ }
48+
49+ return -1 ; // no free slot
50+ }
51+
4052static int ahci_read_sector_raw (int portno , uint64_t lba , void * buffer , uint32_t count );
4153static int ahci_write_sector_raw (int portno , uint64_t lba , void * buffer , uint32_t count );
4254
@@ -460,23 +472,25 @@ static int ahci_wait_slot0_ready(ahci_port_t* port)
460472 return -1 ;
461473}
462474
463- static int ahci_read_sector_raw (int portno , uint64_t lba , void * buffer , uint32_t count ) {
475+ static int ahci_read_sector_raw (int portno , uint64_t lba , void * buffer , uint32_t count )
476+ {
464477 int rc = 0 ;
465478 ahci_port_t * port = & global_ahci_ctrl -> ports [portno ];
466479 ahci_port_mem_t * mem = & port_mem [portno ];
480+
467481 ahci_lock_port_io (portno );
468482
469- while (port -> tfd & (0x80 | 0x08 ));
483+ while (port -> tfd & (0x80 | 0x08 )); // BSY | DRQ
470484
471- int slot = 0 ;
472- if (ahci_wait_slot0_ready ( port ) != 0 ) {
485+ int slot = ahci_find_free_slot ( port ) ;
486+ if (slot < 0 ) {
473487 rc = -1 ;
474488 goto out ;
475489 }
476490
477491 ahci_cmd_header_t * hdr = & mem -> cmd_list [slot ];
478492 memset (hdr , 0 , sizeof (* hdr ));
479- hdr -> flags = 5 ;
493+ hdr -> flags = ( 5 & AHCI_CMD_HDR_CFL_MASK ); // CFL = 5 DWORDS
480494 hdr -> prdtl = 1 ;
481495 hdr -> ctba = (uint32_t )(uintptr_t )mem -> cmd_tables [slot ];
482496 hdr -> ctbau = 0 ;
@@ -485,7 +499,13 @@ static int ahci_read_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t
485499 memset (tbl -> cfis , 0 , 64 );
486500 memset (tbl -> prdt , 0 , sizeof (tbl -> prdt ));
487501
488- tbl -> prdt [0 ].dba = (uint32_t )(uintptr_t )buffer ;
502+ void * dma_buf = kmalloc_aligned (count * 512 , 4096 );
503+ if (!dma_buf ) {
504+ rc = -10 ;
505+ goto out ;
506+ }
507+
508+ tbl -> prdt [0 ].dba = (uint32_t )(uintptr_t )dma_buf ;
489509 tbl -> prdt [0 ].dbau = 0 ;
490510 tbl -> prdt [0 ].dbc = (count * 512 - 1 ) | (1 << 31 );
491511
@@ -494,19 +514,21 @@ static int ahci_read_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t
494514 cfis [1 ] = 1 << 7 ;
495515 cfis [2 ] = READ_DMA_EXT ;
496516
497- cfis [4 ] = (uint8_t )lba ;
498- cfis [5 ] = (uint8_t )(lba >> 8 );
499- cfis [6 ] = (uint8_t )(lba >> 16 );
500- cfis [7 ] = 0x40 ;
501- cfis [8 ] = (uint8_t )(lba >> 24 );
502- cfis [9 ] = (uint8_t )(lba >> 32 );
517+ cfis [4 ] = (uint8_t )lba ;
518+ cfis [5 ] = (uint8_t )(lba >> 8 );
519+ cfis [6 ] = (uint8_t )(lba >> 16 );
520+ cfis [7 ] = 0x40 ;
521+ cfis [8 ] = (uint8_t )(lba >> 24 );
522+ cfis [9 ] = (uint8_t )(lba >> 32 );
503523 cfis [10 ] = (uint8_t )(lba >> 40 );
524+
504525 cfis [12 ] = count & 0xFF ;
505526 cfis [13 ] = (count >> 8 ) & 0xFF ;
506527
507528 port -> serr = 0xFFFFFFFF ;
508- port -> is = 0xFFFFFFFF ;
529+ port -> is = 0xFFFFFFFF ;
509530
531+ __sync_synchronize ();
510532 port -> ci = 1 << slot ;
511533
512534 while (port -> ci & (1 << slot )) {
@@ -517,28 +539,33 @@ static int ahci_read_sector_raw(int portno, uint64_t lba, void* buffer, uint32_t
517539 }
518540
519541 port -> is = 0xFFFFFFFF ;
542+
520543out :
544+ memcpy (buffer , dma_buf , count * 512 );
545+ kfree (dma_buf );
521546 ahci_unlock_port_io (portno );
522547 return rc ;
523548}
524549
525- static int ahci_write_sector_raw (int portno , uint64_t lba , void * buffer , uint32_t count ) {
550+ static int ahci_write_sector_raw (int portno , uint64_t lba , void * buffer , uint32_t count )
551+ {
526552 int rc = 0 ;
527553 ahci_port_t * port = & global_ahci_ctrl -> ports [portno ];
528554 ahci_port_mem_t * mem = & port_mem [portno ];
555+
529556 ahci_lock_port_io (portno );
530557
531- while (port -> tfd & (0x80 | 0x08 ));
558+ while (port -> tfd & (0x80 | 0x08 )); // BSY | DRQ
532559
533- int slot = 0 ;
534- if (ahci_wait_slot0_ready ( port ) != 0 ) {
560+ int slot = ahci_find_free_slot ( port ) ;
561+ if (slot < 0 ) {
535562 rc = -1 ;
536563 goto out ;
537564 }
538565
539566 ahci_cmd_header_t * hdr = & mem -> cmd_list [slot ];
540567 memset (hdr , 0 , sizeof (* hdr ));
541- hdr -> flags = 5 | AHCI_CMD_HDR_W_BIT ;
568+ hdr -> flags = ( 5 & AHCI_CMD_HDR_CFL_MASK ) | AHCI_CMD_HDR_W_BIT ;
542569 hdr -> prdtl = 1 ;
543570 hdr -> ctba = (uint32_t )(uintptr_t )mem -> cmd_tables [slot ];
544571 hdr -> ctbau = 0 ;
@@ -547,7 +574,13 @@ static int ahci_write_sector_raw(int portno, uint64_t lba, void* buffer, uint32_
547574 memset (tbl -> cfis , 0 , 64 );
548575 memset (tbl -> prdt , 0 , sizeof (tbl -> prdt ));
549576
550- tbl -> prdt [0 ].dba = (uint32_t )(uintptr_t )buffer ;
577+ void * dma_buf = kmalloc_aligned (count * 512 , 4096 );
578+ if (!dma_buf ) {
579+ rc = -10 ;
580+ goto out ;
581+ }
582+
583+ tbl -> prdt [0 ].dba = (uint32_t )(uintptr_t )dma_buf ;
551584 tbl -> prdt [0 ].dbau = 0 ;
552585 tbl -> prdt [0 ].dbc = (count * 512 - 1 ) | (1 << 31 );
553586
@@ -556,91 +589,99 @@ static int ahci_write_sector_raw(int portno, uint64_t lba, void* buffer, uint32_
556589 cfis [1 ] = 1 << 7 ;
557590 cfis [2 ] = ATA_CMD_WRITE_DMA_EXT ;
558591
559- cfis [4 ] = (uint8_t )lba ;
560- cfis [5 ] = (uint8_t )(lba >> 8 );
561- cfis [6 ] = (uint8_t )(lba >> 16 );
562- cfis [7 ] = 0x40 ;
563- cfis [8 ] = (uint8_t )(lba >> 24 );
564- cfis [9 ] = (uint8_t )(lba >> 32 );
592+ cfis [4 ] = (uint8_t )lba ;
593+ cfis [5 ] = (uint8_t )(lba >> 8 );
594+ cfis [6 ] = (uint8_t )(lba >> 16 );
595+ cfis [7 ] = 0x40 ;
596+ cfis [8 ] = (uint8_t )(lba >> 24 );
597+ cfis [9 ] = (uint8_t )(lba >> 32 );
565598 cfis [10 ] = (uint8_t )(lba >> 40 );
599+
566600 cfis [12 ] = count & 0xFF ;
567601 cfis [13 ] = (count >> 8 ) & 0xFF ;
568602
569603 port -> serr = 0xFFFFFFFF ;
570- port -> is = 0xFFFFFFFF ;
604+ port -> is = 0xFFFFFFFF ;
571605
606+ __sync_synchronize ();
572607 port -> ci = 1 << slot ;
573608
574609 while (port -> ci & (1 << slot )) {
575- if (port -> tfd & (0x01 | 0x20 )) { // ERR | DF
576- port -> is = 0xFFFFFFFF ;
577- printf ("[AHCI] Write error! tfd=0x%X\n" , port -> tfd );
610+ if (port -> tfd & (0x01 | 0x20 )) {
578611 rc = -3 ;
579612 goto out ;
580613 }
581614 }
582615
583616 port -> is = 0xFFFFFFFF ;
617+
584618out :
619+ memcpy (dma_buf , buffer , count * 512 );
620+ kfree (dma_buf );
585621 ahci_unlock_port_io (portno );
586622 return rc ;
587623}
588624
589- int ahci_identify (int portno , void * buffer ) {
625+ int ahci_identify (int portno , void * buffer )
626+ {
590627 int rc = 0 ;
591628 ahci_port_t * port = & global_ahci_ctrl -> ports [portno ];
592629 ahci_port_mem_t * mem = & port_mem [portno ];
630+
593631 ahci_lock_port_io (portno );
594632
595- // Wait until port is ready
596- while (port -> tfd & (0x80 | 0x08 )); // BSY | DRQ
633+ while (port -> tfd & (0x80 | 0x08 ));
597634
598- int slot = 0 ;
599- if (ahci_wait_slot0_ready ( port ) != 0 ) {
635+ int slot = ahci_find_free_slot ( port ) ;
636+ if (slot < 0 ) {
600637 rc = -1 ;
601638 goto out ;
602639 }
603640
604641 ahci_cmd_header_t * hdr = & mem -> cmd_list [slot ];
605642 memset (hdr , 0 , sizeof (* hdr ));
606- hdr -> flags = 5 ;
607- hdr -> prdtl = 1 ; // one PRDT entry
643+ hdr -> flags = ( 5 & AHCI_CMD_HDR_CFL_MASK ); // CFL = 5 DWORDS
644+ hdr -> prdtl = 1 ;
608645 hdr -> ctba = (uint32_t )(uintptr_t )mem -> cmd_tables [slot ];
609646 hdr -> ctbau = 0 ;
610647
611-
612648 ahci_cmd_table_t * tbl = mem -> cmd_tables [slot ];
613649 memset (tbl -> cfis , 0 , 64 );
614650 memset (tbl -> prdt , 0 , sizeof (tbl -> prdt ));
615651
652+ void * dma_buf = kmalloc_aligned (512 , 4096 );
653+ if (!dma_buf ) {
654+ rc = -10 ;
655+ goto out ;
656+ }
616657
617- tbl -> prdt [0 ].dba = (uint32_t )(uintptr_t )buffer ;
658+ tbl -> prdt [0 ].dba = (uint32_t )(uintptr_t )dma_buf ;
618659 tbl -> prdt [0 ].dbau = 0 ;
619- tbl -> prdt [0 ].dbc = (512 - 1 ) | (1 << 31 ); // 512 bytes, IOC
660+ tbl -> prdt [0 ].dbc = (512 - 1 ) | (1 << 31 );
620661
621662 uint8_t * cfis = tbl -> cfis ;
622- cfis [0 ] = 0x27 ; // Host to device
623- cfis [1 ] = 1 << 7 ; // Command
624- cfis [2 ] = ATA_CMD_IDENTIFY ; // IDENTIFY DEVICE
625- cfis [7 ] = 0 ; // Features = 0
626- cfis [8 ] = 0 ; cfis [9 ] = 0 ; cfis [10 ] = 0 ; // LBA = 0
663+ cfis [0 ] = 0x27 ;
664+ cfis [1 ] = 1 << 7 ;
665+ cfis [2 ] = ATA_CMD_IDENTIFY ;
627666
628667 port -> serr = 0xFFFFFFFF ;
629668 port -> is = 0xFFFFFFFF ;
630669
670+ __sync_synchronize ();
631671 port -> ci = 1 << slot ;
632672
633- // Wait for completion
634673 while (port -> ci & (1 << slot )) {
635- if (port -> tfd & (0x01 | 0x20 )) { // ERR | DF
636- port -> is = 0xFFFFFFFF ;
674+ if (port -> tfd & (0x01 | 0x20 )) {
637675 rc = -2 ;
638676 goto out ;
639677 }
640678 }
641679
642680 port -> is = 0xFFFFFFFF ;
681+
643682out :
683+ memcpy (buffer , dma_buf , 512 );
684+ kfree (dma_buf );
644685 ahci_unlock_port_io (portno );
645686 return rc ;
646687}
0 commit comments