Commit 38a9a621 authored by James Bottomley's avatar James Bottomley

Merge HEAD from ../scsi-misc-2.6-old

parents 27d1097d e75d5176
......@@ -229,7 +229,7 @@ config SCSI_FC_ATTRS
config SCSI_ISCSI_ATTRS
tristate "iSCSI Transport Attributes"
depends on SCSI
depends on SCSI && NET
help
If you wish to export transport-specific information about
each attached iSCSI device to sysfs, say Y.
......@@ -247,6 +247,30 @@ endmenu
menu "SCSI low-level drivers"
depends on SCSI!=n
config ISCSI_TCP
tristate "iSCSI Initiator over TCP/IP"
depends on SCSI && INET
select CRYPTO
select CRYPTO_MD5
select CRYPTO_CRC32C
select SCSI_ISCSI_ATTRS
help
The iSCSI Driver provides a host with the ability to access storage
through an IP network. The driver uses the iSCSI protocol to transport
SCSI requests and responses over a TCP/IP network between the host
(the "initiator") and "targets". Architecturally, the iSCSI driver
combines with the host's TCP/IP stack, network drivers, and Network
Interface Card (NIC) to provide the same functions as a SCSI or a
Fibre Channel (FC) adapter driver with a Host Bus Adapter (HBA).
To compile this driver as a module, choose M here: the
module will be called iscsi_tcp.
The userspace component needed to initialize the driver, documentation,
and sample configuration files can be found here:
http://linux-iscsi.sf.net
config SGIWD93_SCSI
tristate "SGI WD93C93 SCSI Driver"
depends on SGI_IP22 && SCSI
......
......@@ -33,6 +33,7 @@ obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
obj-$(CONFIG_ISCSI_TCP) += iscsi_tcp.o
obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
......
......@@ -608,17 +608,43 @@ static char *container_types[] = {
* files instead of in OS dependant driver source.
*/
static void setinqstr(int devtype, void *data, int tindex)
static void setinqstr(struct aac_dev *dev, void *data, int tindex)
{
struct scsi_inq *str;
struct aac_driver_ident *mp;
mp = aac_get_driver_ident(devtype);
str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
memset(str, ' ', sizeof(*str));
if (dev->supplement_adapter_info.AdapterTypeText[0]) {
char * cp = dev->supplement_adapter_info.AdapterTypeText;
int c = sizeof(str->vid);
while (*cp && *cp != ' ' && --c)
++cp;
c = *cp;
*cp = '\0';
inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
str->vid);
*cp = c;
while (*cp && *cp != ' ')
++cp;
while (*cp == ' ')
++cp;
/* last six chars reserved for vol type */
c = 0;
if (strlen(cp) > sizeof(str->pid)) {
c = cp[sizeof(str->pid)];
cp[sizeof(str->pid)] = '\0';
}
inqstrcpy (cp, str->pid);
if (c)
cp[sizeof(str->pid)] = c;
} else {
struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype);
inqstrcpy (mp->vname, str->vid);
inqstrcpy (mp->model, str->pid); /* last six chars reserved for vol type */
/* last six chars reserved for vol type */
inqstrcpy (mp->model, str->pid);
}
if (tindex < (sizeof(container_types)/sizeof(char *))){
char *findit = str->pid;
......@@ -627,6 +653,8 @@ static void setinqstr(int devtype, void *data, int tindex)
/* RAID is superfluous in the context of a RAID device */
if (memcmp(findit-4, "RAID", 4) == 0)
*(findit -= 4) = ' ';
if (((findit - str->pid) + strlen(container_types[tindex]))
< (sizeof(str->pid) + sizeof(str->prl)))
inqstrcpy (container_types[tindex], findit + 1);
}
inqstrcpy ("V1.0", str->prl);
......@@ -822,12 +850,12 @@ int aac_get_adapter_info(struct aac_dev* dev)
dev->dac_support = (dacmode!=0);
}
if(dev->dac_support != 0) {
if (!pci_set_dma_mask(dev->pdev, 0xFFFFFFFFFFFFFFFFULL) &&
!pci_set_consistent_dma_mask(dev->pdev, 0xFFFFFFFFFFFFFFFFULL)) {
if (!pci_set_dma_mask(dev->pdev, DMA_64BIT_MASK) &&
!pci_set_consistent_dma_mask(dev->pdev, DMA_64BIT_MASK)) {
printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
dev->name, dev->id);
} else if (!pci_set_dma_mask(dev->pdev, 0xFFFFFFFFULL) &&
!pci_set_consistent_dma_mask(dev->pdev, 0xFFFFFFFFULL)) {
} else if (!pci_set_dma_mask(dev->pdev, DMA_32BIT_MASK) &&
!pci_set_consistent_dma_mask(dev->pdev, DMA_32BIT_MASK)) {
printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n",
dev->name, dev->id);
dev->dac_support = 0;
......@@ -1438,7 +1466,6 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
struct Scsi_Host *host = scsicmd->device->host;
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
int cardtype = dev->cardtype;
int ret;
/*
......@@ -1542,14 +1569,14 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* see: <vendor>.c i.e. aac.c
*/
if (scsicmd->device->id == host->this_id) {
setinqstr(cardtype, (void *) (inq_data.inqd_vid), (sizeof(container_types)/sizeof(char *)));
setinqstr(dev, (void *) (inq_data.inqd_vid), (sizeof(container_types)/sizeof(char *)));
inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
return 0;
}
setinqstr(cardtype, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
return aac_get_container_name(scsicmd, cid);
......
......@@ -1560,7 +1560,7 @@ struct fib_ioctl
struct revision
{
__le32 compat;
u32 compat;
__le32 version;
__le32 build;
};
......
......@@ -408,7 +408,7 @@ static int check_revision(struct aac_dev *dev, void __user *arg)
char *driver_version = aac_driver_version;
u32 version;
response.compat = cpu_to_le32(1);
response.compat = 1;
version = (simple_strtol(driver_version,
&driver_version, 10) << 24) | 0x00000400;
version += simple_strtol(driver_version + 1, &driver_version, 10) << 16;
......@@ -574,7 +574,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -ENOMEM;
goto cleanup;
}
sg_user[i] = (void __user *)usg->sg[i].addr;
sg_user[i] = (void __user *)(long)usg->sg[i].addr;
sg_list[i] = p; // save so we can clean up later
sg_indx = i;
......@@ -624,7 +624,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -ENOMEM;
goto cleanup;
}
sg_user[i] = (void __user *)upsg->sg[i].addr;
sg_user[i] = (void __user *)(long)upsg->sg[i].addr;
sg_list[i] = p; // save so we can clean up later
sg_indx = i;
......
......@@ -752,8 +752,8 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
if (error)
goto out;
if (pci_set_dma_mask(pdev, 0xFFFFFFFFULL) ||
pci_set_consistent_dma_mask(pdev, 0xFFFFFFFFULL))
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
goto out;
/*
* If the quirk31 bit is set, the adapter needs adapter
......@@ -797,8 +797,8 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
* address space.
*/
if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
if (pci_set_dma_mask(pdev, 0xFFFFFFFFULL))
goto out_free_fibs;
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
goto out_deinit;
aac->maximum_num_channels = aac_drivers[index].channels;
error = aac_get_adapter_info(aac);
......
......@@ -976,6 +976,16 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
}
}
static inline void pio_trigger(void)
{
static int feedback_requested;
if (!feedback_requested) {
feedback_requested = 1;
printk(KERN_WARNING "%s: Please, contact <linux-scsi@vger.kernel.org> "
"to help improve support for your system.\n", __FILE__);
}
}
/* Prepare SRB for being sent to Device DCB w/ command *cmd */
static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
......@@ -2320,6 +2330,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
CFG2_WIDEFIFO);
while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != 0x40) {
u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
pio_trigger();
*(srb->virt_addr)++ = byte;
if (debug_enabled(DBG_PIO))
printk(" %02x", byte);
......@@ -2331,6 +2342,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
/* Read the last byte ... */
if (srb->total_xfer_length > 0) {
u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
pio_trigger();
*(srb->virt_addr)++ = byte;
srb->total_xfer_length--;
if (debug_enabled(DBG_PIO))
......@@ -2507,6 +2519,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
if (debug_enabled(DBG_PIO))
printk(" %02x", (unsigned char) *(srb->virt_addr));
pio_trigger();
DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
*(srb->virt_addr)++);
......
/*
* iSCSI Initiator over TCP/IP Data-Path
*
* Copyright (C) 2004 Dmitry Yusupov
* Copyright (C) 2004 Alex Aizman
* Copyright (C) 2005 Mike Christie
* maintained by open-iscsi@googlegroups.com
*
* 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.
*
* See the file COPYING included with this distribution for more details.
*
* Credits:
* Christoph Hellwig
* FUJITA Tomonori
* Arne Redlich
* Zhenyu Wang
*/
#include <linux/types.h>
#include <linux/list.h>
#include <linux/inet.h>
#include <linux/blkdev.h>
#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
#include <net/tcp.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_request.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi.h>
#include <scsi/scsi_transport_iscsi.h>
#include "iscsi_tcp.h"
MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, "
"Alex Aizman <itn780@yahoo.com>");
MODULE_DESCRIPTION("iSCSI/TCP data-path");
MODULE_LICENSE("GPL");
MODULE_VERSION("0:4.409");
/* #define DEBUG_TCP */
/* #define DEBUG_SCSI */
#define DEBUG_ASSERT
#ifdef DEBUG_TCP
#define debug_tcp(fmt...) printk(KERN_DEBUG "tcp: " fmt)
#else
#define debug_tcp(fmt...)
#endif
#ifdef DEBUG_SCSI
#define debug_scsi(fmt...) printk(KERN_DEBUG "scsi: " fmt)
#else
#define debug_scsi(fmt...)
#endif
#ifndef DEBUG_ASSERT
#ifdef BUG_ON
#undef BUG_ON
#endif
#define BUG_ON(expr)
#endif
#define INVALID_SN_DELTA 0xffff
static unsigned int iscsi_max_lun = 512;
module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
/* global data */
static kmem_cache_t *taskcache;
static inline void
iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size)
{
sg_init_one(&ibuf->sg, (u8 *)vbuf, size);
ibuf->sent = 0;
}
static inline void
iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
{
ibuf->sg.page = (void*)vbuf;
ibuf->sg.offset = (unsigned int)-1;
ibuf->sg.length = size;
ibuf->sent = 0;
}
static inline void*
iscsi_buf_iov_base(struct iscsi_buf *ibuf)
{
return (char*)ibuf->sg.page + ibuf->sent;
}
static inline void
iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
{
/*
* Fastpath: sg element fits into single page
*/
if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) {
ibuf->sg.page = sg->page;
ibuf->sg.offset = sg->offset;
ibuf->sg.length = sg->length;
} else
iscsi_buf_init_iov(ibuf, page_address(sg->page), sg->length);
ibuf->sent = 0;
}
static inline int
iscsi_buf_left(struct iscsi_buf *ibuf)
{
int rc;
rc = ibuf->sg.length - ibuf->sent;
BUG_ON(rc < 0);
return rc;
}
static inline void
iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
u8* crc)
{
crypto_digest_digest(conn->tx_tfm, &buf->sg, 1, crc);
buf->sg.length += sizeof(uint32_t);
}
static void
iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
{
struct iscsi_session *session = conn->session;
unsigned long flags;
spin_lock_irqsave(&session->lock, flags);
if (session->conn_cnt == 1 || session->leadconn == conn)
session->state = ISCSI_STATE_FAILED;
spin_unlock_irqrestore(&session->lock, flags);
set_bit(SUSPEND_BIT, &conn->suspend_tx);
set_bit(SUSPEND_BIT, &conn->suspend_rx);
iscsi_conn_error(iscsi_handle(conn), err);
}
static inline int
iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
{
uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn);
uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn);
if (max_cmdsn < exp_cmdsn -1 &&
max_cmdsn > exp_cmdsn - INVALID_SN_DELTA)
return ISCSI_ERR_MAX_CMDSN;
if (max_cmdsn > session->max_cmdsn ||
max_cmdsn < session->max_cmdsn - INVALID_SN_DELTA)
session->max_cmdsn = max_cmdsn;
if (exp_cmdsn > session->exp_cmdsn ||
exp_cmdsn < session->exp_cmdsn - INVALID_SN_DELTA)
session->exp_cmdsn = exp_cmdsn;
return 0;
}
static inline int
iscsi_hdr_extract(struct iscsi_conn *conn)
{
struct sk_buff *skb = conn->in.skb;
if (conn->in.copy >= conn->hdr_size &&
conn->in_progress == IN_PROGRESS_WAIT_HEADER) {
/*
* Zero-copy PDU Header: using connection context
* to store header pointer.
*/
if (skb_shinfo(skb)->frag_list == NULL &&
!skb_shinfo(skb)->nr_frags)
conn->in.hdr = (struct iscsi_hdr *)
((char*)skb->data + conn->in.offset);
else {
/* ignoring return code since we checked
* in.copy before */
skb_copy_bits(skb, conn->in.offset,
&conn->hdr, conn->hdr_size);
conn->in.hdr = &conn->hdr;
}
conn->in.offset += conn->hdr_size;
conn->in.copy -= conn->hdr_size;
} else {
int hdr_remains;
int copylen;
/*
* PDU header scattered across SKB's,
* copying it... This'll happen quite rarely.
*/
if (conn->in_progress == IN_PROGRESS_WAIT_HEADER)
conn->in.hdr_offset = 0;
hdr_remains = conn->hdr_size - conn->in.hdr_offset;
BUG_ON(hdr_remains <= 0);
copylen = min(conn->in.copy, hdr_remains);
skb_copy_bits(skb, conn->in.offset,
(char*)&conn->hdr + conn->in.hdr_offset, copylen);
debug_tcp("PDU gather offset %d bytes %d in.offset %d "
"in.copy %d\n", conn->in.hdr_offset, copylen,
conn->in.offset, conn->in.copy);
conn->in.offset += copylen;
conn->in.copy -= copylen;
if (copylen < hdr_remains) {
conn->in_progress = IN_PROGRESS_HEADER_GATHER;
conn->in.hdr_offset += copylen;
return -EAGAIN;
}
conn->in.hdr = &conn->hdr;
conn->discontiguous_hdr_cnt++;
conn->in_progress = IN_PROGRESS_WAIT_HEADER;
}
return 0;
}
static inline void
iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
struct scsi_cmnd *sc = ctask->sc;
struct iscsi_session *session = conn->session;
spin_lock(&session->lock);
if (unlikely(!sc)) {
spin_unlock(&session->lock);
return;
}
if (sc->sc_data_direction == DMA_TO_DEVICE) {
struct iscsi_data_task *dtask, *n;
/* WRITE: cleanup Data-Out's if any */
spin_lock(&conn->lock);
list_for_each_entry_safe(dtask, n, &ctask->dataqueue, item) {
list_del(&dtask->item);
mempool_free(dtask, ctask->datapool);
}
spin_unlock(&conn->lock);
}
ctask->xmstate = XMSTATE_IDLE;
ctask->r2t = NULL;
ctask->sc = NULL;
__kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
spin_unlock(&session->lock);
}
/**
* iscsi_cmd_rsp - SCSI Command Response processing
* @conn: iscsi connection
* @ctask: scsi command task
**/
static int
iscsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
int rc;
struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)conn->in.hdr;
struct iscsi_session *session = conn->session;
struct scsi_cmnd *sc = ctask->sc;
rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
if (rc) {
sc->result = (DID_ERROR << 16);
goto out;
}
conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
sc->result = (DID_OK << 16) | rhdr->cmd_status;
if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) {
sc->result = (DID_ERROR << 16);
goto out;
}
if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION && conn->senselen) {
int sensecopy = min(conn->senselen, SCSI_SENSE_BUFFERSIZE);
memcpy(sc->sense_buffer, conn->data + 2, sensecopy);
debug_scsi("copied %d bytes of sense\n", sensecopy);
}
if (sc->sc_data_direction == DMA_TO_DEVICE)
goto out;
if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
int res_count = be32_to_cpu(rhdr->residual_count);
if (res_count > 0 && res_count <= sc->request_bufflen)
sc->resid = res_count;
else
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
} else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW)
sc->resid = be32_to_cpu(rhdr->residual_count);
out:
debug_scsi("done [sc %lx res %d itt 0x%x]\n",
(long)sc, sc->result, ctask->itt);
conn->scsirsp_pdus_cnt++;
iscsi_ctask_cleanup(conn, ctask);
sc->scsi_done(sc);
return rc;
}
/**
* iscsi_data_rsp - SCSI Data-In Response processing
* @conn: iscsi connection
* @ctask: scsi command task
**/
static int
iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
int rc;
struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)conn->in.hdr;
struct iscsi_session *session = conn->session;
int datasn = be32_to_cpu(rhdr->datasn);
rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
if (rc)
return rc;
/*
* setup Data-In byte counter (gets decremented..)
*/
ctask->data_count = conn->in.datalen;
if (conn->in.datalen == 0)
return 0;
if (ctask->datasn != datasn)
return ISCSI_ERR_DATASN;
ctask->datasn++;
ctask->data_offset = be32_to_cpu(rhdr->offset);
if (ctask->data_offset + conn->in.datalen > ctask->total_length)
return ISCSI_ERR_DATA_OFFSET;
if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
struct scsi_cmnd *sc = ctask->sc;
conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
int res_count = be32_to_cpu(rhdr->residual_count);
if (res_count > 0 &&
res_count <= sc->request_bufflen) {
sc->resid = res_count;