diff options
Diffstat (limited to 'firmware/drivers/ata.c')
-rw-r--r-- | firmware/drivers/ata.c | 63 |
1 files changed, 36 insertions, 27 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 549a7bf920..db8bdf92a0 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c | |||
@@ -89,6 +89,7 @@ static bool initialized = false; | |||
89 | static long last_user_activity = -1; | 89 | static long last_user_activity = -1; |
90 | long last_disk_activity = -1; | 90 | long last_disk_activity = -1; |
91 | 91 | ||
92 | static unsigned long total_sectors; | ||
92 | static int multisectors; /* number of supported multisectors */ | 93 | static int multisectors; /* number of supported multisectors */ |
93 | static unsigned short identify_info[SECTOR_SIZE/2]; | 94 | static unsigned short identify_info[SECTOR_SIZE/2]; |
94 | 95 | ||
@@ -284,6 +285,11 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
284 | mutex_lock(&ata_mtx); | 285 | mutex_lock(&ata_mtx); |
285 | #endif | 286 | #endif |
286 | 287 | ||
288 | if (start + incount > total_sectors) { | ||
289 | ret = -1; | ||
290 | goto error; | ||
291 | } | ||
292 | |||
287 | last_disk_activity = current_tick; | 293 | last_disk_activity = current_tick; |
288 | spinup_start = current_tick; | 294 | spinup_start = current_tick; |
289 | 295 | ||
@@ -293,16 +299,14 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
293 | spinup = true; | 299 | spinup = true; |
294 | if (poweroff) { | 300 | if (poweroff) { |
295 | if (ata_power_on()) { | 301 | if (ata_power_on()) { |
296 | mutex_unlock(&ata_mtx); | 302 | ret = -2; |
297 | ata_led(false); | 303 | goto error; |
298 | return -1; | ||
299 | } | 304 | } |
300 | } | 305 | } |
301 | else { | 306 | else { |
302 | if (perform_soft_reset()) { | 307 | if (perform_soft_reset()) { |
303 | mutex_unlock(&ata_mtx); | 308 | ret = -2; |
304 | ata_led(false); | 309 | goto error; |
305 | return -1; | ||
306 | } | 310 | } |
307 | } | 311 | } |
308 | } | 312 | } |
@@ -312,9 +316,8 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
312 | SET_REG(ATA_SELECT, ata_device); | 316 | SET_REG(ATA_SELECT, ata_device); |
313 | if (!wait_for_rdy()) | 317 | if (!wait_for_rdy()) |
314 | { | 318 | { |
315 | mutex_unlock(&ata_mtx); | 319 | ret = -3; |
316 | ata_led(false); | 320 | goto error; |
317 | return -2; | ||
318 | } | 321 | } |
319 | 322 | ||
320 | retry: | 323 | retry: |
@@ -371,7 +374,7 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
371 | We choose alternative 2. | 374 | We choose alternative 2. |
372 | */ | 375 | */ |
373 | perform_soft_reset(); | 376 | perform_soft_reset(); |
374 | ret = -4; | 377 | ret = -5; |
375 | goto retry; | 378 | goto retry; |
376 | } | 379 | } |
377 | 380 | ||
@@ -403,7 +406,7 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
403 | */ | 406 | */ |
404 | if ( status & (STATUS_BSY | STATUS_ERR | STATUS_DF) ) { | 407 | if ( status & (STATUS_BSY | STATUS_ERR | STATUS_DF) ) { |
405 | perform_soft_reset(); | 408 | perform_soft_reset(); |
406 | ret = -5; | 409 | ret = -6; |
407 | goto retry; | 410 | goto retry; |
408 | } | 411 | } |
409 | 412 | ||
@@ -415,13 +418,14 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
415 | 418 | ||
416 | if(!ret && !wait_for_end_of_transfer()) { | 419 | if(!ret && !wait_for_end_of_transfer()) { |
417 | perform_soft_reset(); | 420 | perform_soft_reset(); |
418 | ret = -3; | 421 | ret = -4; |
419 | goto retry; | 422 | goto retry; |
420 | } | 423 | } |
421 | break; | 424 | break; |
422 | } | 425 | } |
423 | ata_led(false); | ||
424 | 426 | ||
427 | error: | ||
428 | ata_led(false); | ||
425 | #ifndef MAX_PHYS_SECTOR_SIZE | 429 | #ifndef MAX_PHYS_SECTOR_SIZE |
426 | mutex_unlock(&ata_mtx); | 430 | mutex_unlock(&ata_mtx); |
427 | #endif | 431 | #endif |
@@ -489,6 +493,9 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
489 | mutex_lock(&ata_mtx); | 493 | mutex_lock(&ata_mtx); |
490 | #endif | 494 | #endif |
491 | 495 | ||
496 | if (start + count > total_sectors) | ||
497 | panicf("Writing past end of disk"); | ||
498 | |||
492 | last_disk_activity = current_tick; | 499 | last_disk_activity = current_tick; |
493 | spinup_start = current_tick; | 500 | spinup_start = current_tick; |
494 | 501 | ||
@@ -498,16 +505,14 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
498 | spinup = true; | 505 | spinup = true; |
499 | if (poweroff) { | 506 | if (poweroff) { |
500 | if (ata_power_on()) { | 507 | if (ata_power_on()) { |
501 | mutex_unlock(&ata_mtx); | 508 | ret = -1; |
502 | ata_led(false); | 509 | goto error; |
503 | return -1; | ||
504 | } | 510 | } |
505 | } | 511 | } |
506 | else { | 512 | else { |
507 | if (perform_soft_reset()) { | 513 | if (perform_soft_reset()) { |
508 | mutex_unlock(&ata_mtx); | 514 | ret = -1; |
509 | ata_led(false); | 515 | goto error; |
510 | return -1; | ||
511 | } | 516 | } |
512 | } | 517 | } |
513 | } | 518 | } |
@@ -515,9 +520,8 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
515 | SET_REG(ATA_SELECT, ata_device); | 520 | SET_REG(ATA_SELECT, ata_device); |
516 | if (!wait_for_rdy()) | 521 | if (!wait_for_rdy()) |
517 | { | 522 | { |
518 | mutex_unlock(&ata_mtx); | 523 | ret = -2; |
519 | ata_led(false); | 524 | goto error; |
520 | return -2; | ||
521 | } | 525 | } |
522 | 526 | ||
523 | #ifdef HAVE_LBA48 | 527 | #ifdef HAVE_LBA48 |
@@ -575,8 +579,8 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
575 | ret = -4; | 579 | ret = -4; |
576 | } | 580 | } |
577 | 581 | ||
582 | error: | ||
578 | ata_led(false); | 583 | ata_led(false); |
579 | |||
580 | #ifndef MAX_PHYS_SECTOR_SIZE | 584 | #ifndef MAX_PHYS_SECTOR_SIZE |
581 | mutex_unlock(&ata_mtx); | 585 | mutex_unlock(&ata_mtx); |
582 | #endif | 586 | #endif |
@@ -1240,11 +1244,16 @@ int ata_init(void) | |||
1240 | phys_sector_mult * SECTOR_SIZE); | 1244 | phys_sector_mult * SECTOR_SIZE); |
1241 | #endif | 1245 | #endif |
1242 | 1246 | ||
1247 | total_sectors = identify_info[60] | (identify_info[60] << 16); | ||
1248 | |||
1243 | #ifdef HAVE_LBA48 | 1249 | #ifdef HAVE_LBA48 |
1244 | if (identify_info[83] & 0x0400 /* 48 bit address support */ | 1250 | if (identify_info[83] & 0x0400 /* 48 bit address support */ |
1245 | && identify_info[60] == 0xFFFF /* and disk size >= 128 GiB */ | 1251 | && total_sectors == 0x0FFFFFFF) /* and disk size >= 128 GiB */ |
1246 | && identify_info[61] == 0x0FFF) /* (needs BigLBA addressing) */ | 1252 | { /* (needs BigLBA addressing) */ |
1247 | { | 1253 | if (identify_info[102] || identify_info[103]) |
1254 | panicf("Unsupported disk size, >= 2^32 sectors"); | ||
1255 | |||
1256 | total_sectors = identify_info[100] | (identify_info[101] << 16); | ||
1248 | lba48 = true; /* use BigLBA */ | 1257 | lba48 = true; /* use BigLBA */ |
1249 | } | 1258 | } |
1250 | #endif | 1259 | #endif |