Skip to content

Commit

Permalink
Revert "libata: switch to dynamic allocation instead of ata_scsi_rbuf"
Browse files Browse the repository at this point in the history
This reverts commit a234f73.

The commit tried to get rid of the shared global SCSI response buffer.
Unfortunately, it added blocking allocation to atomic path.  Revert it
for now.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
  • Loading branch information
Tejun Heo committed Jan 18, 2017
1 parent d7969f5 commit d4ae1e2
Showing 1 changed file with 86 additions and 36 deletions.
122 changes: 86 additions & 36 deletions drivers/ata/libata-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@

#define ATA_SCSI_RBUF_SIZE 4096

static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE];

typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);

static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
Expand Down Expand Up @@ -2053,6 +2056,53 @@ struct ata_scsi_args {
struct scsi_cmnd *cmd;
};

/**
* ata_scsi_rbuf_get - Map response buffer.
* @cmd: SCSI command containing buffer to be mapped.
* @flags: unsigned long variable to store irq enable status
* @copy_in: copy in from user buffer
*
* Prepare buffer for simulated SCSI commands.
*
* LOCKING:
* spin_lock_irqsave(ata_scsi_rbuf_lock) on success
*
* RETURNS:
* Pointer to response buffer.
*/
static void *ata_scsi_rbuf_get(struct scsi_cmnd *cmd, bool copy_in,
unsigned long *flags)
{
spin_lock_irqsave(&ata_scsi_rbuf_lock, *flags);

memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE);
if (copy_in)
sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE);
return ata_scsi_rbuf;
}

/**
* ata_scsi_rbuf_put - Unmap response buffer.
* @cmd: SCSI command containing buffer to be unmapped.
* @copy_out: copy out result
* @flags: @flags passed to ata_scsi_rbuf_get()
*
* Returns rbuf buffer. The result is copied to @cmd's buffer if
* @copy_back is true.
*
* LOCKING:
* Unlocks ata_scsi_rbuf_lock.
*/
static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out,
unsigned long *flags)
{
if (copy_out)
sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE);
spin_unlock_irqrestore(&ata_scsi_rbuf_lock, *flags);
}

/**
* ata_scsi_rbuf_fill - wrapper for SCSI command simulators
* @args: device IDENTIFY data / SCSI command of interest.
Expand All @@ -2071,22 +2121,17 @@ struct ata_scsi_args {
static void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf))
{
u8 *rbuf;
unsigned int rc;
struct scsi_cmnd *cmd = args->cmd;
u8 *buf;
unsigned long flags;

buf = kzalloc(ATA_SCSI_RBUF_SIZE, GFP_NOIO);
if (!buf) {
ata_scsi_set_sense(args->dev, cmd, NOT_READY, 0x08, 0);
return;
}
rbuf = ata_scsi_rbuf_get(cmd, false, &flags);
rc = actor(args, rbuf);
ata_scsi_rbuf_put(cmd, rc == 0, &flags);

if (actor(args, buf) == 0) {
sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
buf, ATA_SCSI_RBUF_SIZE);
if (rc == 0)
cmd->result = SAM_STAT_GOOD;
}

kfree(buf);
}

/**
Expand Down Expand Up @@ -3318,17 +3363,24 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
*
* Return: Number of bytes copied into sglist.
*/
static ssize_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax,
static size_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax,
u64 sector, u32 count)
{
struct scsi_device *sdp = cmd->device;
size_t len = sdp->sector_size;
size_t r;
__le64 *buf;
u32 i = 0;
unsigned long flags;

buf = kzalloc(cmd->device->sector_size, GFP_NOFS);
if (!buf)
return -ENOMEM;
WARN_ON(len > ATA_SCSI_RBUF_SIZE);

if (len > ATA_SCSI_RBUF_SIZE)
len = ATA_SCSI_RBUF_SIZE;

spin_lock_irqsave(&ata_scsi_rbuf_lock, flags);
buf = ((void *)ata_scsi_rbuf);
memset(buf, 0, len);
while (i < trmax) {
u64 entry = sector |
((u64)(count > 0xffff ? 0xffff : count) << 48);
Expand All @@ -3338,9 +3390,9 @@ static ssize_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax,
count -= 0xffff;
sector += 0xffff;
}
r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf,
cmd->device->sector_size);
kfree(buf);
r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, len);
spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags);

return r;
}

Expand All @@ -3356,25 +3408,31 @@ static ssize_t ata_format_dsm_trim_descr(struct scsi_cmnd *cmd, u32 trmax,
*
* Return: Number of bytes copied into sglist.
*/
static ssize_t ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba,
u64 num)
static size_t ata_format_sct_write_same(struct scsi_cmnd *cmd, u64 lba, u64 num)
{
struct scsi_device *sdp = cmd->device;
size_t len = sdp->sector_size;
size_t r;
u16 *buf;
unsigned long flags;

buf = kzalloc(cmd->device->sector_size, GFP_NOIO);
if (!buf)
return -ENOMEM;
spin_lock_irqsave(&ata_scsi_rbuf_lock, flags);
buf = ((void *)ata_scsi_rbuf);

put_unaligned_le16(0x0002, &buf[0]); /* SCT_ACT_WRITE_SAME */
put_unaligned_le16(0x0101, &buf[1]); /* WRITE PTRN FG */
put_unaligned_le64(lba, &buf[2]);
put_unaligned_le64(num, &buf[6]);
put_unaligned_le32(0u, &buf[10]); /* pattern */

r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf,
cmd->device->sector_size);
kfree(buf);
WARN_ON(len > ATA_SCSI_RBUF_SIZE);

if (len > ATA_SCSI_RBUF_SIZE)
len = ATA_SCSI_RBUF_SIZE;

r = sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), buf, len);
spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags);

return r;
}

Expand All @@ -3399,7 +3457,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
u64 block;
u32 n_block;
const u32 trmax = len >> 3;
ssize_t size;
u32 size;
u16 fp;
u8 bp = 0xff;
u8 unmap = cdb[1] & 0x8;
Expand Down Expand Up @@ -3450,8 +3508,6 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
*/
if (unmap) {
size = ata_format_dsm_trim_descr(scmd, trmax, block, n_block);
if (size < 0)
goto comm_fail;
if (size != len)
goto invalid_param_len;

Expand All @@ -3475,8 +3531,6 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
}
} else {
size = ata_format_sct_write_same(scmd, block, n_block);
if (size < 0)
goto comm_fail;
if (size != len)
goto invalid_param_len;

Expand Down Expand Up @@ -3515,10 +3569,6 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
/* "Invalid command operation code" */
ata_scsi_set_sense(dev, scmd, ILLEGAL_REQUEST, 0x20, 0x0);
return 1;
comm_fail:
/* "Logical unit communication failure" */
ata_scsi_set_sense(dev, scmd, NOT_READY, 0x08, 0);
return 1;
}

/**
Expand Down

0 comments on commit d4ae1e2

Please sign in to comment.