Commit 66c6ef7678939f2119eb649074babf5d5b2666f6
1 parent
ea185bbd
better support of removable media
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2123 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
69 additions
and
51 deletions
hw/ide.c
... | ... | @@ -943,26 +943,44 @@ static void cd_data_to_raw(uint8_t *buf, int lba) |
943 | 943 | memset(buf, 0, 288); |
944 | 944 | } |
945 | 945 | |
946 | -static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, | |
946 | +static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, | |
947 | 947 | int sector_size) |
948 | 948 | { |
949 | + int ret; | |
950 | + | |
949 | 951 | switch(sector_size) { |
950 | 952 | case 2048: |
951 | - bdrv_read(bs, (int64_t)lba << 2, buf, 4); | |
953 | + ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4); | |
952 | 954 | break; |
953 | 955 | case 2352: |
954 | - bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); | |
956 | + ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); | |
957 | + if (ret < 0) | |
958 | + return ret; | |
955 | 959 | cd_data_to_raw(buf, lba); |
956 | 960 | break; |
957 | 961 | default: |
962 | + ret = -EIO; | |
958 | 963 | break; |
959 | 964 | } |
965 | + return ret; | |
966 | +} | |
967 | + | |
968 | +static void ide_atapi_io_error(IDEState *s, int ret) | |
969 | +{ | |
970 | + /* XXX: handle more errors */ | |
971 | + if (ret == -ENOMEDIUM) { | |
972 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
973 | + ASC_MEDIUM_NOT_PRESENT); | |
974 | + } else { | |
975 | + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | |
976 | + ASC_LOGICAL_BLOCK_OOR); | |
977 | + } | |
960 | 978 | } |
961 | 979 | |
962 | 980 | /* The whole ATAPI transfer logic is handled in this function */ |
963 | 981 | static void ide_atapi_cmd_reply_end(IDEState *s) |
964 | 982 | { |
965 | - int byte_count_limit, size; | |
983 | + int byte_count_limit, size, ret; | |
966 | 984 | #ifdef DEBUG_IDE_ATAPI |
967 | 985 | printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", |
968 | 986 | s->packet_transfer_size, |
... | ... | @@ -981,7 +999,12 @@ static void ide_atapi_cmd_reply_end(IDEState *s) |
981 | 999 | } else { |
982 | 1000 | /* see if a new sector must be read */ |
983 | 1001 | if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { |
984 | - cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); | |
1002 | + ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); | |
1003 | + if (ret < 0) { | |
1004 | + ide_transfer_stop(s); | |
1005 | + ide_atapi_io_error(s, ret); | |
1006 | + return; | |
1007 | + } | |
985 | 1008 | s->lba++; |
986 | 1009 | s->io_buffer_index = 0; |
987 | 1010 | } |
... | ... | @@ -1070,6 +1093,11 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) |
1070 | 1093 | IDEState *s = bm->ide_if; |
1071 | 1094 | int data_offset, n; |
1072 | 1095 | |
1096 | + if (ret < 0) { | |
1097 | + ide_atapi_io_error(s, ret); | |
1098 | + goto eot; | |
1099 | + } | |
1100 | + | |
1073 | 1101 | if (s->io_buffer_size > 0) { |
1074 | 1102 | if (s->cd_sector_size == 2352) { |
1075 | 1103 | n = 1; |
... | ... | @@ -1114,6 +1142,12 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) |
1114 | 1142 | bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, |
1115 | 1143 | s->io_buffer + data_offset, n * 4, |
1116 | 1144 | ide_atapi_cmd_read_dma_cb, bm); |
1145 | + if (!bm->aiocb) { | |
1146 | + /* Note: media not present is the most likely case */ | |
1147 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
1148 | + ASC_MEDIUM_NOT_PRESENT); | |
1149 | + goto eot; | |
1150 | + } | |
1117 | 1151 | } |
1118 | 1152 | |
1119 | 1153 | /* start a CD-CDROM read command with DMA */ |
... | ... | @@ -1270,11 +1304,6 @@ static void ide_atapi_cmd(IDEState *s) |
1270 | 1304 | { |
1271 | 1305 | int nb_sectors, lba; |
1272 | 1306 | |
1273 | - if (!bdrv_is_inserted(s->bs)) { | |
1274 | - ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
1275 | - ASC_MEDIUM_NOT_PRESENT); | |
1276 | - break; | |
1277 | - } | |
1278 | 1307 | if (packet[0] == GPCMD_READ_10) |
1279 | 1308 | nb_sectors = ube16_to_cpu(packet + 7); |
1280 | 1309 | else |
... | ... | @@ -1284,11 +1313,6 @@ static void ide_atapi_cmd(IDEState *s) |
1284 | 1313 | ide_atapi_cmd_ok(s); |
1285 | 1314 | break; |
1286 | 1315 | } |
1287 | - if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { | |
1288 | - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | |
1289 | - ASC_LOGICAL_BLOCK_OOR); | |
1290 | - break; | |
1291 | - } | |
1292 | 1316 | ide_atapi_cmd_read(s, lba, nb_sectors, 2048); |
1293 | 1317 | } |
1294 | 1318 | break; |
... | ... | @@ -1296,22 +1320,12 @@ static void ide_atapi_cmd(IDEState *s) |
1296 | 1320 | { |
1297 | 1321 | int nb_sectors, lba, transfer_request; |
1298 | 1322 | |
1299 | - if (!bdrv_is_inserted(s->bs)) { | |
1300 | - ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
1301 | - ASC_MEDIUM_NOT_PRESENT); | |
1302 | - break; | |
1303 | - } | |
1304 | 1323 | nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; |
1305 | 1324 | lba = ube32_to_cpu(packet + 2); |
1306 | 1325 | if (nb_sectors == 0) { |
1307 | 1326 | ide_atapi_cmd_ok(s); |
1308 | 1327 | break; |
1309 | 1328 | } |
1310 | - if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { | |
1311 | - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | |
1312 | - ASC_LOGICAL_BLOCK_OOR); | |
1313 | - break; | |
1314 | - } | |
1315 | 1329 | transfer_request = packet[9]; |
1316 | 1330 | switch(transfer_request & 0xf8) { |
1317 | 1331 | case 0x00: |
... | ... | @@ -1336,13 +1350,17 @@ static void ide_atapi_cmd(IDEState *s) |
1336 | 1350 | case GPCMD_SEEK: |
1337 | 1351 | { |
1338 | 1352 | int lba; |
1339 | - if (!bdrv_is_inserted(s->bs)) { | |
1353 | + int64_t total_sectors; | |
1354 | + | |
1355 | + bdrv_get_geometry(s->bs, &total_sectors); | |
1356 | + total_sectors >>= 2; | |
1357 | + if (total_sectors <= 0) { | |
1340 | 1358 | ide_atapi_cmd_error(s, SENSE_NOT_READY, |
1341 | 1359 | ASC_MEDIUM_NOT_PRESENT); |
1342 | 1360 | break; |
1343 | 1361 | } |
1344 | 1362 | lba = ube32_to_cpu(packet + 2); |
1345 | - if (((int64_t)lba << 2) > s->nb_sectors) { | |
1363 | + if (lba >= total_sectors) { | |
1346 | 1364 | ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, |
1347 | 1365 | ASC_LOGICAL_BLOCK_OOR); |
1348 | 1366 | break; |
... | ... | @@ -1358,7 +1376,10 @@ static void ide_atapi_cmd(IDEState *s) |
1358 | 1376 | |
1359 | 1377 | if (eject && !start) { |
1360 | 1378 | /* eject the disk */ |
1361 | - bdrv_close(s->bs); | |
1379 | + bdrv_eject(s->bs, 1); | |
1380 | + } else if (eject && start) { | |
1381 | + /* close the tray */ | |
1382 | + bdrv_eject(s->bs, 0); | |
1362 | 1383 | } |
1363 | 1384 | ide_atapi_cmd_ok(s); |
1364 | 1385 | } |
... | ... | @@ -1379,8 +1400,11 @@ static void ide_atapi_cmd(IDEState *s) |
1379 | 1400 | case GPCMD_READ_TOC_PMA_ATIP: |
1380 | 1401 | { |
1381 | 1402 | int format, msf, start_track, len; |
1403 | + int64_t total_sectors; | |
1382 | 1404 | |
1383 | - if (!bdrv_is_inserted(s->bs)) { | |
1405 | + bdrv_get_geometry(s->bs, &total_sectors); | |
1406 | + total_sectors >>= 2; | |
1407 | + if (total_sectors <= 0) { | |
1384 | 1408 | ide_atapi_cmd_error(s, SENSE_NOT_READY, |
1385 | 1409 | ASC_MEDIUM_NOT_PRESENT); |
1386 | 1410 | break; |
... | ... | @@ -1391,7 +1415,7 @@ static void ide_atapi_cmd(IDEState *s) |
1391 | 1415 | start_track = packet[6]; |
1392 | 1416 | switch(format) { |
1393 | 1417 | case 0: |
1394 | - len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track); | |
1418 | + len = cdrom_read_toc(total_sectors, buf, msf, start_track); | |
1395 | 1419 | if (len < 0) |
1396 | 1420 | goto error_cmd; |
1397 | 1421 | ide_atapi_cmd_reply(s, len, max_len); |
... | ... | @@ -1405,7 +1429,7 @@ static void ide_atapi_cmd(IDEState *s) |
1405 | 1429 | ide_atapi_cmd_reply(s, 12, max_len); |
1406 | 1430 | break; |
1407 | 1431 | case 2: |
1408 | - len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track); | |
1432 | + len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track); | |
1409 | 1433 | if (len < 0) |
1410 | 1434 | goto error_cmd; |
1411 | 1435 | ide_atapi_cmd_reply(s, len, max_len); |
... | ... | @@ -1419,15 +1443,21 @@ static void ide_atapi_cmd(IDEState *s) |
1419 | 1443 | } |
1420 | 1444 | break; |
1421 | 1445 | case GPCMD_READ_CDVD_CAPACITY: |
1422 | - if (!bdrv_is_inserted(s->bs)) { | |
1423 | - ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
1424 | - ASC_MEDIUM_NOT_PRESENT); | |
1425 | - break; | |
1446 | + { | |
1447 | + int64_t total_sectors; | |
1448 | + | |
1449 | + bdrv_get_geometry(s->bs, &total_sectors); | |
1450 | + total_sectors >>= 2; | |
1451 | + if (total_sectors <= 0) { | |
1452 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
1453 | + ASC_MEDIUM_NOT_PRESENT); | |
1454 | + break; | |
1455 | + } | |
1456 | + /* NOTE: it is really the number of sectors minus 1 */ | |
1457 | + cpu_to_ube32(buf, total_sectors - 1); | |
1458 | + cpu_to_ube32(buf + 4, 2048); | |
1459 | + ide_atapi_cmd_reply(s, 8, 8); | |
1426 | 1460 | } |
1427 | - /* NOTE: it is really the number of sectors minus 1 */ | |
1428 | - cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1); | |
1429 | - cpu_to_ube32(buf + 4, 2048); | |
1430 | - ide_atapi_cmd_reply(s, 8, 8); | |
1431 | 1461 | break; |
1432 | 1462 | case GPCMD_INQUIRY: |
1433 | 1463 | max_len = packet[4]; |
... | ... | @@ -1451,17 +1481,6 @@ static void ide_atapi_cmd(IDEState *s) |
1451 | 1481 | } |
1452 | 1482 | } |
1453 | 1483 | |
1454 | -/* called when the inserted state of the media has changed */ | |
1455 | -static void cdrom_change_cb(void *opaque) | |
1456 | -{ | |
1457 | - IDEState *s = opaque; | |
1458 | - int64_t nb_sectors; | |
1459 | - | |
1460 | - /* XXX: send interrupt too */ | |
1461 | - bdrv_get_geometry(s->bs, &nb_sectors); | |
1462 | - s->nb_sectors = nb_sectors; | |
1463 | -} | |
1464 | - | |
1465 | 1484 | static void ide_cmd_lba48_transform(IDEState *s, int lba48) |
1466 | 1485 | { |
1467 | 1486 | s->lba48 = lba48; |
... | ... | @@ -2092,7 +2111,6 @@ static void ide_init2(IDEState *ide_state, |
2092 | 2111 | } |
2093 | 2112 | if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { |
2094 | 2113 | s->is_cdrom = 1; |
2095 | - bdrv_set_change_cb(s->bs, cdrom_change_cb, s); | |
2096 | 2114 | } |
2097 | 2115 | } |
2098 | 2116 | s->drive_serial = drive_serial++; | ... | ... |