diff options
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_cdb.c | 5 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 123 |
2 files changed, 25 insertions, 103 deletions
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 30a67707036f..f6f6059f7f74 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -432,6 +432,7 @@ static int target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; + u32 max_sectors; int have_tp = 0; /* @@ -456,7 +457,9 @@ target_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) /* * Set MAXIMUM TRANSFER LENGTH */ - put_unaligned_be32(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, &buf[8]); + max_sectors = min(dev->se_sub_dev->se_dev_attrib.fabric_max_sectors, + dev->se_sub_dev->se_dev_attrib.max_sectors); + put_unaligned_be32(max_sectors, &buf[8]); /* * Set OPTIMAL TRANSFER LENGTH diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 25c67c800f3d..db05c75864e0 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3183,7 +3183,8 @@ static int transport_generic_cmd_sequencer( } if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB && - sectors > dev->se_sub_dev->se_dev_attrib.fabric_max_sectors) { + (sectors > dev->se_sub_dev->se_dev_attrib.fabric_max_sectors || + sectors > dev->se_sub_dev->se_dev_attrib.max_sectors)) { printk_ratelimited(KERN_ERR "SCSI OP %02xh with too big sectors %u\n", cdb[0], sectors); goto out_invalid_cdb_field; @@ -3446,12 +3447,7 @@ static void transport_free_dev_tasks(struct se_cmd *cmd) while (!list_empty(&dispose_list)) { task = list_first_entry(&dispose_list, struct se_task, t_list); - if (task->task_sg != cmd->t_data_sg && - task->task_sg != cmd->t_bidi_data_sg) - kfree(task->task_sg); - list_del(&task->t_list); - cmd->se_dev->transport->free_task(task); } } @@ -3782,112 +3778,35 @@ transport_allocate_data_tasks(struct se_cmd *cmd, struct scatterlist *cmd_sg, unsigned int sgl_nents) { struct se_device *dev = cmd->se_dev; - int task_count, i; - unsigned long long lba; - sector_t sectors, dev_max_sectors; - u32 sector_size; + struct se_dev_attrib *attr = &dev->se_sub_dev->se_dev_attrib; + sector_t sectors; + struct se_task *task; + unsigned long flags; if (transport_cmd_get_valid_sectors(cmd) < 0) return -EINVAL; - dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors; - sector_size = dev->se_sub_dev->se_dev_attrib.block_size; - - WARN_ON(cmd->data_length % sector_size); - - lba = cmd->t_task_lba; - sectors = DIV_ROUND_UP(cmd->data_length, sector_size); - task_count = DIV_ROUND_UP_SECTOR_T(sectors, dev_max_sectors); - - /* - * If we need just a single task reuse the SG list in the command - * and avoid a lot of work. - */ - if (task_count == 1) { - struct se_task *task; - unsigned long flags; - - task = transport_generic_get_task(cmd, data_direction); - if (!task) - return -ENOMEM; - - task->task_sg = cmd_sg; - task->task_sg_nents = sgl_nents; - - task->task_lba = lba; - task->task_sectors = sectors; - task->task_size = task->task_sectors * sector_size; - - spin_lock_irqsave(&cmd->t_state_lock, flags); - list_add_tail(&task->t_list, &cmd->t_task_list); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - return task_count; - } - - for (i = 0; i < task_count; i++) { - struct se_task *task; - unsigned int task_size, task_sg_nents_padded; - struct scatterlist *sg; - unsigned long flags; - int count; - - task = transport_generic_get_task(cmd, data_direction); - if (!task) - return -ENOMEM; - - task->task_lba = lba; - task->task_sectors = min(sectors, dev_max_sectors); - task->task_size = task->task_sectors * sector_size; + sectors = DIV_ROUND_UP(cmd->data_length, attr->block_size); - /* - * This now assumes that passed sg_ents are in PAGE_SIZE chunks - * in order to calculate the number per task SGL entries - */ - task->task_sg_nents = DIV_ROUND_UP(task->task_size, PAGE_SIZE); - /* - * Check if the fabric module driver is requesting that all - * struct se_task->task_sg[] be chained together.. If so, - * then allocate an extra padding SG entry for linking and - * marking the end of the chained SGL for every task except - * the last one for (task_count > 1) operation, or skipping - * the extra padding for the (task_count == 1) case. - */ - if (cmd->se_tfo->task_sg_chaining && (i < (task_count - 1))) { - task_sg_nents_padded = (task->task_sg_nents + 1); - } else - task_sg_nents_padded = task->task_sg_nents; - - task->task_sg = kmalloc(sizeof(struct scatterlist) * - task_sg_nents_padded, GFP_KERNEL); - if (!task->task_sg) { - cmd->se_dev->transport->free_task(task); - return -ENOMEM; - } - - sg_init_table(task->task_sg, task_sg_nents_padded); - - task_size = task->task_size; + BUG_ON(cmd->data_length % attr->block_size); + BUG_ON(sectors > attr->max_sectors); - /* Build new sgl, only up to task_size */ - for_each_sg(task->task_sg, sg, task->task_sg_nents, count) { - if (cmd_sg->length > task_size) - break; + task = transport_generic_get_task(cmd, data_direction); + if (!task) + return -ENOMEM; - *sg = *cmd_sg; - task_size -= cmd_sg->length; - cmd_sg = sg_next(cmd_sg); - } + task->task_sg = cmd_sg; + task->task_sg_nents = sgl_nents; + task->task_size = cmd->data_length; - lba += task->task_sectors; - sectors -= task->task_sectors; + task->task_lba = cmd->t_task_lba; + task->task_sectors = sectors; - spin_lock_irqsave(&cmd->t_state_lock, flags); - list_add_tail(&task->t_list, &cmd->t_task_list); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - } + spin_lock_irqsave(&cmd->t_state_lock, flags); + list_add_tail(&task->t_list, &cmd->t_task_list); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return task_count; + return 1; } static int |