diff options
-rw-r--r-- | drivers/scsi/scsi_debug.c | 116 |
1 files changed, 50 insertions, 66 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 70bcee6516c2..c98559eceade 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -1468,25 +1468,53 @@ static int resp_log_sense(struct scsi_cmnd * scp, | |||
1468 | min(len, SDEBUG_MAX_INQ_ARR_SZ)); | 1468 | min(len, SDEBUG_MAX_INQ_ARR_SZ)); |
1469 | } | 1469 | } |
1470 | 1470 | ||
1471 | static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, | 1471 | static int check_device_access_params(struct sdebug_dev_info *devi, |
1472 | unsigned int num, struct sdebug_dev_info * devip) | 1472 | unsigned long long lba, unsigned int num) |
1473 | { | 1473 | { |
1474 | unsigned long iflags; | ||
1475 | unsigned int block, from_bottom; | ||
1476 | unsigned long long u; | ||
1477 | int ret; | ||
1478 | |||
1479 | if (lba + num > sdebug_capacity) { | 1474 | if (lba + num > sdebug_capacity) { |
1480 | mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, | 1475 | mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); |
1481 | 0); | ||
1482 | return check_condition_result; | 1476 | return check_condition_result; |
1483 | } | 1477 | } |
1484 | /* transfer length excessive (tie in to block limits VPD page) */ | 1478 | /* transfer length excessive (tie in to block limits VPD page) */ |
1485 | if (num > sdebug_store_sectors) { | 1479 | if (num > sdebug_store_sectors) { |
1486 | mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, | 1480 | mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); |
1487 | 0); | ||
1488 | return check_condition_result; | 1481 | return check_condition_result; |
1489 | } | 1482 | } |
1483 | return 0; | ||
1484 | } | ||
1485 | |||
1486 | static int do_device_access(struct scsi_cmnd *scmd, | ||
1487 | struct sdebug_dev_info *devi, | ||
1488 | unsigned long long lba, unsigned int num, int write) | ||
1489 | { | ||
1490 | int ret; | ||
1491 | unsigned int block, rest = 0; | ||
1492 | int (*func)(struct scsi_cmnd *, unsigned char *, int); | ||
1493 | |||
1494 | func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; | ||
1495 | |||
1496 | block = do_div(lba, sdebug_store_sectors); | ||
1497 | if (block + num > sdebug_store_sectors) | ||
1498 | rest = block + num - sdebug_store_sectors; | ||
1499 | |||
1500 | ret = func(scmd, fake_storep + (block * SECT_SIZE), | ||
1501 | (num - rest) * SECT_SIZE); | ||
1502 | if (!ret && rest) | ||
1503 | ret = func(scmd, fake_storep, rest * SECT_SIZE); | ||
1504 | |||
1505 | return ret; | ||
1506 | } | ||
1507 | |||
1508 | static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, | ||
1509 | unsigned int num, struct sdebug_dev_info *devip) | ||
1510 | { | ||
1511 | unsigned long iflags; | ||
1512 | int ret; | ||
1513 | |||
1514 | ret = check_device_access_params(devip, lba, num); | ||
1515 | if (ret) | ||
1516 | return ret; | ||
1517 | |||
1490 | if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && | 1518 | if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && |
1491 | (lba <= OPT_MEDIUM_ERR_ADDR) && | 1519 | (lba <= OPT_MEDIUM_ERR_ADDR) && |
1492 | ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { | 1520 | ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { |
@@ -1505,74 +1533,30 @@ static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, | |||
1505 | return check_condition_result; | 1533 | return check_condition_result; |
1506 | } | 1534 | } |
1507 | read_lock_irqsave(&atomic_rw, iflags); | 1535 | read_lock_irqsave(&atomic_rw, iflags); |
1508 | if ((lba + num) <= sdebug_store_sectors) | 1536 | ret = do_device_access(SCpnt, devip, lba, num, 0); |
1509 | ret = fill_from_dev_buffer(SCpnt, | ||
1510 | fake_storep + (lba * SECT_SIZE), | ||
1511 | num * SECT_SIZE); | ||
1512 | else { | ||
1513 | /* modulo when one arg is 64 bits needs do_div() */ | ||
1514 | u = lba; | ||
1515 | block = do_div(u, sdebug_store_sectors); | ||
1516 | from_bottom = 0; | ||
1517 | if ((block + num) > sdebug_store_sectors) | ||
1518 | from_bottom = (block + num) - sdebug_store_sectors; | ||
1519 | ret = fill_from_dev_buffer(SCpnt, | ||
1520 | fake_storep + (block * SECT_SIZE), | ||
1521 | (num - from_bottom) * SECT_SIZE); | ||
1522 | if ((0 == ret) && (from_bottom > 0)) | ||
1523 | ret = fill_from_dev_buffer(SCpnt, fake_storep, | ||
1524 | from_bottom * SECT_SIZE); | ||
1525 | } | ||
1526 | read_unlock_irqrestore(&atomic_rw, iflags); | 1537 | read_unlock_irqrestore(&atomic_rw, iflags); |
1527 | return ret; | 1538 | return ret; |
1528 | } | 1539 | } |
1529 | 1540 | ||
1530 | static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, | 1541 | static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, |
1531 | unsigned int num, struct sdebug_dev_info * devip) | 1542 | unsigned int num, struct sdebug_dev_info *devip) |
1532 | { | 1543 | { |
1533 | unsigned long iflags; | 1544 | unsigned long iflags; |
1534 | unsigned int block, to_bottom; | 1545 | int ret; |
1535 | unsigned long long u; | ||
1536 | int res; | ||
1537 | 1546 | ||
1538 | if (lba + num > sdebug_capacity) { | 1547 | ret = check_device_access_params(devip, lba, num); |
1539 | mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, | 1548 | if (ret) |
1540 | 0); | 1549 | return ret; |
1541 | return check_condition_result; | ||
1542 | } | ||
1543 | /* transfer length excessive (tie in to block limits VPD page) */ | ||
1544 | if (num > sdebug_store_sectors) { | ||
1545 | mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, | ||
1546 | 0); | ||
1547 | return check_condition_result; | ||
1548 | } | ||
1549 | 1550 | ||
1550 | write_lock_irqsave(&atomic_rw, iflags); | 1551 | write_lock_irqsave(&atomic_rw, iflags); |
1551 | if ((lba + num) <= sdebug_store_sectors) | 1552 | ret = do_device_access(SCpnt, devip, lba, num, 1); |
1552 | res = fetch_to_dev_buffer(SCpnt, | ||
1553 | fake_storep + (lba * SECT_SIZE), | ||
1554 | num * SECT_SIZE); | ||
1555 | else { | ||
1556 | /* modulo when one arg is 64 bits needs do_div() */ | ||
1557 | u = lba; | ||
1558 | block = do_div(u, sdebug_store_sectors); | ||
1559 | to_bottom = 0; | ||
1560 | if ((block + num) > sdebug_store_sectors) | ||
1561 | to_bottom = (block + num) - sdebug_store_sectors; | ||
1562 | res = fetch_to_dev_buffer(SCpnt, | ||
1563 | fake_storep + (block * SECT_SIZE), | ||
1564 | (num - to_bottom) * SECT_SIZE); | ||
1565 | if ((0 == res) && (to_bottom > 0)) | ||
1566 | res = fetch_to_dev_buffer(SCpnt, fake_storep, | ||
1567 | to_bottom * SECT_SIZE); | ||
1568 | } | ||
1569 | write_unlock_irqrestore(&atomic_rw, iflags); | 1553 | write_unlock_irqrestore(&atomic_rw, iflags); |
1570 | if (-1 == res) | 1554 | if (-1 == ret) |
1571 | return (DID_ERROR << 16); | 1555 | return (DID_ERROR << 16); |
1572 | else if ((res < (num * SECT_SIZE)) && | 1556 | else if ((ret < (num * SECT_SIZE)) && |
1573 | (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) | 1557 | (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) |
1574 | printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " | 1558 | printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " |
1575 | " IO sent=%d bytes\n", num * SECT_SIZE, res); | 1559 | " IO sent=%d bytes\n", num * SECT_SIZE, ret); |
1576 | return 0; | 1560 | return 0; |
1577 | } | 1561 | } |
1578 | 1562 | ||