mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-18 21:26:31 +00:00
- Makes initial pass-through devices checks less strict. The main reason for that is because not all devices comply SCSI requirements too well.
- Workarounds in vdisk readv/writev limitation to process only limited number of entries per call git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1528 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -65,7 +65,7 @@ static struct scst_dev_type cdrom_devtype = {
|
||||
*************************************************************/
|
||||
static int cdrom_attach(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
int res, rc;
|
||||
uint8_t cmd[10];
|
||||
const int buffer_size = 512;
|
||||
uint8_t *buffer = NULL;
|
||||
@@ -106,10 +106,11 @@ static int cdrom_attach(struct scst_device *dev)
|
||||
retries = SCST_DEV_UA_RETRIES;
|
||||
while (1) {
|
||||
memset(buffer, 0, buffer_size);
|
||||
memset(sense_buffer, 0, sizeof(sense_buffer));
|
||||
data_dir = SCST_DATA_READ;
|
||||
|
||||
TRACE_DBG("%s", "Doing READ_CAPACITY");
|
||||
res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
|
||||
rc = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
|
||||
buffer_size, sense_buffer,
|
||||
SCST_GENERIC_CDROM_REG_TIMEOUT, 3, 0
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
|
||||
@@ -117,9 +118,9 @@ static int cdrom_attach(struct scst_device *dev)
|
||||
#endif
|
||||
);
|
||||
|
||||
TRACE_DBG("READ_CAPACITY done: %x", res);
|
||||
TRACE_DBG("READ_CAPACITY done: %x", rc);
|
||||
|
||||
if ((res == 0) ||
|
||||
if ((rc == 0) ||
|
||||
!scst_analyze_sense(sense_buffer,
|
||||
sizeof(sense_buffer), SCST_SENSE_KEY_VALID,
|
||||
UNIT_ATTENTION, 0, 0))
|
||||
@@ -129,11 +130,12 @@ static int cdrom_attach(struct scst_device *dev)
|
||||
PRINT_ERROR("UA not cleared after %d retries",
|
||||
SCST_DEV_UA_RETRIES);
|
||||
params->block_shift = CDROM_DEF_BLOCK_SHIFT;
|
||||
res = -ENODEV;
|
||||
goto out_free_buf;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
if (rc == 0) {
|
||||
int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) |
|
||||
(buffer[6] << 8) | (buffer[7] << 0));
|
||||
if (sector_size == 0)
|
||||
@@ -144,9 +146,11 @@ static int cdrom_attach(struct scst_device *dev)
|
||||
TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)",
|
||||
sector_size, dev->scsi_dev->scsi_level, SCSI_2);
|
||||
} else {
|
||||
TRACE_BUFFER("Returned sense", sense_buffer,
|
||||
sizeof(sense_buffer));
|
||||
params->block_shift = CDROM_DEF_BLOCK_SHIFT;
|
||||
TRACE(TRACE_MINOR, "Read capacity failed: %x, using default "
|
||||
"sector size %d", rc, params->block_shift);
|
||||
PRINT_BUFF_FLAG(TRACE_MINOR, "Returned sense", sense_buffer,
|
||||
sizeof(sense_buffer));
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
|
||||
@@ -61,7 +61,7 @@ static struct scst_dev_type changer_devtype = {
|
||||
*************************************************************/
|
||||
static int changer_attach(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
int res, rc;
|
||||
int retries;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -86,18 +86,19 @@ static int changer_attach(struct scst_device *dev)
|
||||
retries = SCST_DEV_UA_RETRIES;
|
||||
do {
|
||||
TRACE_DBG("%s", "Doing TEST_UNIT_READY");
|
||||
res = scsi_test_unit_ready(dev->scsi_dev,
|
||||
rc = scsi_test_unit_ready(dev->scsi_dev,
|
||||
SCST_GENERIC_CHANGER_TIMEOUT, CHANGER_RETRIES
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
|
||||
);
|
||||
#else
|
||||
, NULL);
|
||||
#endif
|
||||
TRACE_DBG("TEST_UNIT_READY done: %x", res);
|
||||
} while ((--retries > 0) && res);
|
||||
if (res) {
|
||||
res = -ENODEV;
|
||||
goto out;
|
||||
TRACE_DBG("TEST_UNIT_READY done: %x", rc);
|
||||
} while ((--retries > 0) && rc);
|
||||
|
||||
if (rc) {
|
||||
PRINT_WARNING("Unit not ready: %x", rc);
|
||||
/* Let's try not to be too smart and continue processing */
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
|
||||
@@ -152,7 +152,7 @@ module_exit(exit_scst_disk_driver);
|
||||
*************************************************************/
|
||||
static int disk_attach(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
int res, rc;
|
||||
uint8_t cmd[10];
|
||||
const int buffer_size = 512;
|
||||
uint8_t *buffer = NULL;
|
||||
@@ -193,10 +193,11 @@ static int disk_attach(struct scst_device *dev)
|
||||
retries = SCST_DEV_UA_RETRIES;
|
||||
while (1) {
|
||||
memset(buffer, 0, buffer_size);
|
||||
memset(sense_buffer, 0, sizeof(sense_buffer));
|
||||
data_dir = SCST_DATA_READ;
|
||||
|
||||
TRACE_DBG("%s", "Doing READ_CAPACITY");
|
||||
res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
|
||||
rc = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
|
||||
buffer_size, sense_buffer,
|
||||
SCST_GENERIC_DISK_REG_TIMEOUT, 3, 0
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
|
||||
@@ -204,15 +205,12 @@ static int disk_attach(struct scst_device *dev)
|
||||
#endif
|
||||
);
|
||||
|
||||
TRACE_DBG("READ_CAPACITY done: %x", res);
|
||||
TRACE_DBG("READ_CAPACITY done: %x", rc);
|
||||
|
||||
if ((res == 0) ||
|
||||
if ((rc == 0) ||
|
||||
!scst_analyze_sense(sense_buffer,
|
||||
sizeof(sense_buffer), SCST_SENSE_ALL_VALID,
|
||||
SCST_LOAD_SENSE(scst_sense_medium_changed_UA)) ||
|
||||
!scst_analyze_sense(sense_buffer, sizeof(sense_buffer),
|
||||
SCST_SENSE_KEY_VALID | SCST_SENSE_ASC_VALID,
|
||||
UNIT_ATTENTION, 0x29, 0))
|
||||
sizeof(sense_buffer), SCST_SENSE_KEY_VALID,
|
||||
UNIT_ATTENTION, 0, 0))
|
||||
break;
|
||||
if (!--retries) {
|
||||
PRINT_ERROR("UA not clear after %d retries",
|
||||
@@ -221,7 +219,7 @@ static int disk_attach(struct scst_device *dev)
|
||||
goto out_free_buf;
|
||||
}
|
||||
}
|
||||
if (res == 0) {
|
||||
if (rc == 0) {
|
||||
int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) |
|
||||
(buffer[6] << 8) | (buffer[7] << 0));
|
||||
if (sector_size == 0)
|
||||
@@ -230,10 +228,11 @@ static int disk_attach(struct scst_device *dev)
|
||||
params->block_shift =
|
||||
scst_calc_block_shift(sector_size);
|
||||
} else {
|
||||
TRACE_BUFFER("Returned sense", sense_buffer,
|
||||
params->block_shift = DISK_DEF_BLOCK_SHIFT;
|
||||
TRACE(TRACE_MINOR, "Read capacity failed: %x, using default "
|
||||
"sector size %d", rc, params->block_shift);
|
||||
PRINT_BUFF_FLAG(TRACE_MINOR, "Returned sense", sense_buffer,
|
||||
sizeof(sense_buffer));
|
||||
res = -ENODEV;
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
|
||||
@@ -152,7 +152,7 @@ module_exit(exit_scst_modisk_driver);
|
||||
*************************************************************/
|
||||
static int modisk_attach(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
int res, rc;
|
||||
uint8_t cmd[10];
|
||||
const int buffer_size = 512;
|
||||
uint8_t *buffer = NULL;
|
||||
@@ -207,10 +207,11 @@ static int modisk_attach(struct scst_device *dev)
|
||||
retries = SCST_DEV_UA_RETRIES;
|
||||
while (1) {
|
||||
memset(buffer, 0, buffer_size);
|
||||
memset(sense_buffer, 0, sizeof(sense_buffer));
|
||||
data_dir = SCST_DATA_READ;
|
||||
|
||||
TRACE_DBG("%s", "Doing READ_CAPACITY");
|
||||
res = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
|
||||
rc = scsi_execute(dev->scsi_dev, cmd, data_dir, buffer,
|
||||
buffer_size, sense_buffer,
|
||||
SCST_GENERIC_MODISK_REG_TIMEOUT, 3, 0
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
|
||||
@@ -218,9 +219,9 @@ static int modisk_attach(struct scst_device *dev)
|
||||
#endif
|
||||
);
|
||||
|
||||
TRACE_DBG("READ_CAPACITY done: %x", res);
|
||||
TRACE_DBG("READ_CAPACITY done: %x", rc);
|
||||
|
||||
if (!res || !scst_analyze_sense(sense_buffer,
|
||||
if (!rc || !scst_analyze_sense(sense_buffer,
|
||||
sizeof(sense_buffer), SCST_SENSE_KEY_VALID,
|
||||
UNIT_ATTENTION, 0, 0))
|
||||
break;
|
||||
@@ -232,7 +233,7 @@ static int modisk_attach(struct scst_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
if (rc == 0) {
|
||||
int sector_size = ((buffer[4] << 24) | (buffer[5] << 16) |
|
||||
(buffer[6] << 8) | (buffer[7] << 0));
|
||||
if (sector_size == 0)
|
||||
@@ -243,13 +244,11 @@ static int modisk_attach(struct scst_device *dev)
|
||||
TRACE_DBG("Sector size is %i scsi_level %d(SCSI_2 %d)",
|
||||
sector_size, dev->scsi_dev->scsi_level, SCSI_2);
|
||||
} else {
|
||||
TRACE_BUFFER("Returned sense", sense_buffer,
|
||||
params->block_shift = MODISK_DEF_BLOCK_SHIFT;
|
||||
TRACE(TRACE_MINOR, "Read capacity failed: %x, using default "
|
||||
"sector size %d", rc, params->block_shift);
|
||||
PRINT_BUFF_FLAG(TRACE_MINOR, "Returned sense", sense_buffer,
|
||||
sizeof(sense_buffer));
|
||||
|
||||
if (sense_buffer[2] != NOT_READY) {
|
||||
res = -ENODEV;
|
||||
goto out_free_buf;
|
||||
}
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
|
||||
@@ -61,7 +61,7 @@ static struct scst_dev_type processor_devtype = {
|
||||
*************************************************************/
|
||||
static int processor_attach(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
int res, rc;
|
||||
int retries;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -86,18 +86,19 @@ static int processor_attach(struct scst_device *dev)
|
||||
retries = SCST_DEV_UA_RETRIES;
|
||||
do {
|
||||
TRACE_DBG("%s", "Doing TEST_UNIT_READY");
|
||||
res = scsi_test_unit_ready(dev->scsi_dev,
|
||||
rc = scsi_test_unit_ready(dev->scsi_dev,
|
||||
SCST_GENERIC_PROCESSOR_TIMEOUT, PROCESSOR_RETRIES
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
|
||||
);
|
||||
#else
|
||||
, NULL);
|
||||
#endif
|
||||
TRACE_DBG("TEST_UNIT_READY done: %x", res);
|
||||
} while ((--retries > 0) && res);
|
||||
if (res) {
|
||||
res = -ENODEV;
|
||||
goto out;
|
||||
TRACE_DBG("TEST_UNIT_READY done: %x", rc);
|
||||
} while ((--retries > 0) && rc);
|
||||
|
||||
if (rc) {
|
||||
PRINT_WARNING("Unit not ready: %x", rc);
|
||||
/* Let's try not to be too smart and continue processing */
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
|
||||
@@ -61,7 +61,7 @@ static struct scst_dev_type raid_devtype = {
|
||||
*************************************************************/
|
||||
static int raid_attach(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
int res, rc;
|
||||
int retries;
|
||||
|
||||
TRACE_ENTRY();
|
||||
@@ -86,18 +86,19 @@ static int raid_attach(struct scst_device *dev)
|
||||
retries = SCST_DEV_UA_RETRIES;
|
||||
do {
|
||||
TRACE_DBG("%s", "Doing TEST_UNIT_READY");
|
||||
res = scsi_test_unit_ready(dev->scsi_dev,
|
||||
rc = scsi_test_unit_ready(dev->scsi_dev,
|
||||
SCST_GENERIC_RAID_TIMEOUT, RAID_RETRIES
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
|
||||
);
|
||||
#else
|
||||
, NULL);
|
||||
#endif
|
||||
TRACE_DBG("TEST_UNIT_READY done: %x", res);
|
||||
} while ((--retries > 0) && res);
|
||||
if (res) {
|
||||
res = -ENODEV;
|
||||
goto out;
|
||||
TRACE_DBG("TEST_UNIT_READY done: %x", rc);
|
||||
} while ((--retries > 0) && rc);
|
||||
|
||||
if (rc) {
|
||||
PRINT_WARNING("Unit not ready: %x", rc);
|
||||
/* Let's try not to be too smart and continue processing */
|
||||
}
|
||||
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
|
||||
@@ -157,7 +157,7 @@ module_exit(exit_scst_tape_driver);
|
||||
*************************************************************/
|
||||
static int tape_attach(struct scst_device *dev)
|
||||
{
|
||||
int res = 0;
|
||||
int res, rc;
|
||||
int retries;
|
||||
struct scsi_mode_data data;
|
||||
const int buffer_size = 512;
|
||||
@@ -181,6 +181,8 @@ static int tape_attach(struct scst_device *dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
params->block_size = TAPE_DEF_BLOCK_SIZE;
|
||||
|
||||
buffer = kmalloc(buffer_size, GFP_KERNEL);
|
||||
if (!buffer) {
|
||||
TRACE(TRACE_OUT_OF_MEM, "%s", "Memory allocation failure");
|
||||
@@ -191,39 +193,40 @@ static int tape_attach(struct scst_device *dev)
|
||||
retries = SCST_DEV_UA_RETRIES;
|
||||
do {
|
||||
TRACE_DBG("%s", "Doing TEST_UNIT_READY");
|
||||
res = scsi_test_unit_ready(dev->scsi_dev,
|
||||
rc = scsi_test_unit_ready(dev->scsi_dev,
|
||||
SCST_GENERIC_TAPE_SMALL_TIMEOUT, TAPE_RETRIES
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
|
||||
);
|
||||
#else
|
||||
, NULL);
|
||||
#endif
|
||||
TRACE_DBG("TEST_UNIT_READY done: %x", res);
|
||||
} while ((--retries > 0) && res);
|
||||
if (res) {
|
||||
res = -ENODEV;
|
||||
goto out;
|
||||
TRACE_DBG("TEST_UNIT_READY done: %x", rc);
|
||||
} while ((--retries > 0) && rc);
|
||||
|
||||
if (rc) {
|
||||
PRINT_WARNING("Unit not ready: %x", rc);
|
||||
/* Let's try not to be too smart and continue processing */
|
||||
goto obtain;
|
||||
}
|
||||
|
||||
TRACE_DBG("%s", "Doing MODE_SENSE");
|
||||
res = scsi_mode_sense(dev->scsi_dev,
|
||||
rc = scsi_mode_sense(dev->scsi_dev,
|
||||
((dev->scsi_dev->scsi_level <= SCSI_2) ?
|
||||
((dev->scsi_dev->lun << 5) & 0xe0) : 0),
|
||||
0 /* Mode Page 0 */,
|
||||
buffer, buffer_size,
|
||||
SCST_GENERIC_TAPE_SMALL_TIMEOUT, TAPE_RETRIES,
|
||||
&data, NULL);
|
||||
TRACE_DBG("MODE_SENSE done: %x", res);
|
||||
TRACE_DBG("MODE_SENSE done: %x", rc);
|
||||
|
||||
if (res == 0) {
|
||||
if (rc == 0) {
|
||||
int medium_type, mode, speed, density;
|
||||
if (buffer[3] == 8) {
|
||||
params->block_size = ((buffer[9] << 16) |
|
||||
(buffer[10] << 8) |
|
||||
(buffer[11] << 0));
|
||||
} else {
|
||||
} else
|
||||
params->block_size = TAPE_DEF_BLOCK_SIZE;
|
||||
}
|
||||
medium_type = buffer[1];
|
||||
mode = (buffer[2] & 0x70) >> 4;
|
||||
speed = buffer[2] & 0x0f;
|
||||
@@ -232,10 +235,12 @@ static int tape_attach(struct scst_device *dev)
|
||||
"speed 0x%02x dens 0x%02x", dev->scsi_dev->lun,
|
||||
params->block_size, medium_type, mode, speed, density);
|
||||
} else {
|
||||
PRINT_ERROR("MODE_SENSE failed: %x", rc);
|
||||
res = -ENODEV;
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
obtain:
|
||||
res = scst_obtain_device_parameters(dev);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Failed to obtain control parameters for device "
|
||||
|
||||
+182
-128
@@ -2353,7 +2353,7 @@ static struct iovec *vdisk_alloc_iv(struct scst_cmd *cmd,
|
||||
{
|
||||
int iv_count;
|
||||
|
||||
iv_count = scst_get_buf_count(cmd);
|
||||
iv_count = min_t(int, scst_get_buf_count(cmd), UIO_MAXIOV);
|
||||
if (iv_count > thr->iv_count) {
|
||||
kfree(thr->iv);
|
||||
/* It can't be called in atomic context */
|
||||
@@ -2382,6 +2382,7 @@ static void vdisk_exec_read(struct scst_cmd *cmd,
|
||||
struct file *fd = thr->fd;
|
||||
struct iovec *iv;
|
||||
int iv_count, i;
|
||||
bool finished = false;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -2392,70 +2393,96 @@ static void vdisk_exec_read(struct scst_cmd *cmd,
|
||||
if (iv == NULL)
|
||||
goto out;
|
||||
|
||||
iv_count = 0;
|
||||
full_len = 0;
|
||||
i = -1;
|
||||
length = scst_get_buf_first(cmd, (uint8_t __force **)&address);
|
||||
while (length > 0) {
|
||||
full_len += length;
|
||||
i++;
|
||||
iv_count++;
|
||||
iv[i].iov_base = address;
|
||||
iv[i].iov_len = length;
|
||||
length = scst_get_buf_next(cmd, (uint8_t __force **)&address);
|
||||
}
|
||||
if (unlikely(length < 0)) {
|
||||
PRINT_ERROR("scst_get_buf_() failed: %zd", length);
|
||||
PRINT_ERROR("scst_get_buf_first() failed: %zd", length);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_put;
|
||||
goto out;
|
||||
}
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
|
||||
TRACE_DBG("reading(iv_count %d, full_len %zd)", iv_count, full_len);
|
||||
/* SEEK */
|
||||
if (fd->f_op->llseek)
|
||||
err = fd->f_op->llseek(fd, loff, 0/*SEEK_SET*/);
|
||||
else
|
||||
err = default_llseek(fd, loff, 0/*SEEK_SET*/);
|
||||
if (err != loff) {
|
||||
PRINT_ERROR("lseek trouble %lld != %lld",
|
||||
(long long unsigned int)err,
|
||||
(long long unsigned int)loff);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_set_fs;
|
||||
}
|
||||
|
||||
/* READ */
|
||||
err = vfs_readv(fd, (struct iovec __force __user *)iv, iv_count,
|
||||
&fd->f_pos);
|
||||
|
||||
if ((err < 0) || (err < full_len)) {
|
||||
PRINT_ERROR("readv() returned %lld from %zd",
|
||||
(long long unsigned int)err,
|
||||
full_len);
|
||||
if (err == -EAGAIN)
|
||||
scst_set_busy(cmd);
|
||||
else {
|
||||
while (1) {
|
||||
iv_count = 0;
|
||||
full_len = 0;
|
||||
i = -1;
|
||||
while (length > 0) {
|
||||
full_len += length;
|
||||
i++;
|
||||
iv_count++;
|
||||
iv[i].iov_base = address;
|
||||
iv[i].iov_len = length;
|
||||
if (iv_count == UIO_MAXIOV)
|
||||
break;
|
||||
length = scst_get_buf_next(cmd,
|
||||
(uint8_t __force **)&address);
|
||||
}
|
||||
if (length == 0) {
|
||||
finished = true;
|
||||
if (unlikely(iv_count == 0))
|
||||
break;
|
||||
} else if (unlikely(length < 0)) {
|
||||
PRINT_ERROR("scst_get_buf_next() failed: %zd", length);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_read_error));
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_set_fs;
|
||||
}
|
||||
goto out_set_fs;
|
||||
}
|
||||
|
||||
out_set_fs:
|
||||
TRACE_DBG("(iv_count %d, full_len %zd)", iv_count, full_len);
|
||||
/* SEEK */
|
||||
if (fd->f_op->llseek)
|
||||
err = fd->f_op->llseek(fd, loff, 0/*SEEK_SET*/);
|
||||
else
|
||||
err = default_llseek(fd, loff, 0/*SEEK_SET*/);
|
||||
if (err != loff) {
|
||||
PRINT_ERROR("lseek trouble %lld != %lld",
|
||||
(long long unsigned int)err,
|
||||
(long long unsigned int)loff);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_set_fs;
|
||||
}
|
||||
|
||||
/* READ */
|
||||
err = vfs_readv(fd, (struct iovec __force __user *)iv, iv_count,
|
||||
&fd->f_pos);
|
||||
|
||||
if ((err < 0) || (err < full_len)) {
|
||||
PRINT_ERROR("readv() returned %lld from %zd",
|
||||
(long long unsigned int)err,
|
||||
full_len);
|
||||
if (err == -EAGAIN)
|
||||
scst_set_busy(cmd);
|
||||
else {
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_read_error));
|
||||
}
|
||||
goto out_set_fs;
|
||||
}
|
||||
|
||||
for (i = 0; i < iv_count; i++)
|
||||
scst_put_buf(cmd, (void __force *)(iv[i].iov_base));
|
||||
|
||||
if (finished)
|
||||
break;
|
||||
|
||||
loff += full_len;
|
||||
length = scst_get_buf_next(cmd, (uint8_t __force **)&address);
|
||||
};
|
||||
|
||||
set_fs(old_fs);
|
||||
|
||||
out_put:
|
||||
for (; i >= 0; i--)
|
||||
scst_put_buf(cmd, (void __force *)(iv[i].iov_base));
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
|
||||
out_set_fs:
|
||||
set_fs(old_fs);
|
||||
for (i = 0; i < iv_count; i++)
|
||||
scst_put_buf(cmd, (void __force *)(iv[i].iov_base));
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void vdisk_exec_write(struct scst_cmd *cmd,
|
||||
@@ -2463,13 +2490,14 @@ static void vdisk_exec_write(struct scst_cmd *cmd,
|
||||
{
|
||||
mm_segment_t old_fs;
|
||||
loff_t err;
|
||||
ssize_t length, full_len;
|
||||
ssize_t length, full_len, saved_full_len;
|
||||
uint8_t __user *address;
|
||||
struct scst_vdisk_dev *virt_dev =
|
||||
(struct scst_vdisk_dev *)cmd->dev->dh_priv;
|
||||
struct file *fd = thr->fd;
|
||||
struct iovec *iv, *eiv;
|
||||
int iv_count, eiv_count;
|
||||
int i, iv_count, eiv_count;
|
||||
bool finished = false;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -2480,102 +2508,128 @@ static void vdisk_exec_write(struct scst_cmd *cmd,
|
||||
if (iv == NULL)
|
||||
goto out;
|
||||
|
||||
iv_count = 0;
|
||||
full_len = 0;
|
||||
length = scst_get_buf_first(cmd, (uint8_t __force **)&address);
|
||||
while (length > 0) {
|
||||
full_len += length;
|
||||
iv[iv_count].iov_base = address;
|
||||
iv[iv_count].iov_len = length;
|
||||
iv_count++;
|
||||
length = scst_get_buf_next(cmd, (uint8_t __force **)&address);
|
||||
}
|
||||
if (unlikely(length < 0)) {
|
||||
PRINT_ERROR("scst_get_buf_() failed: %zd", length);
|
||||
PRINT_ERROR("scst_get_buf_first() failed: %zd", length);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_put;
|
||||
goto out;
|
||||
}
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
|
||||
eiv = iv;
|
||||
eiv_count = iv_count;
|
||||
restart:
|
||||
TRACE_DBG("writing(eiv_count %d, full_len %zd)", eiv_count, full_len);
|
||||
|
||||
/* SEEK */
|
||||
if (fd->f_op->llseek)
|
||||
err = fd->f_op->llseek(fd, loff, 0 /*SEEK_SET */);
|
||||
else
|
||||
err = default_llseek(fd, loff, 0 /*SEEK_SET */);
|
||||
if (err != loff) {
|
||||
PRINT_ERROR("lseek trouble %lld != %lld",
|
||||
(long long unsigned int)err,
|
||||
(long long unsigned int)loff);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_set_fs;
|
||||
}
|
||||
|
||||
/* WRITE */
|
||||
err = vfs_writev(fd, (struct iovec __force __user *)eiv, eiv_count,
|
||||
&fd->f_pos);
|
||||
|
||||
if (err < 0) {
|
||||
PRINT_ERROR("write() returned %lld from %zd",
|
||||
(long long unsigned int)err,
|
||||
full_len);
|
||||
if (err == -EAGAIN)
|
||||
scst_set_busy(cmd);
|
||||
else {
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_write_error));
|
||||
}
|
||||
goto out_set_fs;
|
||||
} else if (err < full_len) {
|
||||
/*
|
||||
* Probably that's wrong, but sometimes write() returns
|
||||
* value less, than requested. Let's restart.
|
||||
*/
|
||||
int i, e = eiv_count;
|
||||
TRACE_MGMT_DBG("write() returned %d from %zd "
|
||||
"(iv_count=%d)", (int)err, full_len,
|
||||
eiv_count);
|
||||
if (err == 0) {
|
||||
PRINT_INFO("Suspicious: write() returned 0 from "
|
||||
"%zd (iv_count=%d)", full_len, eiv_count);
|
||||
}
|
||||
full_len -= err;
|
||||
for (i = 0; i < e; i++) {
|
||||
if ((long long)eiv->iov_len < err) {
|
||||
err -= eiv->iov_len;
|
||||
eiv++;
|
||||
eiv_count--;
|
||||
} else {
|
||||
eiv->iov_base =
|
||||
(uint8_t __force __user *)eiv->iov_base +
|
||||
err;
|
||||
eiv->iov_len -= err;
|
||||
while (1) {
|
||||
iv_count = 0;
|
||||
full_len = 0;
|
||||
i = -1;
|
||||
while (length > 0) {
|
||||
full_len += length;
|
||||
i++;
|
||||
iv_count++;
|
||||
iv[i].iov_base = address;
|
||||
iv[i].iov_len = length;
|
||||
if (iv_count == UIO_MAXIOV)
|
||||
break;
|
||||
}
|
||||
length = scst_get_buf_next(cmd,
|
||||
(uint8_t __force **)&address);
|
||||
}
|
||||
goto restart;
|
||||
if (length == 0) {
|
||||
finished = true;
|
||||
if (unlikely(iv_count == 0))
|
||||
break;
|
||||
} else if (unlikely(length < 0)) {
|
||||
PRINT_ERROR("scst_get_buf_next() failed: %zd", length);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_set_fs;
|
||||
}
|
||||
|
||||
saved_full_len = full_len;
|
||||
eiv = iv;
|
||||
eiv_count = iv_count;
|
||||
restart:
|
||||
TRACE_DBG("writing(eiv_count %d, full_len %zd)", eiv_count, full_len);
|
||||
|
||||
/* SEEK */
|
||||
if (fd->f_op->llseek)
|
||||
err = fd->f_op->llseek(fd, loff, 0 /*SEEK_SET */);
|
||||
else
|
||||
err = default_llseek(fd, loff, 0 /*SEEK_SET */);
|
||||
if (err != loff) {
|
||||
PRINT_ERROR("lseek trouble %lld != %lld",
|
||||
(long long unsigned int)err,
|
||||
(long long unsigned int)loff);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
goto out_set_fs;
|
||||
}
|
||||
|
||||
/* WRITE */
|
||||
err = vfs_writev(fd, (struct iovec __force __user *)eiv, eiv_count,
|
||||
&fd->f_pos);
|
||||
|
||||
if (err < 0) {
|
||||
PRINT_ERROR("write() returned %lld from %zd",
|
||||
(long long unsigned int)err,
|
||||
full_len);
|
||||
if (err == -EAGAIN)
|
||||
scst_set_busy(cmd);
|
||||
else {
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_write_error));
|
||||
}
|
||||
goto out_set_fs;
|
||||
} else if (err < full_len) {
|
||||
/*
|
||||
* Probably that's wrong, but sometimes write() returns
|
||||
* value less, than requested. Let's restart.
|
||||
*/
|
||||
int i, e = eiv_count;
|
||||
TRACE_MGMT_DBG("write() returned %d from %zd "
|
||||
"(iv_count=%d)", (int)err, full_len,
|
||||
eiv_count);
|
||||
if (err == 0) {
|
||||
PRINT_INFO("Suspicious: write() returned 0 from "
|
||||
"%zd (iv_count=%d)", full_len, eiv_count);
|
||||
}
|
||||
full_len -= err;
|
||||
for (i = 0; i < e; i++) {
|
||||
if ((long long)eiv->iov_len < err) {
|
||||
err -= eiv->iov_len;
|
||||
eiv++;
|
||||
eiv_count--;
|
||||
} else {
|
||||
eiv->iov_base =
|
||||
(uint8_t __force __user *)eiv->iov_base + err;
|
||||
eiv->iov_len -= err;
|
||||
break;
|
||||
}
|
||||
}
|
||||
goto restart;
|
||||
}
|
||||
|
||||
for (i = 0; i < iv_count; i++)
|
||||
scst_put_buf(cmd, (void __force *)(iv[i].iov_base));
|
||||
|
||||
if (finished)
|
||||
break;
|
||||
|
||||
loff += saved_full_len;
|
||||
length = scst_get_buf_next(cmd, (uint8_t __force **)&address);
|
||||
}
|
||||
|
||||
out_set_fs:
|
||||
set_fs(old_fs);
|
||||
|
||||
out_put:
|
||||
while (iv_count > 0) {
|
||||
scst_put_buf(cmd, (void __force *)(iv[iv_count-1].iov_base));
|
||||
iv_count--;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
|
||||
out_set_fs:
|
||||
set_fs(old_fs);
|
||||
for (i = 0; i < iv_count; i++)
|
||||
scst_put_buf(cmd, (void __force *)(iv[i].iov_base));
|
||||
goto out;
|
||||
}
|
||||
|
||||
struct scst_blockio_work {
|
||||
|
||||
Reference in New Issue
Block a user