1- #include < kernel.h>
1+ #include " kernel.h"
22
33void * aligned_buf = NULL ;
44uint8_t * raw_buf = NULL ;
55uint8_t * buf = NULL ;
66static uint8_t * raw_write_buf = NULL ;
77static uint8_t * aligned_write_buf = NULL ;
88
9- int find_cmdslot (ahci_hba_port_t * port , ahci_hba_mem_t * abar );
10- bool ahci_read (ahci_hba_port_t * port , uint64_t start , uint32_t count , uint16_t * buf , ahci_hba_mem_t * abar );
11- bool ahci_write (ahci_hba_port_t * port , uint64_t start , uint32_t count , char * buf , ahci_hba_mem_t * abar );
12- bool ahci_atapi_read (ahci_hba_port_t * port , uint64_t start , uint32_t count , uint16_t * buf , ahci_hba_mem_t * abar );
13- uint64_t ahci_read_size (ahci_hba_port_t * port , ahci_hba_mem_t * abar );
14- static void build_sata_label (storage_device_t * sd , const uint8_t * id_page );
15- static void humanise_capacity (char * out , size_t out_len , uint64_t bytes );
16-
179void ahci_handler ([[maybe_unused ]] uint8_t isr , [[maybe_unused ]] uint64_t error , [[maybe_unused ]] uint64_t irq , void * opaque )
1810{
1911 ahci_hba_mem_t * abar = (ahci_hba_mem_t * )opaque ;
@@ -208,9 +200,42 @@ static void build_atapi_label(storage_device_t *sd, const uint8_t *inq) {
208200 sd -> ui .is_optical = true;
209201}
210202
203+ bool wait_for_ready (ahci_hba_port_t * port ) {
204+ int spin = 0 ;
205+ while ((port -> tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ )) && spin < 1000000 ) {
206+ spin ++ ;
207+ }
208+ if (spin == 1000000 ) {
209+ return false;
210+ }
211+ return true;
212+ }
213+
214+ void fill_prdt (achi_hba_cmd_tbl_t * cmdtbl , size_t index , void * address , uint32_t byte_count_minus_one , bool interrupt ) {
215+ cmdtbl -> prdt_entry [index ].dba = (uint32_t )((uint64_t )address & 0xffffffff );
216+ cmdtbl -> prdt_entry [index ].dbau = (uint32_t )(((uint64_t )(address ) >> 32 ) & 0xffffffff );
217+ cmdtbl -> prdt_entry [index ].dbc = byte_count_minus_one ;
218+ cmdtbl -> prdt_entry [index ].i = interrupt ? 1 : 0 ;
219+ }
220+
221+ ahci_hba_cmd_header_t * get_cmdheader_for_slot (ahci_hba_port_t * port , size_t slot , bool write , bool atapi , uint16_t prdtls ) {
222+ ahci_hba_cmd_header_t * cmdheader = (ahci_hba_cmd_header_t * )(uint64_t )port -> clb ;
223+ cmdheader += slot ;
224+ cmdheader -> cfl = sizeof (ahci_fis_reg_h2d_t ) / sizeof (uint32_t );
225+ cmdheader -> w = write ? 1 : 0 ;
226+ cmdheader -> a = atapi ? 1 : 0 ;
227+ cmdheader -> prdtl = prdtls ;
228+ return cmdheader ;
229+ }
230+
231+ achi_hba_cmd_tbl_t * get_and_clear_cmdtbl (ahci_hba_cmd_header_t * cmdheader ) {
232+ achi_hba_cmd_tbl_t * cmdtbl = (achi_hba_cmd_tbl_t * )((uint64_t )cmdheader -> ctba );
233+ memset (cmdtbl , 0 , sizeof (achi_hba_cmd_tbl_t ) + (cmdheader -> prdtl - 1 )* sizeof (ahci_hba_prdt_entry_t ));
234+ return cmdtbl ;
235+ }
236+
211237/* Fills a 512-byte ATA IDENTIFY buffer into 'out'. Returns true on success. */
212- bool ahci_identify_page (ahci_hba_port_t * port , ahci_hba_mem_t * abar , uint8_t * out )
213- {
238+ bool ahci_identify_page (ahci_hba_port_t * port , ahci_hba_mem_t * abar , uint8_t * out ) {
214239 if (!out ) {
215240 return false;
216241 }
@@ -227,31 +252,18 @@ bool ahci_identify_page(ahci_hba_port_t *port, ahci_hba_mem_t *abar, uint8_t *ou
227252 buf = (uint8_t * )(((uintptr_t )raw_buf + 0xFFF ) & ~0xFFF );
228253 }
229254
230- ahci_hba_cmd_header_t * cmdheader = (ahci_hba_cmd_header_t * )(uint64_t )port -> clb ;
231- cmdheader += slot ;
232- cmdheader -> cfl = sizeof (ahci_fis_reg_h2d_t ) / sizeof (uint32_t );
233- cmdheader -> w = 0 ;
234- cmdheader -> prdtl = 1 ;
235-
236- achi_hba_cmd_tbl_t * cmdtbl = (achi_hba_cmd_tbl_t * )((uint64_t )cmdheader -> ctba );
237- memset (cmdtbl , 0 , sizeof (achi_hba_cmd_tbl_t ) + (cmdheader -> prdtl - 1 ) * sizeof (ahci_hba_prdt_entry_t ));
255+ ahci_hba_cmd_header_t * cmdheader = get_cmdheader_for_slot (port , slot , false, false, 1 );
256+ achi_hba_cmd_tbl_t * cmdtbl = get_and_clear_cmdtbl (cmdheader );
238257
239- cmdtbl -> prdt_entry [0 ].dba = (uint32_t )((uint64_t )buf & 0xffffffff );
240- cmdtbl -> prdt_entry [0 ].dbau = (uint32_t )(((uint64_t )buf ) >> 32 );
241- cmdtbl -> prdt_entry [0 ].dbc = 511 ;
242- cmdtbl -> prdt_entry [0 ].i = 1 ;
258+ fill_prdt (cmdtbl , 0 , buf , 511 , true);
243259
244260 ahci_fis_reg_h2d_t * cmdfis = (ahci_fis_reg_h2d_t * )(& cmdtbl -> cfis );
245261 memset (cmdfis , 0 , sizeof (ahci_fis_reg_h2d_t ));
246262 cmdfis -> fis_type = FIS_TYPE_REG_H2D ;
247263 cmdfis -> c = 1 ;
248264 cmdfis -> command = ATA_CMD_IDENTIFY ;
249265
250- int spin = 0 ;
251- while ((port -> tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ )) && spin < 1000000 ) {
252- spin ++ ;
253- }
254- if (spin == 1000000 ) {
266+ if (!wait_for_ready (port )) {
255267 dprintf ("Port hung [identify]\n" );
256268 return false;
257269 }
@@ -302,20 +314,10 @@ bool atapi_enquiry(ahci_hba_port_t *port, ahci_hba_mem_t *abar, uint8_t *out, ui
302314 return false;
303315 }
304316
305- ahci_hba_cmd_header_t * cmdheader = (ahci_hba_cmd_header_t * )(uint64_t )port -> clb ;
306- cmdheader += slot ;
307- cmdheader -> cfl = sizeof (ahci_fis_reg_h2d_t ) / sizeof (uint32_t );
308- cmdheader -> w = 0 ;
309- cmdheader -> a = 1 ;
310- cmdheader -> prdtl = 1 ;
311-
312- achi_hba_cmd_tbl_t * cmdtbl = (achi_hba_cmd_tbl_t * )((uint64_t )cmdheader -> ctba );
313- memset (cmdtbl , 0 , sizeof (achi_hba_cmd_tbl_t ) + (cmdheader -> prdtl - 1 ) * sizeof (ahci_hba_prdt_entry_t ));
317+ ahci_hba_cmd_header_t * cmdheader = get_cmdheader_for_slot (port , slot , false, true, 1 );
318+ achi_hba_cmd_tbl_t * cmdtbl = get_and_clear_cmdtbl (cmdheader );
314319
315- cmdtbl -> prdt_entry [0 ].dba = (uint32_t )((uint64_t )aligned_buf & 0xffffffff );
316- cmdtbl -> prdt_entry [0 ].dbau = (uint32_t )(((uint64_t )aligned_buf ) >> 32 );
317- cmdtbl -> prdt_entry [0 ].dbc = len - 1 ;
318- cmdtbl -> prdt_entry [0 ].i = 1 ;
320+ fill_prdt (cmdtbl , 0 , aligned_buf , len - 1 , true);
319321
320322 ahci_fis_reg_h2d_t * cmdfis = (ahci_fis_reg_h2d_t * )(& cmdtbl -> cfis );
321323 memset (cmdfis , 0 , sizeof (ahci_fis_reg_h2d_t ));
@@ -332,11 +334,7 @@ bool atapi_enquiry(ahci_hba_port_t *port, ahci_hba_mem_t *abar, uint8_t *out, ui
332334 cmdtbl -> acmd [4 ] = (uint8_t )len ; /* Allocation length (1 byte for 6-byte CDB) */
333335 cmdtbl -> acmd [5 ] = 0 ; /* Control */
334336
335- int spin = 0 ;
336- while ((port -> tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ )) && spin < 1000000 ) {
337- spin ++ ;
338- }
339- if (spin == 1000000 ) {
337+ if (!wait_for_ready (port )) {
340338 dprintf ("Port hung [inquiry]\n" );
341339 return false;
342340 }
@@ -454,20 +452,13 @@ bool ahci_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *
454452
455453 port -> is = (uint32_t )-1 ;
456454
457- int spin = 0 ;
458455 int slot = find_cmdslot (port , abar );
459456 if (slot == -1 ) {
460457 return false;
461458 }
462459
463- ahci_hba_cmd_header_t * cmdheader = (ahci_hba_cmd_header_t * )(uint64_t )port -> clb ;
464- cmdheader += slot ;
465- cmdheader -> cfl = sizeof (ahci_fis_reg_h2d_t ) / sizeof (uint32_t ); // Command FIS size
466- cmdheader -> w = 0 ; // read
467- cmdheader -> prdtl = (uint16_t )((count - 1 ) >> 4 ) + 1 ; // PRDT entries count (ceil(count/16))
468-
469- achi_hba_cmd_tbl_t * cmdtbl = (achi_hba_cmd_tbl_t * )((uint64_t )cmdheader -> ctba );
470- memset (cmdtbl , 0 , sizeof (achi_hba_cmd_tbl_t ) + (cmdheader -> prdtl - 1 ) * sizeof (ahci_hba_prdt_entry_t ));
460+ ahci_hba_cmd_header_t * cmdheader = get_cmdheader_for_slot (port , slot , false, false, ((count - 1 ) >> 4 ) + 1 );
461+ achi_hba_cmd_tbl_t * cmdtbl = get_and_clear_cmdtbl (cmdheader );
471462
472463 uint8_t * rd_buf = aligned_read_buf ;
473464
@@ -503,10 +494,7 @@ bool ahci_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *
503494 cmdfis -> countl = o_count & 0xFF ;
504495 cmdfis -> counth = (o_count >> 8 ) & 0xFF ;
505496
506- while ((port -> tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ )) && spin < 1000000 ) {
507- spin ++ ;
508- }
509- if (spin == 1000000 ) {
497+ if (!wait_for_ready (port )) {
510498 dprintf ("Port hung [read] (start %lx count %x)\n" , start , o_count );
511499 return false;
512500 }
@@ -539,20 +527,13 @@ bool ahci_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint16_t *
539527uint64_t ahci_read_size (ahci_hba_port_t * port , ahci_hba_mem_t * abar )
540528{
541529 port -> is = (uint32_t ) -1 ; // Clear pending interrupt bits
542- int spin = 0 ; // Spin lock timeout counter
543530 int slot = find_cmdslot (port , abar );
544531 if (slot == -1 ) {
545532 return 0 ;
546533 }
547-
548- ahci_hba_cmd_header_t * cmdheader = (ahci_hba_cmd_header_t * )(uint64_t )port -> clb ;
549- cmdheader += slot ;
550- cmdheader -> cfl = sizeof (ahci_fis_reg_h2d_t )/sizeof (uint32_t ); // Command FIS size
551- cmdheader -> w = 0 ; // Read from device
552- cmdheader -> prdtl = 1 ; // PRDT entries count
553-
554- achi_hba_cmd_tbl_t * cmdtbl = (achi_hba_cmd_tbl_t * )((uint64_t )cmdheader -> ctba );
555- memset (cmdtbl , 0 , sizeof (achi_hba_cmd_tbl_t ) + (cmdheader -> prdtl - 1 )* sizeof (ahci_hba_prdt_entry_t ));
534+
535+ ahci_hba_cmd_header_t * cmdheader = get_cmdheader_for_slot (port , slot , false, false, 1 );
536+ achi_hba_cmd_tbl_t * cmdtbl = get_and_clear_cmdtbl (cmdheader );
556537
557538 if (!raw_buf && !buf ) {
558539 raw_buf = (uint8_t * )kmalloc_low (HDD_SECTOR_SIZE + 0x1000 ); // extra for alignment
@@ -561,27 +542,20 @@ uint64_t ahci_read_size(ahci_hba_port_t *port, ahci_hba_mem_t* abar)
561542
562543 // 8K bytes (16 sectors) per PRDT
563544 // Last entry
564- cmdtbl -> prdt_entry [0 ].dba = (uint32_t )((uint64_t )buf & 0xffffffff );
565- cmdtbl -> prdt_entry [0 ].dbau = (uint32_t )(((uint64_t )(buf ) >> 32 ) & 0xffffffff );
566- cmdtbl -> prdt_entry [0 ].dbc = 511 ;
567- cmdtbl -> prdt_entry [0 ].i = 1 ;
545+ fill_prdt (cmdtbl , 0 , buf , 511 , true);
568546
569547 // Setup command
570548 ahci_fis_reg_h2d_t * cmdfis = (ahci_fis_reg_h2d_t * )(& cmdtbl -> cfis );
571549 memset (cmdfis , 0 , sizeof (ahci_fis_reg_h2d_t ));
572550 cmdfis -> fis_type = FIS_TYPE_REG_H2D ;
573551 cmdfis -> c = 1 ; // Command
574552 cmdfis -> command = ATA_CMD_IDENTIFY ; // ATA_CMD_READ_DMA_EX;
575-
576- // The below loop waits until the port is no longer busy before issuing a new command
577- while ((port -> tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ )) && spin < 1000000 ) {
578- spin ++ ;
579- }
580- if (spin == 1000000 ) {
553+
554+ if (!wait_for_ready (port )) {
581555 dprintf ("Port hung [read size]\n" );
582- return 0 ;
556+ return false ;
583557 }
584-
558+
585559 port -> ci = 1 <<slot ; // Issue command
586560
587561 // Wait for completion
@@ -623,22 +597,11 @@ bool ahci_atapi_read(ahci_hba_port_t *port, uint64_t start, uint32_t count, uint
623597 return false;
624598 }
625599
626- ahci_hba_cmd_header_t * cmdheader = (ahci_hba_cmd_header_t * )(uint64_t )(port -> clb );
627- cmdheader += slot ;
628-
629- cmdheader -> cfl = sizeof (ahci_fis_reg_h2d_t ) / sizeof (uint32_t );
630- cmdheader -> w = 0 ;
631- cmdheader -> a = 1 ;
632- cmdheader -> prdtl = 1 ;
633-
634- struct achi_hba_cmd_tbl_t * cmdtbl = (achi_hba_cmd_tbl_t * )(uint64_t )(cmdheader -> ctba );
635- memset (cmdtbl , 0 , sizeof (achi_hba_cmd_tbl_t ) + (cmdheader -> prdtl - 1 ) * sizeof (ahci_hba_prdt_entry_t ));
600+ ahci_hba_cmd_header_t * cmdheader = get_cmdheader_for_slot (port , slot , false, true, 1 );
601+ achi_hba_cmd_tbl_t * cmdtbl = get_and_clear_cmdtbl (cmdheader );
636602
637603 int i = 0 ;
638- cmdtbl -> prdt_entry [i ].dba = (uint32_t )((uint64_t )aligned_buf & 0xffffffff );
639- cmdtbl -> prdt_entry [i ].dbau = (uint32_t )(((uint64_t )(aligned_buf ) >> 32 ) & 0xffffffff );
640- cmdtbl -> prdt_entry [i ].dbc = count * ATAPI_SECTOR_SIZE - 1 ; // 2048 bytes per sector
641- cmdtbl -> prdt_entry [i ].i = 1 ;
604+ fill_prdt (cmdtbl , i , aligned_buf , count * ATAPI_SECTOR_SIZE - 1 , true);
642605
643606 ahci_fis_reg_h2d_t * cmdfis = (ahci_fis_reg_h2d_t * )cmdtbl -> cfis ;
644607 memset (cmdfis , 0 , sizeof (ahci_fis_reg_h2d_t ));
@@ -704,7 +667,6 @@ bool ahci_write(ahci_hba_port_t *port, uint64_t start, uint32_t count, char *buf
704667 uint32_t starth = ((start & 0xFFFFFFFF00000000 ) >> 32 );
705668 uint32_t o_count = count ;
706669 port -> is = (uint32_t )-1 ; // Clear pending interrupt bits
707- int spin = 0 ; // Spin lock timeout counter
708670 int slot = find_cmdslot (port , abar );
709671 if (slot == -1 ) {
710672 return false;
@@ -717,15 +679,8 @@ bool ahci_write(ahci_hba_port_t *port, uint64_t start, uint32_t count, char *buf
717679
718680 memcpy (aligned_write_buf , buf , o_count * HDD_SECTOR_SIZE );
719681
720- ahci_hba_cmd_header_t * cmdheader = (ahci_hba_cmd_header_t * )(uint64_t )port -> clb ;
721- cmdheader += slot ;
722-
723- cmdheader -> cfl = sizeof (ahci_fis_reg_h2d_t )/sizeof (uint32_t ); // Command FIS size
724- cmdheader -> w = 1 ; // Write device
725- cmdheader -> prdtl = (uint16_t )((o_count - 1 )>>4 ) + 1 ; // PRDT entries count
726-
727- achi_hba_cmd_tbl_t * cmdtbl = (achi_hba_cmd_tbl_t * )((uint64_t )cmdheader -> ctba );
728- memset (cmdtbl , 0 , sizeof (achi_hba_cmd_tbl_t ) + (cmdheader -> prdtl - 1 )* sizeof (ahci_hba_prdt_entry_t ));
682+ ahci_hba_cmd_header_t * cmdheader = get_cmdheader_for_slot (port , slot , true, false, ((o_count - 1 )>>4 ) + 1 );
683+ achi_hba_cmd_tbl_t * cmdtbl = get_and_clear_cmdtbl (cmdheader );
729684
730685 uint8_t * wr_buf = aligned_write_buf ;
731686
@@ -765,11 +720,7 @@ bool ahci_write(ahci_hba_port_t *port, uint64_t start, uint32_t count, char *buf
765720 cmdfis -> countl = o_count & 0xFF ;
766721 cmdfis -> counth = (o_count >> 8 ) & 0xFF ;
767722
768- // The below loop waits until the port is no longer busy before issuing a new command
769- while ((port -> tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ )) && spin < 1000000 ) {
770- spin ++ ;
771- }
772- if (spin == 1000000 ) {
723+ if (!wait_for_ready (port )) {
773724 dprintf ("Port hung [write] (start %lx count %x)\n" , start , o_count );
774725 return false;
775726 }
@@ -818,7 +769,7 @@ static void ata_copy_str(char *dst, size_t dst_len, const uint8_t *id_page, int
818769 }
819770}
820771
821- static void humanise_capacity (char * out , size_t out_len , uint64_t bytes ) {
772+ void humanise_capacity (char * out , size_t out_len , uint64_t bytes ) {
822773 const char * units [] = { "B" , "KB" , "MB" , "GB" , "TB" , "PB" };
823774 int u = 0 ;
824775 uint64_t v = bytes ;
@@ -831,7 +782,7 @@ static void humanise_capacity(char *out, size_t out_len, uint64_t bytes) {
831782 snprintf (out , out_len , "%lu %s" , v , units [u ]);
832783}
833784
834- static void build_sata_label (storage_device_t * sd , const uint8_t * id_page ) {
785+ void build_sata_label (storage_device_t * sd , const uint8_t * id_page ) {
835786 char model [48 ] = {0 };
836787 char size_str [24 ] = {0 };
837788
0 commit comments