- 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:
Vladislav Bolkhovitin
2010-03-02 17:32:23 +00:00
parent 6463e79a7c
commit eba1edba31
8 changed files with 256 additions and 192 deletions
+11 -7
View File
@@ -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);
+8 -7
View File
@@ -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);
+12 -13
View File
@@ -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);
+10 -11
View File
@@ -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);
+8 -7
View File
@@ -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);
+8 -7
View File
@@ -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);
+17 -12
View File
@@ -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
View File
@@ -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 {