@@ -300,11 +300,28 @@ static void iblock_complete_cmd(struct se_cmd *cmd)
if (!atomic_dec_and_test(&ibr->pending))
return;
-
- if (atomic_read(&ibr->ib_bio_err_cnt))
- status = SAM_STAT_CHECK_CONDITION;
- else
+ /*
+ * Propigate use these two bio completion values from raw block
+ * drivers to signal up BUSY and TASK_SET_FULL status to the
+ * host side initiator. The latter for Linux/iSCSI initiators
+ * means the Linux/SCSI LLD will begin to reduce it's internal
+ * per session queue_depth.
+ */
+ if (atomic_read(&ibr->ib_bio_err_cnt)) {
+ switch (ibr->ib_bio_retry) {
+ case -EAGAIN:
+ status = SAM_STAT_BUSY;
+ break;
+ case -ENOMEM:
+ status = SAM_STAT_TASK_SET_FULL;
+ break;
+ default:
+ status = SAM_STAT_CHECK_CONDITION;
+ break;
+ }
+ } else {
status = SAM_STAT_GOOD;
+ }
target_complete_cmd(cmd, status);
kfree(ibr);
@@ -316,7 +333,15 @@ static void iblock_bio_done(struct bio *bio)
struct iblock_req *ibr = cmd->priv;
if (bio->bi_error) {
- pr_err("bio error: %p, err: %d\n", bio, bio->bi_error);
+ pr_debug_ratelimited("test_bit(BIO_UPTODATE) failed for bio: %p,"
+ " err: %d\n", bio, bio->bi_error);
+ /*
+ * Save the retryable status provided and translate into
+ * SAM status in iblock_complete_cmd().
+ */
+ if (bio->bi_error == -EAGAIN || bio->bi_error == -ENOMEM) {
+ ibr->ib_bio_retry = bio->bi_error;
+ }
/*
* Bump the ib_bio_err_cnt and release bio.
*/
@@ -655,8 +680,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
u32 sg_num = sgl_nents;
sector_t block_lba;
unsigned bio_cnt;
- int rw = 0;
- int i;
+ int i, rw = 0;
if (data_direction == DMA_TO_DEVICE) {
struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
@@ -9,6 +9,7 @@
struct iblock_req {
atomic_t pending;
atomic_t ib_bio_err_cnt;
+ int ib_bio_retry;
} ____cacheline_aligned;
#define IBDF_HAS_UDEV_PATH 0x01
@@ -732,11 +732,20 @@ static unsigned char *transport_get_sense_buffer(struct se_cmd *cmd)
void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
{
struct se_device *dev = cmd->se_dev;
- int success = scsi_status == GOOD;
+ int success;
unsigned long flags;
cmd->scsi_status = scsi_status;
-
+ switch (cmd->scsi_status) {
+ case SAM_STAT_GOOD:
+ case SAM_STAT_BUSY:
+ case SAM_STAT_TASK_SET_FULL:
+ success = 1;
+ break;
+ default:
+ success = 0;
+ break;
+ }
spin_lock_irqsave(&cmd->t_state_lock, flags);
cmd->transport_state &= ~CMD_T_BUSY;