![Jean Delvare](/assets/img/avatar_default.png)
I noticed that many source files include <linux/pci.h> while they do not appear to need it. Here is an attempt to clean it all up. In order to find all possibly affected files, I searched for all files including <linux/pci.h> but without any other occurence of "pci" or "PCI". I removed the include statement from all of these, then I compiled an allmodconfig kernel on both i386 and x86_64 and fixed the false positives manually. My tests covered 66% of the affected files, so there could be false positives remaining. Untested files are: arch/alpha/kernel/err_common.c arch/alpha/kernel/err_ev6.c arch/alpha/kernel/err_ev7.c arch/ia64/sn/kernel/huberror.c arch/ia64/sn/kernel/xpnet.c arch/m68knommu/kernel/dma.c arch/mips/lib/iomap.c arch/powerpc/platforms/pseries/ras.c arch/ppc/8260_io/enet.c arch/ppc/8260_io/fcc_enet.c arch/ppc/8xx_io/enet.c arch/ppc/syslib/ppc4xx_sgdma.c arch/sh64/mach-cayman/iomap.c arch/xtensa/kernel/xtensa_ksyms.c arch/xtensa/platform-iss/setup.c drivers/i2c/busses/i2c-at91.c drivers/i2c/busses/i2c-mpc.c drivers/media/video/saa711x.c drivers/misc/hdpuftrs/hdpu_cpustate.c drivers/misc/hdpuftrs/hdpu_nexus.c drivers/net/au1000_eth.c drivers/net/fec_8xx/fec_main.c drivers/net/fec_8xx/fec_mii.c drivers/net/fs_enet/fs_enet-main.c drivers/net/fs_enet/mac-fcc.c drivers/net/fs_enet/mac-fec.c drivers/net/fs_enet/mac-scc.c drivers/net/fs_enet/mii-bitbang.c drivers/net/fs_enet/mii-fec.c drivers/net/ibm_emac/ibm_emac_core.c drivers/net/lasi_82596.c drivers/parisc/hppb.c drivers/sbus/sbus.c drivers/video/g364fb.c drivers/video/platinumfb.c drivers/video/stifb.c drivers/video/valkyriefb.c include/asm-arm/arch-ixp4xx/dma.h sound/oss/au1550_ac97.c I would welcome test reports for these files. I am fine with removing the untested files from the patch if the general opinion is that these changes aren't safe. The tested part would still be nice to have. Note that this patch depends on another header fixup patch I submitted to LKML yesterday: [PATCH] scatterlist.h needs types.h http://lkml.org/lkml/2007/3/01/141 Signed-off-by: Jean Delvare <khali@linux-fr.org> Cc: Badari Pulavarty <pbadari@us.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
441 lines
10 KiB
C
441 lines
10 KiB
C
/*
|
|
* SCSI RDAM Protocol lib functions
|
|
*
|
|
* Copyright (C) 2006 FUJITA Tomonori <tomof@acm.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA
|
|
*/
|
|
#include <linux/err.h>
|
|
#include <linux/kfifo.h>
|
|
#include <linux/scatterlist.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <scsi/scsi.h>
|
|
#include <scsi/scsi_cmnd.h>
|
|
#include <scsi/scsi_tcq.h>
|
|
#include <scsi/scsi_tgt.h>
|
|
#include <scsi/srp.h>
|
|
#include <scsi/libsrp.h>
|
|
|
|
enum srp_task_attributes {
|
|
SRP_SIMPLE_TASK = 0,
|
|
SRP_HEAD_TASK = 1,
|
|
SRP_ORDERED_TASK = 2,
|
|
SRP_ACA_TASK = 4
|
|
};
|
|
|
|
/* tmp - will replace with SCSI logging stuff */
|
|
#define eprintk(fmt, args...) \
|
|
do { \
|
|
printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args); \
|
|
} while (0)
|
|
/* #define dprintk eprintk */
|
|
#define dprintk(fmt, args...)
|
|
|
|
static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
|
|
struct srp_buf **ring)
|
|
{
|
|
int i;
|
|
struct iu_entry *iue;
|
|
|
|
q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL);
|
|
if (!q->pool)
|
|
return -ENOMEM;
|
|
q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL);
|
|
if (!q->items)
|
|
goto free_pool;
|
|
|
|
spin_lock_init(&q->lock);
|
|
q->queue = kfifo_init((void *) q->pool, max * sizeof(void *),
|
|
GFP_KERNEL, &q->lock);
|
|
if (IS_ERR(q->queue))
|
|
goto free_item;
|
|
|
|
for (i = 0, iue = q->items; i < max; i++) {
|
|
__kfifo_put(q->queue, (void *) &iue, sizeof(void *));
|
|
iue->sbuf = ring[i];
|
|
iue++;
|
|
}
|
|
return 0;
|
|
|
|
free_item:
|
|
kfree(q->items);
|
|
free_pool:
|
|
kfree(q->pool);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
static void srp_iu_pool_free(struct srp_queue *q)
|
|
{
|
|
kfree(q->items);
|
|
kfree(q->pool);
|
|
}
|
|
|
|
static struct srp_buf **srp_ring_alloc(struct device *dev,
|
|
size_t max, size_t size)
|
|
{
|
|
int i;
|
|
struct srp_buf **ring;
|
|
|
|
ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL);
|
|
if (!ring)
|
|
return NULL;
|
|
|
|
for (i = 0; i < max; i++) {
|
|
ring[i] = kzalloc(sizeof(struct srp_buf), GFP_KERNEL);
|
|
if (!ring[i])
|
|
goto out;
|
|
ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma,
|
|
GFP_KERNEL);
|
|
if (!ring[i]->buf)
|
|
goto out;
|
|
}
|
|
return ring;
|
|
|
|
out:
|
|
for (i = 0; i < max && ring[i]; i++) {
|
|
if (ring[i]->buf)
|
|
dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
|
|
kfree(ring[i]);
|
|
}
|
|
kfree(ring);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max,
|
|
size_t size)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < max; i++) {
|
|
dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma);
|
|
kfree(ring[i]);
|
|
}
|
|
}
|
|
|
|
int srp_target_alloc(struct srp_target *target, struct device *dev,
|
|
size_t nr, size_t iu_size)
|
|
{
|
|
int err;
|
|
|
|
spin_lock_init(&target->lock);
|
|
INIT_LIST_HEAD(&target->cmd_queue);
|
|
|
|
target->dev = dev;
|
|
target->dev->driver_data = target;
|
|
|
|
target->srp_iu_size = iu_size;
|
|
target->rx_ring_size = nr;
|
|
target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size);
|
|
if (!target->rx_ring)
|
|
return -ENOMEM;
|
|
err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring);
|
|
if (err)
|
|
goto free_ring;
|
|
|
|
return 0;
|
|
|
|
free_ring:
|
|
srp_ring_free(target->dev, target->rx_ring, nr, iu_size);
|
|
return -ENOMEM;
|
|
}
|
|
EXPORT_SYMBOL_GPL(srp_target_alloc);
|
|
|
|
void srp_target_free(struct srp_target *target)
|
|
{
|
|
srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size,
|
|
target->srp_iu_size);
|
|
srp_iu_pool_free(&target->iu_queue);
|
|
}
|
|
EXPORT_SYMBOL_GPL(srp_target_free);
|
|
|
|
struct iu_entry *srp_iu_get(struct srp_target *target)
|
|
{
|
|
struct iu_entry *iue = NULL;
|
|
|
|
kfifo_get(target->iu_queue.queue, (void *) &iue, sizeof(void *));
|
|
if (!iue)
|
|
return iue;
|
|
iue->target = target;
|
|
INIT_LIST_HEAD(&iue->ilist);
|
|
iue->flags = 0;
|
|
return iue;
|
|
}
|
|
EXPORT_SYMBOL_GPL(srp_iu_get);
|
|
|
|
void srp_iu_put(struct iu_entry *iue)
|
|
{
|
|
kfifo_put(iue->target->iu_queue.queue, (void *) &iue, sizeof(void *));
|
|
}
|
|
EXPORT_SYMBOL_GPL(srp_iu_put);
|
|
|
|
static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
|
|
enum dma_data_direction dir, srp_rdma_t rdma_io,
|
|
int dma_map, int ext_desc)
|
|
{
|
|
struct iu_entry *iue = NULL;
|
|
struct scatterlist *sg = NULL;
|
|
int err, nsg = 0, len;
|
|
|
|
if (dma_map) {
|
|
iue = (struct iu_entry *) sc->SCp.ptr;
|
|
sg = sc->request_buffer;
|
|
|
|
dprintk("%p %u %u %d\n", iue, sc->request_bufflen,
|
|
md->len, sc->use_sg);
|
|
|
|
nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg,
|
|
DMA_BIDIRECTIONAL);
|
|
if (!nsg) {
|
|
printk("fail to map %p %d\n", iue, sc->use_sg);
|
|
return 0;
|
|
}
|
|
len = min(sc->request_bufflen, md->len);
|
|
} else
|
|
len = md->len;
|
|
|
|
err = rdma_io(sc, sg, nsg, md, 1, dir, len);
|
|
|
|
if (dma_map)
|
|
dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
|
|
struct srp_indirect_buf *id,
|
|
enum dma_data_direction dir, srp_rdma_t rdma_io,
|
|
int dma_map, int ext_desc)
|
|
{
|
|
struct iu_entry *iue = NULL;
|
|
struct srp_direct_buf *md = NULL;
|
|
struct scatterlist dummy, *sg = NULL;
|
|
dma_addr_t token = 0;
|
|
long err;
|
|
unsigned int done = 0;
|
|
int nmd, nsg = 0, len;
|
|
|
|
if (dma_map || ext_desc) {
|
|
iue = (struct iu_entry *) sc->SCp.ptr;
|
|
sg = sc->request_buffer;
|
|
|
|
dprintk("%p %u %u %d %d\n",
|
|
iue, sc->request_bufflen, id->len,
|
|
cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
|
|
}
|
|
|
|
nmd = id->table_desc.len / sizeof(struct srp_direct_buf);
|
|
|
|
if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) ||
|
|
(dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) {
|
|
md = &id->desc_list[0];
|
|
goto rdma;
|
|
}
|
|
|
|
if (ext_desc && dma_map) {
|
|
md = dma_alloc_coherent(iue->target->dev, id->table_desc.len,
|
|
&token, GFP_KERNEL);
|
|
if (!md) {
|
|
eprintk("Can't get dma memory %u\n", id->table_desc.len);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
sg_init_one(&dummy, md, id->table_desc.len);
|
|
sg_dma_address(&dummy) = token;
|
|
err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
|
|
id->table_desc.len);
|
|
if (err < 0) {
|
|
eprintk("Error copying indirect table %ld\n", err);
|
|
goto free_mem;
|
|
}
|
|
} else {
|
|
eprintk("This command uses external indirect buffer\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
rdma:
|
|
if (dma_map) {
|
|
nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
|
|
if (!nsg) {
|
|
eprintk("fail to map %p %d\n", iue, sc->use_sg);
|
|
goto free_mem;
|
|
}
|
|
len = min(sc->request_bufflen, id->len);
|
|
} else
|
|
len = id->len;
|
|
|
|
err = rdma_io(sc, sg, nsg, md, nmd, dir, len);
|
|
|
|
if (dma_map)
|
|
dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL);
|
|
|
|
free_mem:
|
|
if (token && dma_map)
|
|
dma_free_coherent(iue->target->dev, id->table_desc.len, md, token);
|
|
|
|
return done;
|
|
}
|
|
|
|
static int data_out_desc_size(struct srp_cmd *cmd)
|
|
{
|
|
int size = 0;
|
|
u8 fmt = cmd->buf_fmt >> 4;
|
|
|
|
switch (fmt) {
|
|
case SRP_NO_DATA_DESC:
|
|
break;
|
|
case SRP_DATA_DESC_DIRECT:
|
|
size = sizeof(struct srp_direct_buf);
|
|
break;
|
|
case SRP_DATA_DESC_INDIRECT:
|
|
size = sizeof(struct srp_indirect_buf) +
|
|
sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
|
|
break;
|
|
default:
|
|
eprintk("client error. Invalid data_out_format %x\n", fmt);
|
|
break;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
/*
|
|
* TODO: this can be called multiple times for a single command if it
|
|
* has very long data.
|
|
*/
|
|
int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
|
|
srp_rdma_t rdma_io, int dma_map, int ext_desc)
|
|
{
|
|
struct srp_direct_buf *md;
|
|
struct srp_indirect_buf *id;
|
|
enum dma_data_direction dir;
|
|
int offset, err = 0;
|
|
u8 format;
|
|
|
|
offset = cmd->add_cdb_len * 4;
|
|
|
|
dir = srp_cmd_direction(cmd);
|
|
if (dir == DMA_FROM_DEVICE)
|
|
offset += data_out_desc_size(cmd);
|
|
|
|
if (dir == DMA_TO_DEVICE)
|
|
format = cmd->buf_fmt >> 4;
|
|
else
|
|
format = cmd->buf_fmt & ((1U << 4) - 1);
|
|
|
|
switch (format) {
|
|
case SRP_NO_DATA_DESC:
|
|
break;
|
|
case SRP_DATA_DESC_DIRECT:
|
|
md = (struct srp_direct_buf *)
|
|
(cmd->add_data + offset);
|
|
err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc);
|
|
break;
|
|
case SRP_DATA_DESC_INDIRECT:
|
|
id = (struct srp_indirect_buf *)
|
|
(cmd->add_data + offset);
|
|
err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map,
|
|
ext_desc);
|
|
break;
|
|
default:
|
|
eprintk("Unknown format %d %x\n", dir, format);
|
|
break;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(srp_transfer_data);
|
|
|
|
static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
|
|
{
|
|
struct srp_direct_buf *md;
|
|
struct srp_indirect_buf *id;
|
|
int len = 0, offset = cmd->add_cdb_len * 4;
|
|
u8 fmt;
|
|
|
|
if (dir == DMA_TO_DEVICE)
|
|
fmt = cmd->buf_fmt >> 4;
|
|
else {
|
|
fmt = cmd->buf_fmt & ((1U << 4) - 1);
|
|
offset += data_out_desc_size(cmd);
|
|
}
|
|
|
|
switch (fmt) {
|
|
case SRP_NO_DATA_DESC:
|
|
break;
|
|
case SRP_DATA_DESC_DIRECT:
|
|
md = (struct srp_direct_buf *) (cmd->add_data + offset);
|
|
len = md->len;
|
|
break;
|
|
case SRP_DATA_DESC_INDIRECT:
|
|
id = (struct srp_indirect_buf *) (cmd->add_data + offset);
|
|
len = id->len;
|
|
break;
|
|
default:
|
|
eprintk("invalid data format %x\n", fmt);
|
|
break;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
|
|
u64 addr)
|
|
{
|
|
enum dma_data_direction dir;
|
|
struct scsi_cmnd *sc;
|
|
int tag, len, err;
|
|
|
|
switch (cmd->task_attr) {
|
|
case SRP_SIMPLE_TASK:
|
|
tag = MSG_SIMPLE_TAG;
|
|
break;
|
|
case SRP_ORDERED_TASK:
|
|
tag = MSG_ORDERED_TAG;
|
|
break;
|
|
case SRP_HEAD_TASK:
|
|
tag = MSG_HEAD_TAG;
|
|
break;
|
|
default:
|
|
eprintk("Task attribute %d not supported\n", cmd->task_attr);
|
|
tag = MSG_ORDERED_TAG;
|
|
}
|
|
|
|
dir = srp_cmd_direction(cmd);
|
|
len = vscsis_data_length(cmd, dir);
|
|
|
|
dprintk("%p %x %lx %d %d %d %llx\n", info, cmd->cdb[0],
|
|
cmd->lun, dir, len, tag, (unsigned long long) cmd->tag);
|
|
|
|
sc = scsi_host_get_command(shost, dir, GFP_KERNEL);
|
|
if (!sc)
|
|
return -ENOMEM;
|
|
|
|
sc->SCp.ptr = info;
|
|
memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE);
|
|
sc->request_bufflen = len;
|
|
sc->request_buffer = (void *) (unsigned long) addr;
|
|
sc->tag = tag;
|
|
err = scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag);
|
|
if (err)
|
|
scsi_host_put_command(shost, sc);
|
|
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(srp_cmd_queue);
|
|
|
|
MODULE_DESCRIPTION("SCSI RDAM Protocol lib functions");
|
|
MODULE_AUTHOR("FUJITA Tomonori");
|
|
MODULE_LICENSE("GPL");
|