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,26 +943,44 @@ static void cd_data_to_raw(uint8_t *buf, int lba) | ||
| 943 | memset(buf, 0, 288); | 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 | int sector_size) | 947 | int sector_size) |
| 948 | { | 948 | { |
| 949 | + int ret; | ||
| 950 | + | ||
| 949 | switch(sector_size) { | 951 | switch(sector_size) { |
| 950 | case 2048: | 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 | break; | 954 | break; |
| 953 | case 2352: | 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 | cd_data_to_raw(buf, lba); | 959 | cd_data_to_raw(buf, lba); |
| 956 | break; | 960 | break; |
| 957 | default: | 961 | default: |
| 962 | + ret = -EIO; | ||
| 958 | break; | 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 | /* The whole ATAPI transfer logic is handled in this function */ | 980 | /* The whole ATAPI transfer logic is handled in this function */ |
| 963 | static void ide_atapi_cmd_reply_end(IDEState *s) | 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 | #ifdef DEBUG_IDE_ATAPI | 984 | #ifdef DEBUG_IDE_ATAPI |
| 967 | printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", | 985 | printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", |
| 968 | s->packet_transfer_size, | 986 | s->packet_transfer_size, |
| @@ -981,7 +999,12 @@ static void ide_atapi_cmd_reply_end(IDEState *s) | @@ -981,7 +999,12 @@ static void ide_atapi_cmd_reply_end(IDEState *s) | ||
| 981 | } else { | 999 | } else { |
| 982 | /* see if a new sector must be read */ | 1000 | /* see if a new sector must be read */ |
| 983 | if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { | 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 | s->lba++; | 1008 | s->lba++; |
| 986 | s->io_buffer_index = 0; | 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,6 +1093,11 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) | ||
| 1070 | IDEState *s = bm->ide_if; | 1093 | IDEState *s = bm->ide_if; |
| 1071 | int data_offset, n; | 1094 | int data_offset, n; |
| 1072 | 1095 | ||
| 1096 | + if (ret < 0) { | ||
| 1097 | + ide_atapi_io_error(s, ret); | ||
| 1098 | + goto eot; | ||
| 1099 | + } | ||
| 1100 | + | ||
| 1073 | if (s->io_buffer_size > 0) { | 1101 | if (s->io_buffer_size > 0) { |
| 1074 | if (s->cd_sector_size == 2352) { | 1102 | if (s->cd_sector_size == 2352) { |
| 1075 | n = 1; | 1103 | n = 1; |
| @@ -1114,6 +1142,12 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) | @@ -1114,6 +1142,12 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) | ||
| 1114 | bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, | 1142 | bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, |
| 1115 | s->io_buffer + data_offset, n * 4, | 1143 | s->io_buffer + data_offset, n * 4, |
| 1116 | ide_atapi_cmd_read_dma_cb, bm); | 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 | /* start a CD-CDROM read command with DMA */ | 1153 | /* start a CD-CDROM read command with DMA */ |
| @@ -1270,11 +1304,6 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1270,11 +1304,6 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1270 | { | 1304 | { |
| 1271 | int nb_sectors, lba; | 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 | if (packet[0] == GPCMD_READ_10) | 1307 | if (packet[0] == GPCMD_READ_10) |
| 1279 | nb_sectors = ube16_to_cpu(packet + 7); | 1308 | nb_sectors = ube16_to_cpu(packet + 7); |
| 1280 | else | 1309 | else |
| @@ -1284,11 +1313,6 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1284,11 +1313,6 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1284 | ide_atapi_cmd_ok(s); | 1313 | ide_atapi_cmd_ok(s); |
| 1285 | break; | 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 | ide_atapi_cmd_read(s, lba, nb_sectors, 2048); | 1316 | ide_atapi_cmd_read(s, lba, nb_sectors, 2048); |
| 1293 | } | 1317 | } |
| 1294 | break; | 1318 | break; |
| @@ -1296,22 +1320,12 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1296,22 +1320,12 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1296 | { | 1320 | { |
| 1297 | int nb_sectors, lba, transfer_request; | 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 | nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; | 1323 | nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; |
| 1305 | lba = ube32_to_cpu(packet + 2); | 1324 | lba = ube32_to_cpu(packet + 2); |
| 1306 | if (nb_sectors == 0) { | 1325 | if (nb_sectors == 0) { |
| 1307 | ide_atapi_cmd_ok(s); | 1326 | ide_atapi_cmd_ok(s); |
| 1308 | break; | 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 | transfer_request = packet[9]; | 1329 | transfer_request = packet[9]; |
| 1316 | switch(transfer_request & 0xf8) { | 1330 | switch(transfer_request & 0xf8) { |
| 1317 | case 0x00: | 1331 | case 0x00: |
| @@ -1336,13 +1350,17 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1336,13 +1350,17 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1336 | case GPCMD_SEEK: | 1350 | case GPCMD_SEEK: |
| 1337 | { | 1351 | { |
| 1338 | int lba; | 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 | ide_atapi_cmd_error(s, SENSE_NOT_READY, | 1358 | ide_atapi_cmd_error(s, SENSE_NOT_READY, |
| 1341 | ASC_MEDIUM_NOT_PRESENT); | 1359 | ASC_MEDIUM_NOT_PRESENT); |
| 1342 | break; | 1360 | break; |
| 1343 | } | 1361 | } |
| 1344 | lba = ube32_to_cpu(packet + 2); | 1362 | lba = ube32_to_cpu(packet + 2); |
| 1345 | - if (((int64_t)lba << 2) > s->nb_sectors) { | 1363 | + if (lba >= total_sectors) { |
| 1346 | ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, | 1364 | ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, |
| 1347 | ASC_LOGICAL_BLOCK_OOR); | 1365 | ASC_LOGICAL_BLOCK_OOR); |
| 1348 | break; | 1366 | break; |
| @@ -1358,7 +1376,10 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1358,7 +1376,10 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1358 | 1376 | ||
| 1359 | if (eject && !start) { | 1377 | if (eject && !start) { |
| 1360 | /* eject the disk */ | 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 | ide_atapi_cmd_ok(s); | 1384 | ide_atapi_cmd_ok(s); |
| 1364 | } | 1385 | } |
| @@ -1379,8 +1400,11 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1379,8 +1400,11 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1379 | case GPCMD_READ_TOC_PMA_ATIP: | 1400 | case GPCMD_READ_TOC_PMA_ATIP: |
| 1380 | { | 1401 | { |
| 1381 | int format, msf, start_track, len; | 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 | ide_atapi_cmd_error(s, SENSE_NOT_READY, | 1408 | ide_atapi_cmd_error(s, SENSE_NOT_READY, |
| 1385 | ASC_MEDIUM_NOT_PRESENT); | 1409 | ASC_MEDIUM_NOT_PRESENT); |
| 1386 | break; | 1410 | break; |
| @@ -1391,7 +1415,7 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1391,7 +1415,7 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1391 | start_track = packet[6]; | 1415 | start_track = packet[6]; |
| 1392 | switch(format) { | 1416 | switch(format) { |
| 1393 | case 0: | 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 | if (len < 0) | 1419 | if (len < 0) |
| 1396 | goto error_cmd; | 1420 | goto error_cmd; |
| 1397 | ide_atapi_cmd_reply(s, len, max_len); | 1421 | ide_atapi_cmd_reply(s, len, max_len); |
| @@ -1405,7 +1429,7 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1405,7 +1429,7 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1405 | ide_atapi_cmd_reply(s, 12, max_len); | 1429 | ide_atapi_cmd_reply(s, 12, max_len); |
| 1406 | break; | 1430 | break; |
| 1407 | case 2: | 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 | if (len < 0) | 1433 | if (len < 0) |
| 1410 | goto error_cmd; | 1434 | goto error_cmd; |
| 1411 | ide_atapi_cmd_reply(s, len, max_len); | 1435 | ide_atapi_cmd_reply(s, len, max_len); |
| @@ -1419,15 +1443,21 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1419,15 +1443,21 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1419 | } | 1443 | } |
| 1420 | break; | 1444 | break; |
| 1421 | case GPCMD_READ_CDVD_CAPACITY: | 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 | break; | 1461 | break; |
| 1432 | case GPCMD_INQUIRY: | 1462 | case GPCMD_INQUIRY: |
| 1433 | max_len = packet[4]; | 1463 | max_len = packet[4]; |
| @@ -1451,17 +1481,6 @@ static void ide_atapi_cmd(IDEState *s) | @@ -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 | static void ide_cmd_lba48_transform(IDEState *s, int lba48) | 1484 | static void ide_cmd_lba48_transform(IDEState *s, int lba48) |
| 1466 | { | 1485 | { |
| 1467 | s->lba48 = lba48; | 1486 | s->lba48 = lba48; |
| @@ -2092,7 +2111,6 @@ static void ide_init2(IDEState *ide_state, | @@ -2092,7 +2111,6 @@ static void ide_init2(IDEState *ide_state, | ||
| 2092 | } | 2111 | } |
| 2093 | if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { | 2112 | if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { |
| 2094 | s->is_cdrom = 1; | 2113 | s->is_cdrom = 1; |
| 2095 | - bdrv_set_change_cb(s->bs, cdrom_change_cb, s); | ||
| 2096 | } | 2114 | } |
| 2097 | } | 2115 | } |
| 2098 | s->drive_serial = drive_serial++; | 2116 | s->drive_serial = drive_serial++; |