* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (102 commits)
[SCSI] scsi_dh: fix kconfig related build errors
[SCSI] sym53c8xx: Fix bogus sym_que_entry re-implementation of container_of
[SCSI] scsi_cmnd.h: remove double inclusion of linux/blkdev.h
[SCSI] make struct scsi_{host,target}_type static
[SCSI] fix locking in host use of blk_plug_device()
[SCSI] zfcp: Cleanup external header file
[SCSI] zfcp: Cleanup code in zfcp_erp.c
[SCSI] zfcp: zfcp_fsf cleanup.
[SCSI] zfcp: consolidate sysfs things into one file.
[SCSI] zfcp: Cleanup of code in zfcp_aux.c
[SCSI] zfcp: Cleanup of code in zfcp_scsi.c
[SCSI] zfcp: Move status accessors from zfcp to SCSI include file.
[SCSI] zfcp: Small QDIO cleanups
[SCSI] zfcp: Adapter reopen for large number of unsolicited status
[SCSI] zfcp: Fix error checking for ELS ADISC requests
[SCSI] zfcp: wait until adapter is finished with ERP during auto-port
[SCSI] ibmvfc: IBM Power Virtual Fibre Channel Adapter Client Driver
[SCSI] sg: Add target reset support
[SCSI] lib: Add support for the T10 (SCSI) Data Integrity Field CRC
[SCSI] sd: Move scsi_disk() accessor function to sd.h
...
#include <linux/uio.h>
#include <linux/idr.h>
#include <linux/bsg.h>
+#include <linux/smp_lock.h>
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
char name[BUS_ID_SIZE];
int max_queue;
unsigned long flags;
+ struct blk_scsi_cmd_filter *cmd_filter;
+ mode_t *f_mode;
};
enum {
BSG_F_BLOCK = 1,
- BSG_F_WRITE_PERM = 2,
};
#define BSG_DEFAULT_CMDS 64
}
static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
- struct sg_io_v4 *hdr, int has_write_perm)
+ struct sg_io_v4 *hdr, struct bsg_device *bd)
{
if (hdr->request_len > BLK_MAX_CDB) {
rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
return -EFAULT;
if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) {
- if (blk_verify_command(rq->cmd, has_write_perm))
+ if (blk_cmd_filter_verify_command(bd->cmd_filter, rq->cmd,
+ bd->f_mode))
return -EPERM;
} else if (!capable(CAP_SYS_RAWIO))
return -EPERM;
rq = blk_get_request(q, rw, GFP_KERNEL);
if (!rq)
return ERR_PTR(-ENOMEM);
- ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM,
- &bd->flags));
+ ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd);
if (ret)
goto out;
set_bit(BSG_F_BLOCK, &bd->flags);
}
-static inline void bsg_set_write_perm(struct bsg_device *bd, struct file *file)
+static void bsg_set_cmd_filter(struct bsg_device *bd,
+ struct file *file)
{
- if (file->f_mode & FMODE_WRITE)
- set_bit(BSG_F_WRITE_PERM, &bd->flags);
- else
- clear_bit(BSG_F_WRITE_PERM, &bd->flags);
+ struct inode *inode;
+ struct gendisk *disk;
+
+ if (!file)
+ return;
+
+ inode = file->f_dentry->d_inode;
+ if (!inode)
+ return;
+
+ disk = inode->i_bdev->bd_disk;
+
+ bd->cmd_filter = &disk->cmd_filter;
+ bd->f_mode = &file->f_mode;
}
/*
dprintk("%s: read %Zd bytes\n", bd->name, count);
bsg_set_block(bd, file);
+ bsg_set_cmd_filter(bd, file);
+
bytes_read = 0;
ret = __bsg_read(buf, count, bd, NULL, &bytes_read);
*ppos = bytes_read;
dprintk("%s: write %Zd bytes\n", bd->name, count);
bsg_set_block(bd, file);
- bsg_set_write_perm(bd, file);
+ bsg_set_cmd_filter(bd, file);
bytes_written = 0;
ret = __bsg_write(bd, buf, count, &bytes_written);
{
struct bsg_class_device *bcd =
container_of(kref, struct bsg_class_device, ref);
+ struct device *parent = bcd->parent;
if (bcd->release)
bcd->release(bcd->parent);
- put_device(bcd->parent);
+ put_device(parent);
}
static int bsg_put_device(struct bsg_device *bd)
mutex_lock(&bsg_mutex);
do_free = atomic_dec_and_test(&bd->ref_count);
- if (!do_free)
+ if (!do_free) {
+ mutex_unlock(&bsg_mutex);
goto out;
+ }
+
+ hlist_del(&bd->dev_list);
+ mutex_unlock(&bsg_mutex);
dprintk("%s: tearing down\n", bd->name);
*/
ret = bsg_complete_all_commands(bd);
- hlist_del(&bd->dev_list);
kfree(bd);
out:
- mutex_unlock(&bsg_mutex);
kref_put(&q->bsg_dev.ref, bsg_kref_release_function);
if (do_free)
blk_put_queue(q);
}
bd->queue = rq;
+
bsg_set_block(bd, file);
+ bsg_set_cmd_filter(bd, file);
atomic_set(&bd->ref_count, 1);
mutex_lock(&bsg_mutex);
static int bsg_open(struct inode *inode, struct file *file)
{
- struct bsg_device *bd = bsg_get_device(inode, file);
+ struct bsg_device *bd;
+
+ lock_kernel();
+ bd = bsg_get_device(inode, file);
+ unlock_kernel();
if (IS_ERR(bd))
return PTR_ERR(bd);
* Zhenyu Wang
* Modified by:
* Erez Zilber
- *
- *
- * $Id: iscsi_iser.c 6965 2006-05-07 11:36:20Z ogerlitz $
*/
#include <linux/types.h>
#include "iscsi_iser.h"
+ static struct scsi_host_template iscsi_iser_sht;
+ static struct iscsi_transport iscsi_iser_transport;
+ static struct scsi_transport_template *iscsi_iser_scsi_transport;
+
static unsigned int iscsi_max_lun = 512;
module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
struct iscsi_hdr *hdr, char *rx_data, int rx_data_len)
{
int rc = 0;
- uint32_t ret_itt;
int datalen;
int ahslen;
/* read AHS */
ahslen = hdr->hlength * 4;
- /* verify itt (itt encoding: age+cid+itt) */
- rc = iscsi_verify_itt(conn, hdr, &ret_itt);
-
- if (!rc)
- rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len);
-
+ rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len);
if (rc && rc != ISCSI_ERR_NO_SCSI_CMD)
goto error;
/**
- * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
+ * iscsi_iser_task_init - Initialize task
+ * @task: iscsi task
*
- **/
+ * Initialize the task for the scsi command or mgmt command.
+ */
static int
- iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
+ iscsi_iser_task_init(struct iscsi_task *task)
{
- struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data;
- struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iscsi_iser_conn *iser_conn = task->conn->dd_data;
+ struct iscsi_iser_task *iser_task = task->dd_data;
+
+ /* mgmt task */
+ if (!task->sc) {
+ iser_task->desc.data = task->data;
+ return 0;
+ }
- iser_ctask->command_sent = 0;
- iser_ctask->iser_conn = iser_conn;
- iser_ctask_rdma_init(iser_ctask);
+ iser_task->command_sent = 0;
+ iser_task->iser_conn = iser_conn;
+ iser_task_rdma_init(iser_task);
return 0;
}
/**
- * iscsi_mtask_xmit - xmit management(immediate) task
+ * iscsi_iser_mtask_xmit - xmit management(immediate) task
* @conn: iscsi connection
- * @mtask: task management task
+ * @task: task management task
*
* Notes:
* The function can return -EAGAIN in which case caller must
*
**/
static int
- iscsi_iser_mtask_xmit(struct iscsi_conn *conn,
- struct iscsi_mgmt_task *mtask)
+ iscsi_iser_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
{
int error = 0;
- debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
+ debug_scsi("task deq [cid %d itt 0x%x]\n", conn->id, task->itt);
- error = iser_send_control(conn, mtask);
+ error = iser_send_control(conn, task);
- /* since iser xmits control with zero copy, mtasks can not be recycled
+ /* since iser xmits control with zero copy, tasks can not be recycled
* right after sending them.
* The recycling scheme is based on whether a response is expected
- * - if yes, the mtask is recycled at iscsi_complete_pdu
- * - if no, the mtask is recycled at iser_snd_completion
+ * - if yes, the task is recycled at iscsi_complete_pdu
+ * - if no, the task is recycled at iser_snd_completion
*/
if (error && error != -ENOBUFS)
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
}
static int
- iscsi_iser_ctask_xmit_unsol_data(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask)
+ iscsi_iser_task_xmit_unsol_data(struct iscsi_conn *conn,
+ struct iscsi_task *task)
{
struct iscsi_data hdr;
int error = 0;
/* Send data-out PDUs while there's still unsolicited data to send */
- while (ctask->unsol_count > 0) {
- iscsi_prep_unsolicit_data_pdu(ctask, &hdr);
+ while (task->unsol_count > 0) {
+ iscsi_prep_unsolicit_data_pdu(task, &hdr);
debug_scsi("Sending data-out: itt 0x%x, data count %d\n",
- hdr.itt, ctask->data_count);
+ hdr.itt, task->data_count);
/* the buffer description has been passed with the command */
/* Send the command */
- error = iser_send_data_out(conn, ctask, &hdr);
+ error = iser_send_data_out(conn, task, &hdr);
if (error) {
- ctask->unsol_datasn--;
- goto iscsi_iser_ctask_xmit_unsol_data_exit;
+ task->unsol_datasn--;
+ goto iscsi_iser_task_xmit_unsol_data_exit;
}
- ctask->unsol_count -= ctask->data_count;
+ task->unsol_count -= task->data_count;
debug_scsi("Need to send %d more as data-out PDUs\n",
- ctask->unsol_count);
+ task->unsol_count);
}
- iscsi_iser_ctask_xmit_unsol_data_exit:
+ iscsi_iser_task_xmit_unsol_data_exit:
return error;
}
static int
- iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask)
+ iscsi_iser_task_xmit(struct iscsi_task *task)
{
- struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct iscsi_iser_task *iser_task = task->dd_data;
int error = 0;
- if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) {
- BUG_ON(scsi_bufflen(ctask->sc) == 0);
+ if (!task->sc)
+ return iscsi_iser_mtask_xmit(conn, task);
+
+ if (task->sc->sc_data_direction == DMA_TO_DEVICE) {
+ BUG_ON(scsi_bufflen(task->sc) == 0);
debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
- ctask->itt, scsi_bufflen(ctask->sc),
- ctask->imm_count, ctask->unsol_count);
+ task->itt, scsi_bufflen(task->sc),
+ task->imm_count, task->unsol_count);
}
- debug_scsi("ctask deq [cid %d itt 0x%x]\n",
- conn->id, ctask->itt);
+ debug_scsi("task deq [cid %d itt 0x%x]\n",
+ conn->id, task->itt);
/* Send the cmd PDU */
- if (!iser_ctask->command_sent) {
- error = iser_send_command(conn, ctask);
+ if (!iser_task->command_sent) {
+ error = iser_send_command(conn, task);
if (error)
- goto iscsi_iser_ctask_xmit_exit;
- iser_ctask->command_sent = 1;
+ goto iscsi_iser_task_xmit_exit;
+ iser_task->command_sent = 1;
}
/* Send unsolicited data-out PDU(s) if necessary */
- if (ctask->unsol_count)
- error = iscsi_iser_ctask_xmit_unsol_data(conn, ctask);
+ if (task->unsol_count)
+ error = iscsi_iser_task_xmit_unsol_data(conn, task);
- iscsi_iser_ctask_xmit_exit:
+ iscsi_iser_task_xmit_exit:
if (error && error != -ENOBUFS)
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return error;
}
static void
- iscsi_iser_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+ iscsi_iser_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task)
{
- struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iscsi_iser_task *iser_task = task->dd_data;
- if (iser_ctask->status == ISER_TASK_STATUS_STARTED) {
- iser_ctask->status = ISER_TASK_STATUS_COMPLETED;
- iser_ctask_rdma_finalize(iser_ctask);
- }
- }
-
- static struct iser_conn *
- iscsi_iser_ib_conn_lookup(__u64 ep_handle)
- {
- struct iser_conn *ib_conn;
- struct iser_conn *uib_conn = (struct iser_conn *)(unsigned long)ep_handle;
+ /* mgmt tasks do not need special cleanup */
+ if (!task->sc)
+ return;
- mutex_lock(&ig.connlist_mutex);
- list_for_each_entry(ib_conn, &ig.connlist, conn_list) {
- if (ib_conn == uib_conn) {
- mutex_unlock(&ig.connlist_mutex);
- return ib_conn;
- }
+ if (iser_task->status == ISER_TASK_STATUS_STARTED) {
+ iser_task->status = ISER_TASK_STATUS_COMPLETED;
+ iser_task_rdma_finalize(iser_task);
}
- mutex_unlock(&ig.connlist_mutex);
- iser_err("no conn exists for eph %llx\n",(unsigned long long)ep_handle);
- return NULL;
}
static struct iscsi_cls_conn *
struct iscsi_cls_conn *cls_conn;
struct iscsi_iser_conn *iser_conn;
- cls_conn = iscsi_conn_setup(cls_session, conn_idx);
+ cls_conn = iscsi_conn_setup(cls_session, sizeof(*iser_conn), conn_idx);
if (!cls_conn)
return NULL;
conn = cls_conn->dd_data;
*/
conn->max_recv_dlength = 128;
- iser_conn = kzalloc(sizeof(*iser_conn), GFP_KERNEL);
- if (!iser_conn)
- goto conn_alloc_fail;
-
- /* currently this is the only field which need to be initiated */
- rwlock_init(&iser_conn->lock);
-
+ iser_conn = conn->dd_data;
conn->dd_data = iser_conn;
iser_conn->iscsi_conn = conn;
return cls_conn;
-
- conn_alloc_fail:
- iscsi_conn_teardown(cls_conn);
- return NULL;
}
static void
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = iser_conn->ib_conn;
iscsi_conn_teardown(cls_conn);
- if (iser_conn->ib_conn)
- iser_conn->ib_conn->iser_conn = NULL;
- kfree(iser_conn);
+ /*
+ * Userspace will normally call the stop callback and
+ * already have freed the ib_conn, but if it goofed up then
+ * we free it here.
+ */
+ if (ib_conn) {
+ ib_conn->iser_conn = NULL;
+ iser_conn_put(ib_conn);
+ }
}
static int
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_iser_conn *iser_conn;
struct iser_conn *ib_conn;
+ struct iscsi_endpoint *ep;
int error;
error = iscsi_conn_bind(cls_session, cls_conn, is_leading);
/* the transport ep handle comes from user space so it must be
* verified against the global ib connections list */
- ib_conn = iscsi_iser_ib_conn_lookup(transport_eph);
- if (!ib_conn) {
+ ep = iscsi_lookup_endpoint(transport_eph);
+ if (!ep) {
iser_err("can't bind eph %llx\n",
(unsigned long long)transport_eph);
return -EINVAL;
}
+ ib_conn = ep->dd_data;
+
/* binds the iSER connection retrieved from the previously
* connected ep_handle to the iSCSI layer connection. exchanges
* connection pointers */
iser_conn = conn->dd_data;
ib_conn->iser_conn = iser_conn;
iser_conn->ib_conn = ib_conn;
+ iser_conn_get(ib_conn);
+ return 0;
+ }
- conn->recv_lock = &iser_conn->lock;
+ static void
+ iscsi_iser_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+ {
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_conn *ib_conn = iser_conn->ib_conn;
- return 0;
+ /*
+ * Userspace may have goofed up and not bound the connection or
+ * might have only partially setup the connection.
+ */
+ if (ib_conn) {
+ iscsi_conn_stop(cls_conn, flag);
+ /*
+ * There is no unbind event so the stop callback
+ * must release the ref from the bind.
+ */
+ iser_conn_put(ib_conn);
+ }
+ iser_conn->ib_conn = NULL;
}
static int
return iscsi_conn_start(cls_conn);
}
- static struct iscsi_transport iscsi_iser_transport;
+ static void iscsi_iser_session_destroy(struct iscsi_cls_session *cls_session)
+ {
+ struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+
+ iscsi_host_remove(shost);
+ iscsi_host_free(shost);
+ }
static struct iscsi_cls_session *
- iscsi_iser_session_create(struct iscsi_transport *iscsit,
- struct scsi_transport_template *scsit,
- uint16_t cmds_max, uint16_t qdepth,
- uint32_t initial_cmdsn, uint32_t *hostno)
+ iscsi_iser_session_create(struct iscsi_endpoint *ep,
+ uint16_t cmds_max, uint16_t qdepth,
+ uint32_t initial_cmdsn, uint32_t *hostno)
{
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
+ struct Scsi_Host *shost;
int i;
- uint32_t hn;
- struct iscsi_cmd_task *ctask;
- struct iscsi_mgmt_task *mtask;
- struct iscsi_iser_cmd_task *iser_ctask;
- struct iser_desc *desc;
+ struct iscsi_task *task;
+ struct iscsi_iser_task *iser_task;
+ struct iser_conn *ib_conn;
+
+ shost = iscsi_host_alloc(&iscsi_iser_sht, 0, ISCSI_MAX_CMD_PER_LUN);
+ if (!shost)
+ return NULL;
+ shost->transportt = iscsi_iser_scsi_transport;
+ shost->max_lun = iscsi_max_lun;
+ shost->max_id = 0;
+ shost->max_channel = 0;
+ shost->max_cmd_len = 16;
+
+ /*
+ * older userspace tools (before 2.0-870) did not pass us
+ * the leading conn's ep so this will be NULL;
+ */
+ if (ep)
+ ib_conn = ep->dd_data;
+
+ if (iscsi_host_add(shost,
+ ep ? ib_conn->device->ib_device->dma_device : NULL))
+ goto free_host;
+ *hostno = shost->host_no;
/*
* we do not support setting can_queue cmd_per_lun from userspace yet
* because we preallocate so many resources
*/
- cls_session = iscsi_session_setup(iscsit, scsit,
+ cls_session = iscsi_session_setup(&iscsi_iser_transport, shost,
ISCSI_DEF_XMIT_CMDS_MAX,
- ISCSI_MAX_CMD_PER_LUN,
- sizeof(struct iscsi_iser_cmd_task),
- sizeof(struct iser_desc),
- initial_cmdsn, &hn);
+ sizeof(struct iscsi_iser_task),
+ initial_cmdsn, 0);
if (!cls_session)
- return NULL;
-
- *hostno = hn;
- session = class_to_transport_session(cls_session);
+ goto remove_host;
+ session = cls_session->dd_data;
+ shost->can_queue = session->scsi_cmds_max;
/* libiscsi setup itts, data and pool so just set desc fields */
for (i = 0; i < session->cmds_max; i++) {
- ctask = session->cmds[i];
- iser_ctask = ctask->dd_data;
- ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header;
- ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header);
- }
-
- for (i = 0; i < session->mgmtpool_max; i++) {
- mtask = session->mgmt_cmds[i];
- desc = mtask->dd_data;
- mtask->hdr = &desc->iscsi_header;
- desc->data = mtask->data;
+ task = session->cmds[i];
+ iser_task = task->dd_data;
+ task->hdr = (struct iscsi_cmd *)&iser_task->desc.iscsi_header;
+ task->hdr_max = sizeof(iser_task->desc.iscsi_header);
}
-
return cls_session;
+
+ remove_host:
+ iscsi_host_remove(shost);
+ free_host:
+ iscsi_host_free(shost);
+ return NULL;
}
static int
stats->custom[3].value = conn->fmr_unalign_cnt;
}
- static int
- iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking,
- __u64 *ep_handle)
+ static struct iscsi_endpoint *
+ iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking)
{
int err;
struct iser_conn *ib_conn;
+ struct iscsi_endpoint *ep;
- err = iser_conn_init(&ib_conn);
- if (err)
- goto out;
+ ep = iscsi_create_endpoint(sizeof(*ib_conn));
+ if (!ep)
+ return ERR_PTR(-ENOMEM);
- err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr, non_blocking);
- if (!err)
- *ep_handle = (__u64)(unsigned long)ib_conn;
+ ib_conn = ep->dd_data;
+ ib_conn->ep = ep;
+ iser_conn_init(ib_conn);
- out:
- return err;
+ err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr,
+ non_blocking);
+ if (err) {
+ iscsi_destroy_endpoint(ep);
+ return ERR_PTR(err);
+ }
+ return ep;
}
static int
- iscsi_iser_ep_poll(__u64 ep_handle, int timeout_ms)
+ iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
{
- struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
+ struct iser_conn *ib_conn;
int rc;
- if (!ib_conn)
- return -EINVAL;
-
+ ib_conn = ep->dd_data;
rc = wait_event_interruptible_timeout(ib_conn->wait,
ib_conn->state == ISER_CONN_UP,
msecs_to_jiffies(timeout_ms));
}
static void
- iscsi_iser_ep_disconnect(__u64 ep_handle)
+ iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep)
{
struct iser_conn *ib_conn;
- ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
- if (!ib_conn)
- return;
+ ib_conn = ep->dd_data;
+ if (ib_conn->iser_conn)
+ /*
+ * Must suspend xmit path if the ep is bound to the
+ * iscsi_conn, so we know we are not accessing the ib_conn
+ * when we free it.
+ *
+ * This may not be bound if the ep poll failed.
+ */
+ iscsi_suspend_tx(ib_conn->iser_conn->iscsi_conn);
+
iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
iser_conn_terminate(ib_conn);
.name = "iSCSI Initiator over iSER, v." DRV_VER,
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
- .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1,
.sg_tablesize = ISCSI_ISER_SG_TABLESIZE,
.max_sectors = 1024,
.cmd_per_lun = ISCSI_MAX_CMD_PER_LUN,
ISCSI_USERNAME | ISCSI_PASSWORD |
ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
- ISCSI_PING_TMO | ISCSI_RECV_TMO,
+ ISCSI_PING_TMO | ISCSI_RECV_TMO |
+ ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
.host_param_mask = ISCSI_HOST_HWADDRESS |
ISCSI_HOST_NETDEV_NAME |
ISCSI_HOST_INITIATOR_NAME,
- .host_template = &iscsi_iser_sht,
- .conndata_size = sizeof(struct iscsi_conn),
- .max_lun = ISCSI_ISER_MAX_LUN,
- .max_cmd_len = ISCSI_ISER_MAX_CMD_LEN,
/* session management */
.create_session = iscsi_iser_session_create,
- .destroy_session = iscsi_session_teardown,
+ .destroy_session = iscsi_iser_session_destroy,
/* connection management */
.create_conn = iscsi_iser_conn_create,
.bind_conn = iscsi_iser_conn_bind,
.get_conn_param = iscsi_conn_get_param,
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_iser_conn_start,
- .stop_conn = iscsi_conn_stop,
+ .stop_conn = iscsi_iser_conn_stop,
/* iscsi host params */
.get_host_param = iscsi_host_get_param,
.set_host_param = iscsi_host_set_param,
/* IO */
.send_pdu = iscsi_conn_send_pdu,
.get_stats = iscsi_iser_conn_get_stats,
- .init_cmd_task = iscsi_iser_cmd_init,
- .xmit_cmd_task = iscsi_iser_ctask_xmit,
- .xmit_mgmt_task = iscsi_iser_mtask_xmit,
- .cleanup_cmd_task = iscsi_iser_cleanup_ctask,
+ .init_task = iscsi_iser_task_init,
+ .xmit_task = iscsi_iser_task_xmit,
+ .cleanup_task = iscsi_iser_cleanup_task,
/* recovery */
.session_recovery_timedout = iscsi_session_recovery_timedout,
return -EINVAL;
}
- iscsi_iser_transport.max_lun = iscsi_max_lun;
-
memset(&ig, 0, sizeof(struct iser_global));
ig.desc_cache = kmem_cache_create("iser_descriptors",
mutex_init(&ig.connlist_mutex);
INIT_LIST_HEAD(&ig.connlist);
- if (!iscsi_register_transport(&iscsi_iser_transport)) {
+ iscsi_iser_scsi_transport = iscsi_register_transport(
+ &iscsi_iser_transport);
+ if (!iscsi_iser_scsi_transport) {
iser_err("iscsi_register_transport failed\n");
err = -EINVAL;
goto register_transport_failure;
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
- *
- * $Id: iscsi_iser.h 7051 2006-05-10 12:29:11Z ogerlitz $
*/
#ifndef __ISCSI_ISER_H__
#define __ISCSI_ISER_H__
/* support upto 512KB in one RDMA */
#define ISCSI_ISER_SG_TABLESIZE (0x80000 >> SHIFT_4K)
#define ISCSI_ISER_MAX_LUN 256
- #define ISCSI_ISER_MAX_CMD_LEN 16
/* QP settings */
/* Maximal bounds on received asynchronous PDUs */
/* fwd declarations */
struct iser_device;
struct iscsi_iser_conn;
- struct iscsi_iser_cmd_task;
+ struct iscsi_iser_task;
+ struct iscsi_endpoint;
struct iser_mem_reg {
u32 lkey;
#define MAX_REGD_BUF_VECTOR_LEN 2
struct iser_dto {
- struct iscsi_iser_cmd_task *ctask;
+ struct iscsi_iser_task *task;
struct iser_conn *ib_conn;
int notify_enable;
struct iser_conn {
struct iscsi_iser_conn *iser_conn; /* iser conn for upcalls */
+ struct iscsi_endpoint *ep;
enum iser_ib_conn_state state; /* rdma connection state */
+ atomic_t refcount;
spinlock_t lock; /* used for state changes */
struct iser_device *device; /* device context */
struct rdma_cm_id *cma_id; /* CMA ID */
struct iscsi_iser_conn {
struct iscsi_conn *iscsi_conn;/* ptr to iscsi conn */
struct iser_conn *ib_conn; /* iSER IB conn */
-
- rwlock_t lock;
};
- struct iscsi_iser_cmd_task {
+ struct iscsi_iser_task {
struct iser_desc desc;
struct iscsi_iser_conn *iser_conn;
enum iser_task_status status;
/* allocate connection resources needed for rdma functionality */
int iser_conn_set_full_featured_mode(struct iscsi_conn *conn);
- int iser_send_control(struct iscsi_conn *conn,
- struct iscsi_mgmt_task *mtask);
+ int iser_send_control(struct iscsi_conn *conn,
+ struct iscsi_task *task);
- int iser_send_command(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask);
+ int iser_send_command(struct iscsi_conn *conn,
+ struct iscsi_task *task);
- int iser_send_data_out(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask,
- struct iscsi_data *hdr);
+ int iser_send_data_out(struct iscsi_conn *conn,
+ struct iscsi_task *task,
+ struct iscsi_data *hdr);
void iscsi_iser_recv(struct iscsi_conn *conn,
struct iscsi_hdr *hdr,
char *rx_data,
int rx_data_len);
- int iser_conn_init(struct iser_conn **ib_conn);
+ void iser_conn_init(struct iser_conn *ib_conn);
+
+ void iser_conn_get(struct iser_conn *ib_conn);
+
+ void iser_conn_put(struct iser_conn *ib_conn);
void iser_conn_terminate(struct iser_conn *ib_conn);
void iser_snd_completion(struct iser_desc *desc);
- void iser_ctask_rdma_init(struct iscsi_iser_cmd_task *ctask);
+ void iser_task_rdma_init(struct iscsi_iser_task *task);
- void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *ctask);
+ void iser_task_rdma_finalize(struct iscsi_iser_task *task);
void iser_dto_buffs_release(struct iser_dto *dto);
struct iser_regd_buf *regd_buf,
enum dma_data_direction direction);
- void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
+ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *task,
enum iser_data_dir cmd_dir);
- int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *ctask,
+ int iser_reg_rdma_mem(struct iscsi_iser_task *task,
enum iser_data_dir cmd_dir);
int iser_connect(struct iser_conn *ib_conn,
int iser_conn_state_comp(struct iser_conn *ib_conn,
enum iser_ib_conn_state comp);
- int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
+ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
struct iser_data_buf *data,
enum iser_data_dir iser_dir,
enum dma_data_direction dma_dir);
- void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask);
+ void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task);
#endif
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
- *
- * $Id: iser_initiator.c 6964 2006-05-07 11:11:43Z ogerlitz $
*/
#include <linux/kernel.h>
#include <linux/slab.h>
/* Register user buffer memory and initialize passive rdma
* dto descriptor. Total data size is stored in
- * iser_ctask->data[ISER_DIR_IN].data_len
+ * iser_task->data[ISER_DIR_IN].data_len
*/
- static int iser_prepare_read_cmd(struct iscsi_cmd_task *ctask,
+ static int iser_prepare_read_cmd(struct iscsi_task *task,
unsigned int edtl)
{
- struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_regd_buf *regd_buf;
int err;
- struct iser_hdr *hdr = &iser_ctask->desc.iser_header;
- struct iser_data_buf *buf_in = &iser_ctask->data[ISER_DIR_IN];
+ struct iser_hdr *hdr = &iser_task->desc.iser_header;
+ struct iser_data_buf *buf_in = &iser_task->data[ISER_DIR_IN];
- err = iser_dma_map_task_data(iser_ctask,
+ err = iser_dma_map_task_data(iser_task,
buf_in,
ISER_DIR_IN,
DMA_FROM_DEVICE);
if (err)
return err;
- if (edtl > iser_ctask->data[ISER_DIR_IN].data_len) {
+ if (edtl > iser_task->data[ISER_DIR_IN].data_len) {
iser_err("Total data length: %ld, less than EDTL: "
"%d, in READ cmd BHS itt: %d, conn: 0x%p\n",
- iser_ctask->data[ISER_DIR_IN].data_len, edtl,
- ctask->itt, iser_ctask->iser_conn);
+ iser_task->data[ISER_DIR_IN].data_len, edtl,
+ task->itt, iser_task->iser_conn);
return -EINVAL;
}
- err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_IN);
+ err = iser_reg_rdma_mem(iser_task,ISER_DIR_IN);
if (err) {
iser_err("Failed to set up Data-IN RDMA\n");
return err;
}
- regd_buf = &iser_ctask->rdma_regd[ISER_DIR_IN];
+ regd_buf = &iser_task->rdma_regd[ISER_DIR_IN];
hdr->flags |= ISER_RSV;
hdr->read_stag = cpu_to_be32(regd_buf->reg.rkey);
hdr->read_va = cpu_to_be64(regd_buf->reg.va);
iser_dbg("Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX\n",
- ctask->itt, regd_buf->reg.rkey,
+ task->itt, regd_buf->reg.rkey,
(unsigned long long)regd_buf->reg.va);
return 0;
/* Register user buffer memory and initialize passive rdma
* dto descriptor. Total data size is stored in
- * ctask->data[ISER_DIR_OUT].data_len
+ * task->data[ISER_DIR_OUT].data_len
*/
static int
- iser_prepare_write_cmd(struct iscsi_cmd_task *ctask,
+ iser_prepare_write_cmd(struct iscsi_task *task,
unsigned int imm_sz,
unsigned int unsol_sz,
unsigned int edtl)
{
- struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_regd_buf *regd_buf;
int err;
- struct iser_dto *send_dto = &iser_ctask->desc.dto;
- struct iser_hdr *hdr = &iser_ctask->desc.iser_header;
- struct iser_data_buf *buf_out = &iser_ctask->data[ISER_DIR_OUT];
+ struct iser_dto *send_dto = &iser_task->desc.dto;
+ struct iser_hdr *hdr = &iser_task->desc.iser_header;
+ struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT];
- err = iser_dma_map_task_data(iser_ctask,
+ err = iser_dma_map_task_data(iser_task,
buf_out,
ISER_DIR_OUT,
DMA_TO_DEVICE);
if (err)
return err;
- if (edtl > iser_ctask->data[ISER_DIR_OUT].data_len) {
+ if (edtl > iser_task->data[ISER_DIR_OUT].data_len) {
iser_err("Total data length: %ld, less than EDTL: %d, "
"in WRITE cmd BHS itt: %d, conn: 0x%p\n",
- iser_ctask->data[ISER_DIR_OUT].data_len,
- edtl, ctask->itt, ctask->conn);
+ iser_task->data[ISER_DIR_OUT].data_len,
+ edtl, task->itt, task->conn);
return -EINVAL;
}
- err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_OUT);
+ err = iser_reg_rdma_mem(iser_task,ISER_DIR_OUT);
if (err != 0) {
iser_err("Failed to register write cmd RDMA mem\n");
return err;
}
- regd_buf = &iser_ctask->rdma_regd[ISER_DIR_OUT];
+ regd_buf = &iser_task->rdma_regd[ISER_DIR_OUT];
if (unsol_sz < edtl) {
hdr->flags |= ISER_WSV;
iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X "
"VA:%#llX + unsol:%d\n",
- ctask->itt, regd_buf->reg.rkey,
+ task->itt, regd_buf->reg.rkey,
(unsigned long long)regd_buf->reg.va, unsol_sz);
}
if (imm_sz > 0) {
iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n",
- ctask->itt, imm_sz);
+ task->itt, imm_sz);
iser_dto_add_regd_buff(send_dto,
regd_buf,
0,
/**
* iser_send_command - send command PDU
*/
- int iser_send_command(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask)
+ int iser_send_command(struct iscsi_conn *conn,
+ struct iscsi_task *task)
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
- struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_dto *send_dto = NULL;
unsigned long edtl;
int err = 0;
struct iser_data_buf *data_buf;
- struct iscsi_cmd *hdr = ctask->hdr;
- struct scsi_cmnd *sc = ctask->sc;
+ struct iscsi_cmd *hdr = task->hdr;
+ struct scsi_cmnd *sc = task->sc;
if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
return -EPERM;
}
- if (iser_check_xmit(conn, ctask))
+ if (iser_check_xmit(conn, task))
return -ENOBUFS;
edtl = ntohl(hdr->data_length);
/* build the tx desc regd header and add it to the tx desc dto */
- iser_ctask->desc.type = ISCSI_TX_SCSI_COMMAND;
- send_dto = &iser_ctask->desc.dto;
- send_dto->ctask = iser_ctask;
- iser_create_send_desc(iser_conn, &iser_ctask->desc);
+ iser_task->desc.type = ISCSI_TX_SCSI_COMMAND;
+ send_dto = &iser_task->desc.dto;
+ send_dto->task = iser_task;
+ iser_create_send_desc(iser_conn, &iser_task->desc);
if (hdr->flags & ISCSI_FLAG_CMD_READ)
- data_buf = &iser_ctask->data[ISER_DIR_IN];
+ data_buf = &iser_task->data[ISER_DIR_IN];
else
- data_buf = &iser_ctask->data[ISER_DIR_OUT];
+ data_buf = &iser_task->data[ISER_DIR_OUT];
if (scsi_sg_count(sc)) { /* using a scatter list */
data_buf->buf = scsi_sglist(sc);
data_buf->data_len = scsi_bufflen(sc);
if (hdr->flags & ISCSI_FLAG_CMD_READ) {
- err = iser_prepare_read_cmd(ctask, edtl);
+ err = iser_prepare_read_cmd(task, edtl);
if (err)
goto send_command_error;
}
if (hdr->flags & ISCSI_FLAG_CMD_WRITE) {
- err = iser_prepare_write_cmd(ctask,
- ctask->imm_count,
- ctask->imm_count +
- ctask->unsol_count,
+ err = iser_prepare_write_cmd(task,
+ task->imm_count,
+ task->imm_count +
+ task->unsol_count,
edtl);
if (err)
goto send_command_error;
goto send_command_error;
}
- iser_ctask->status = ISER_TASK_STATUS_STARTED;
+ iser_task->status = ISER_TASK_STATUS_STARTED;
- err = iser_post_send(&iser_ctask->desc);
+ err = iser_post_send(&iser_task->desc);
if (!err)
return 0;
send_command_error:
iser_dto_buffs_release(send_dto);
- iser_err("conn %p failed ctask->itt %d err %d\n",conn, ctask->itt, err);
+ iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err);
return err;
}
/**
* iser_send_data_out - send data out PDU
*/
- int iser_send_data_out(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask,
+ int iser_send_data_out(struct iscsi_conn *conn,
+ struct iscsi_task *task,
struct iscsi_data *hdr)
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
- struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iscsi_iser_task *iser_task = task->dd_data;
struct iser_desc *tx_desc = NULL;
struct iser_dto *send_dto = NULL;
unsigned long buf_offset;
return -EPERM;
}
- if (iser_check_xmit(conn, ctask))
+ if (iser_check_xmit(conn, task))
return -ENOBUFS;
itt = (__force uint32_t)hdr->itt;
/* build the tx desc regd header and add it to the tx desc dto */
send_dto = &tx_desc->dto;
- send_dto->ctask = iser_ctask;
+ send_dto->task = iser_task;
iser_create_send_desc(iser_conn, tx_desc);
iser_reg_single(iser_conn->ib_conn->device,
/* all data was registered for RDMA, we can use the lkey */
iser_dto_add_regd_buff(send_dto,
- &iser_ctask->rdma_regd[ISER_DIR_OUT],
+ &iser_task->rdma_regd[ISER_DIR_OUT],
buf_offset,
data_seg_len);
- if (buf_offset + data_seg_len > iser_ctask->data[ISER_DIR_OUT].data_len) {
+ if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) {
iser_err("Offset:%ld & DSL:%ld in Data-Out "
"inconsistent with total len:%ld, itt:%d\n",
buf_offset, data_seg_len,
- iser_ctask->data[ISER_DIR_OUT].data_len, itt);
+ iser_task->data[ISER_DIR_OUT].data_len, itt);
err = -EINVAL;
goto send_data_out_error;
}
}
int iser_send_control(struct iscsi_conn *conn,
- struct iscsi_mgmt_task *mtask)
+ struct iscsi_task *task)
{
struct iscsi_iser_conn *iser_conn = conn->dd_data;
- struct iser_desc *mdesc = mtask->dd_data;
+ struct iscsi_iser_task *iser_task = task->dd_data;
+ struct iser_desc *mdesc = &iser_task->desc;
struct iser_dto *send_dto = NULL;
unsigned long data_seg_len;
int err = 0;
return -EPERM;
}
- if (iser_check_xmit(conn,mtask))
+ if (iser_check_xmit(conn, task))
return -ENOBUFS;
/* build the tx desc regd header and add it to the tx desc dto */
mdesc->type = ISCSI_TX_CONTROL;
send_dto = &mdesc->dto;
- send_dto->ctask = NULL;
+ send_dto->task = NULL;
iser_create_send_desc(iser_conn, mdesc);
device = iser_conn->ib_conn->device;
iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE);
- data_seg_len = ntoh24(mtask->hdr->dlength);
+ data_seg_len = ntoh24(task->hdr->dlength);
if (data_seg_len > 0) {
regd_buf = &mdesc->data_regd_buf;
memset(regd_buf, 0, sizeof(struct iser_regd_buf));
regd_buf->device = device;
- regd_buf->virt_addr = mtask->data;
- regd_buf->data_size = mtask->data_count;
+ regd_buf->virt_addr = task->data;
+ regd_buf->data_size = task->data_count;
iser_reg_single(device, regd_buf,
DMA_TO_DEVICE);
iser_dto_add_regd_buff(send_dto, regd_buf,
void iser_rcv_completion(struct iser_desc *rx_desc,
unsigned long dto_xfer_len)
{
- struct iser_dto *dto = &rx_desc->dto;
+ struct iser_dto *dto = &rx_desc->dto;
struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn;
- struct iscsi_session *session = conn->iscsi_conn->session;
- struct iscsi_cmd_task *ctask;
- struct iscsi_iser_cmd_task *iser_ctask;
+ struct iscsi_task *task;
+ struct iscsi_iser_task *iser_task;
struct iscsi_hdr *hdr;
char *rx_data = NULL;
int rx_data_len = 0;
- unsigned int itt;
unsigned char opcode;
hdr = &rx_desc->iscsi_header;
opcode = hdr->opcode & ISCSI_OPCODE_MASK;
if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
- itt = get_itt(hdr->itt); /* mask out cid and age bits */
- if (!(itt < session->cmds_max))
+ spin_lock(&conn->iscsi_conn->session->lock);
+ task = iscsi_itt_to_ctask(conn->iscsi_conn, hdr->itt);
+ if (task)
+ __iscsi_get_task(task);
+ spin_unlock(&conn->iscsi_conn->session->lock);
+
+ if (!task)
iser_err("itt can't be matched to task!!! "
- "conn %p opcode %d cmds_max %d itt %d\n",
- conn->iscsi_conn,opcode,session->cmds_max,itt);
- /* use the mapping given with the cmds array indexed by itt */
- ctask = (struct iscsi_cmd_task *)session->cmds[itt];
- iser_ctask = ctask->dd_data;
- iser_dbg("itt %d ctask %p\n",itt,ctask);
- iser_ctask->status = ISER_TASK_STATUS_COMPLETED;
- iser_ctask_rdma_finalize(iser_ctask);
+ "conn %p opcode %d itt %d\n",
+ conn->iscsi_conn, opcode, hdr->itt);
+ else {
+ iser_task = task->dd_data;
+ iser_dbg("itt %d task %p\n",hdr->itt, task);
+ iser_task->status = ISER_TASK_STATUS_COMPLETED;
+ iser_task_rdma_finalize(iser_task);
+ iscsi_put_task(task);
+ }
}
-
iser_dto_buffs_release(dto);
iscsi_iser_recv(conn->iscsi_conn, hdr, rx_data, rx_data_len);
struct iser_conn *ib_conn = dto->ib_conn;
struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn;
struct iscsi_conn *conn = iser_conn->iscsi_conn;
- struct iscsi_mgmt_task *mtask;
+ struct iscsi_task *task;
int resume_tx = 0;
iser_dbg("Initiator, Data sent dto=0x%p\n", dto);
if (tx_desc->type == ISCSI_TX_CONTROL) {
/* this arithmetic is legal by libiscsi dd_data allocation */
- mtask = (void *) ((long)(void *)tx_desc -
- sizeof(struct iscsi_mgmt_task));
- if (mtask->hdr->itt == RESERVED_ITT) {
- struct iscsi_session *session = conn->session;
-
- spin_lock(&conn->session->lock);
- iscsi_free_mgmt_task(conn, mtask);
- spin_unlock(&session->lock);
- }
+ task = (void *) ((long)(void *)tx_desc -
+ sizeof(struct iscsi_task));
+ if (task->hdr->itt == RESERVED_ITT)
+ iscsi_put_task(task);
}
}
- void iser_ctask_rdma_init(struct iscsi_iser_cmd_task *iser_ctask)
+ void iser_task_rdma_init(struct iscsi_iser_task *iser_task)
{
- iser_ctask->status = ISER_TASK_STATUS_INIT;
+ iser_task->status = ISER_TASK_STATUS_INIT;
- iser_ctask->dir[ISER_DIR_IN] = 0;
- iser_ctask->dir[ISER_DIR_OUT] = 0;
+ iser_task->dir[ISER_DIR_IN] = 0;
+ iser_task->dir[ISER_DIR_OUT] = 0;
- iser_ctask->data[ISER_DIR_IN].data_len = 0;
- iser_ctask->data[ISER_DIR_OUT].data_len = 0;
+ iser_task->data[ISER_DIR_IN].data_len = 0;
+ iser_task->data[ISER_DIR_OUT].data_len = 0;
- memset(&iser_ctask->rdma_regd[ISER_DIR_IN], 0,
+ memset(&iser_task->rdma_regd[ISER_DIR_IN], 0,
sizeof(struct iser_regd_buf));
- memset(&iser_ctask->rdma_regd[ISER_DIR_OUT], 0,
+ memset(&iser_task->rdma_regd[ISER_DIR_OUT], 0,
sizeof(struct iser_regd_buf));
}
- void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask)
+ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
{
int deferred;
int is_rdma_aligned = 1;
/* if we were reading, copy back to unaligned sglist,
* anyway dma_unmap and free the copy
*/
- if (iser_ctask->data_copy[ISER_DIR_IN].copy_buf != NULL) {
+ if (iser_task->data_copy[ISER_DIR_IN].copy_buf != NULL) {
is_rdma_aligned = 0;
- iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_IN);
+ iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_IN);
}
- if (iser_ctask->data_copy[ISER_DIR_OUT].copy_buf != NULL) {
+ if (iser_task->data_copy[ISER_DIR_OUT].copy_buf != NULL) {
is_rdma_aligned = 0;
- iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_OUT);
+ iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_OUT);
}
- if (iser_ctask->dir[ISER_DIR_IN]) {
- regd = &iser_ctask->rdma_regd[ISER_DIR_IN];
+ if (iser_task->dir[ISER_DIR_IN]) {
+ regd = &iser_task->rdma_regd[ISER_DIR_IN];
deferred = iser_regd_buff_release(regd);
if (deferred) {
iser_err("%d references remain for BUF-IN rdma reg\n",
}
}
- if (iser_ctask->dir[ISER_DIR_OUT]) {
- regd = &iser_ctask->rdma_regd[ISER_DIR_OUT];
+ if (iser_task->dir[ISER_DIR_OUT]) {
+ regd = &iser_task->rdma_regd[ISER_DIR_OUT];
deferred = iser_regd_buff_release(regd);
if (deferred) {
iser_err("%d references remain for BUF-OUT rdma reg\n",
/* if the data was unaligned, it was already unmapped and then copied */
if (is_rdma_aligned)
- iser_dma_unmap_task_data(iser_ctask);
+ iser_dma_unmap_task_data(iser_task);
}
void iser_dto_buffs_release(struct iser_dto *dto)
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
- *
- * $Id: iser_memory.c 6964 2006-05-07 11:11:43Z ogerlitz $
*/
#include <linux/module.h>
#include <linux/kernel.h>
/**
* iser_start_rdma_unaligned_sg
*/
- static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
enum iser_data_dir cmd_dir)
{
int dma_nents;
struct ib_device *dev;
char *mem = NULL;
- struct iser_data_buf *data = &iser_ctask->data[cmd_dir];
+ struct iser_data_buf *data = &iser_task->data[cmd_dir];
unsigned long cmd_data_len = data->data_len;
if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
}
}
- sg_init_one(&iser_ctask->data_copy[cmd_dir].sg_single, mem, cmd_data_len);
- iser_ctask->data_copy[cmd_dir].buf =
- &iser_ctask->data_copy[cmd_dir].sg_single;
- iser_ctask->data_copy[cmd_dir].size = 1;
+ sg_init_one(&iser_task->data_copy[cmd_dir].sg_single, mem, cmd_data_len);
+ iser_task->data_copy[cmd_dir].buf =
+ &iser_task->data_copy[cmd_dir].sg_single;
+ iser_task->data_copy[cmd_dir].size = 1;
- iser_ctask->data_copy[cmd_dir].copy_buf = mem;
+ iser_task->data_copy[cmd_dir].copy_buf = mem;
- dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
+ dev = iser_task->iser_conn->ib_conn->device->ib_device;
dma_nents = ib_dma_map_sg(dev,
- &iser_ctask->data_copy[cmd_dir].sg_single,
+ &iser_task->data_copy[cmd_dir].sg_single,
1,
(cmd_dir == ISER_DIR_OUT) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
BUG_ON(dma_nents == 0);
- iser_ctask->data_copy[cmd_dir].dma_nents = dma_nents;
+ iser_task->data_copy[cmd_dir].dma_nents = dma_nents;
return 0;
}
/**
* iser_finalize_rdma_unaligned_sg
*/
- void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task,
enum iser_data_dir cmd_dir)
{
struct ib_device *dev;
struct iser_data_buf *mem_copy;
unsigned long cmd_data_len;
- dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
- mem_copy = &iser_ctask->data_copy[cmd_dir];
+ dev = iser_task->iser_conn->ib_conn->device->ib_device;
+ mem_copy = &iser_task->data_copy[cmd_dir];
ib_dma_unmap_sg(dev, &mem_copy->sg_single, 1,
(cmd_dir == ISER_DIR_OUT) ?
/* copy back read RDMA to unaligned sg */
mem = mem_copy->copy_buf;
- sgl = (struct scatterlist *)iser_ctask->data[ISER_DIR_IN].buf;
- sg_size = iser_ctask->data[ISER_DIR_IN].size;
+ sgl = (struct scatterlist *)iser_task->data[ISER_DIR_IN].buf;
+ sg_size = iser_task->data[ISER_DIR_IN].size;
p = mem;
for_each_sg(sgl, sg, sg_size, i) {
}
}
- cmd_data_len = iser_ctask->data[cmd_dir].data_len;
+ cmd_data_len = iser_task->data[cmd_dir].data_len;
if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
free_pages((unsigned long)mem_copy->copy_buf,
}
}
- int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
- struct iser_data_buf *data,
- enum iser_data_dir iser_dir,
- enum dma_data_direction dma_dir)
+ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
+ struct iser_data_buf *data,
+ enum iser_data_dir iser_dir,
+ enum dma_data_direction dma_dir)
{
struct ib_device *dev;
- iser_ctask->dir[iser_dir] = 1;
- dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
+ iser_task->dir[iser_dir] = 1;
+ dev = iser_task->iser_conn->ib_conn->device->ib_device;
data->dma_nents = ib_dma_map_sg(dev, data->buf, data->size, dma_dir);
if (data->dma_nents == 0) {
return 0;
}
- void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
+ void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task)
{
struct ib_device *dev;
struct iser_data_buf *data;
- dev = iser_ctask->iser_conn->ib_conn->device->ib_device;
+ dev = iser_task->iser_conn->ib_conn->device->ib_device;
- if (iser_ctask->dir[ISER_DIR_IN]) {
- data = &iser_ctask->data[ISER_DIR_IN];
+ if (iser_task->dir[ISER_DIR_IN]) {
+ data = &iser_task->data[ISER_DIR_IN];
ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE);
}
- if (iser_ctask->dir[ISER_DIR_OUT]) {
- data = &iser_ctask->data[ISER_DIR_OUT];
+ if (iser_task->dir[ISER_DIR_OUT]) {
+ data = &iser_task->data[ISER_DIR_OUT];
ib_dma_unmap_sg(dev, data->buf, data->size, DMA_TO_DEVICE);
}
}
*
* returns 0 on success, errno code on failure
*/
- int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
+ int iser_reg_rdma_mem(struct iscsi_iser_task *iser_task,
enum iser_data_dir cmd_dir)
{
- struct iscsi_conn *iscsi_conn = iser_ctask->iser_conn->iscsi_conn;
- struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn;
+ struct iscsi_conn *iscsi_conn = iser_task->iser_conn->iscsi_conn;
+ struct iser_conn *ib_conn = iser_task->iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
struct ib_device *ibdev = device->ib_device;
- struct iser_data_buf *mem = &iser_ctask->data[cmd_dir];
+ struct iser_data_buf *mem = &iser_task->data[cmd_dir];
struct iser_regd_buf *regd_buf;
int aligned_len;
int err;
int i;
struct scatterlist *sg;
- regd_buf = &iser_ctask->rdma_regd[cmd_dir];
+ regd_buf = &iser_task->rdma_regd[cmd_dir];
aligned_len = iser_data_buf_aligned_len(mem, ibdev);
if (aligned_len != mem->dma_nents) {
iser_data_buf_dump(mem, ibdev);
/* unmap the command data before accessing it */
- iser_dma_unmap_task_data(iser_ctask);
+ iser_dma_unmap_task_data(iser_task);
/* allocate copy buf, if we are writing, copy the */
/* unaligned scatterlist, dma map the copy */
- if (iser_start_rdma_unaligned_sg(iser_ctask, cmd_dir) != 0)
+ if (iser_start_rdma_unaligned_sg(iser_task, cmd_dir) != 0)
return -ENOMEM;
- mem = &iser_ctask->data_copy[cmd_dir];
+ mem = &iser_task->data_copy[cmd_dir];
}
/* if there a single dma entry, FMR is not needed */
err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, ®d_buf->reg);
if (err) {
iser_data_buf_dump(mem, ibdev);
- iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents,
- ntoh24(iser_ctask->desc.iscsi_header.dlength));
+ iser_err("mem->dma_nents = %d (dlength = 0x%x)\n",
+ mem->dma_nents,
+ ntoh24(iser_task->desc.iscsi_header.dlength));
iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n",
ib_conn->page_vec->data_size, ib_conn->page_vec->length,
ib_conn->page_vec->offset);
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
- *
- * $Id: iser_verbs.c 7051 2006-05-10 12:29:11Z ogerlitz $
*/
#include <linux/kernel.h>
#include <linux/module.h>
iser_device_try_release(device);
if (ib_conn->iser_conn)
ib_conn->iser_conn->ib_conn = NULL;
- kfree(ib_conn);
+ iscsi_destroy_endpoint(ib_conn->ep);
+ }
+
+ void iser_conn_get(struct iser_conn *ib_conn)
+ {
+ atomic_inc(&ib_conn->refcount);
+ }
+
+ void iser_conn_put(struct iser_conn *ib_conn)
+ {
+ if (atomic_dec_and_test(&ib_conn->refcount))
+ iser_conn_release(ib_conn);
}
/**
wait_event_interruptible(ib_conn->wait,
ib_conn->state == ISER_CONN_DOWN);
- iser_conn_release(ib_conn);
+ iser_conn_put(ib_conn);
}
static void iser_connect_error(struct rdma_cm_id *cma_id)
return ret;
}
- int iser_conn_init(struct iser_conn **ibconn)
+ void iser_conn_init(struct iser_conn *ib_conn)
{
- struct iser_conn *ib_conn;
-
- ib_conn = kzalloc(sizeof *ib_conn, GFP_KERNEL);
- if (!ib_conn) {
- iser_err("can't alloc memory for struct iser_conn\n");
- return -ENOMEM;
- }
ib_conn->state = ISER_CONN_INIT;
init_waitqueue_head(&ib_conn->wait);
atomic_set(&ib_conn->post_recv_buf_count, 0);
atomic_set(&ib_conn->post_send_buf_count, 0);
+ atomic_set(&ib_conn->refcount, 1);
INIT_LIST_HEAD(&ib_conn->conn_list);
spin_lock_init(&ib_conn->lock);
-
- *ibconn = ib_conn;
- return 0;
}
/**
* For use with LSI PCI chip/adapter(s)
* running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Corporation
+ * Copyright (c) 1999-2008 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
* Public data...
*/
- struct proc_dir_entry *mpt_proc_root_dir;
+ static struct proc_dir_entry *mpt_proc_root_dir;
#define WHOINIT_UNKNOWN 0xAA
return 0;
}
+ /**
+ * mpt_fault_reset_work - work performed on workq after ioc fault
+ * @work: input argument, used to derive ioc
+ *
+ **/
+ static void
+ mpt_fault_reset_work(struct work_struct *work)
+ {
+ MPT_ADAPTER *ioc =
+ container_of(work, MPT_ADAPTER, fault_reset_work.work);
+ u32 ioc_raw_state;
+ int rc;
+ unsigned long flags;
+
+ if (ioc->diagPending || !ioc->active)
+ goto out;
+
+ ioc_raw_state = mpt_GetIocState(ioc, 0);
+ if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+ printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
+ ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+ printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
+ ioc->name, __FUNCTION__);
+ rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
+ printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
+ __FUNCTION__, (rc == 0) ? "success" : "failed");
+ ioc_raw_state = mpt_GetIocState(ioc, 0);
+ if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
+ printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
+ "reset (%04xh)\n", ioc->name, ioc_raw_state &
+ MPI_DOORBELL_DATA_MASK);
+ }
+
+ out:
+ /*
+ * Take turns polling alternate controller
+ */
+ if (ioc->alt_ioc)
+ ioc = ioc->alt_ioc;
+
+ /* rearm the timer */
+ spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+ if (ioc->reset_work_q)
+ queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+ msecs_to_jiffies(MPT_POLLING_INTERVAL));
+ spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+ }
+
+
/*
* Process turbo (context) reply...
*/
/* Find lookup slot. */
INIT_LIST_HEAD(&ioc->list);
+
+ /* Initialize workqueue */
+ INIT_DELAYED_WORK(&ioc->fault_reset_work, mpt_fault_reset_work);
+ spin_lock_init(&ioc->fault_reset_work_lock);
+
+ snprintf(ioc->reset_work_q_name, KOBJ_NAME_LEN, "mpt_poll_%d", ioc->id);
+ ioc->reset_work_q =
+ create_singlethread_workqueue(ioc->reset_work_q_name);
+ if (!ioc->reset_work_q) {
+ printk(MYIOC_s_ERR_FMT "Insufficient memory to add adapter!\n",
+ ioc->name);
+ pci_release_selected_regions(pdev, ioc->bars);
+ kfree(ioc);
+ return -ENOMEM;
+ }
+
dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
ioc->name, &ioc->facts, &ioc->pfacts[0]));
ioc->bus_type = SAS;
}
- if (ioc->bus_type == SAS && mpt_msi_enable == -1)
- ioc->msi_enable = 1;
- else
+ if (mpt_msi_enable == -1) {
+ /* Enable on SAS, disable on FC and SPI */
+ if (ioc->bus_type == SAS)
+ ioc->msi_enable = 1;
+ else
+ ioc->msi_enable = 0;
+ } else
+ /* follow flag: 0 - disable; 1 - enable */
ioc->msi_enable = mpt_msi_enable;
if (ioc->errata_flag_1064)
iounmap(ioc->memmap);
if (r != -5)
pci_release_selected_regions(pdev, ioc->bars);
+
+ destroy_workqueue(ioc->reset_work_q);
+ ioc->reset_work_q = NULL;
+
kfree(ioc);
pci_set_drvdata(pdev, NULL);
return r;
}
#endif
+ if (!ioc->alt_ioc)
+ queue_delayed_work(ioc->reset_work_q, &ioc->fault_reset_work,
+ msecs_to_jiffies(MPT_POLLING_INTERVAL));
+
return 0;
}
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
char pname[32];
u8 cb_idx;
+ unsigned long flags;
+ struct workqueue_struct *wq;
+
+ /*
+ * Stop polling ioc for fault condition
+ */
+ spin_lock_irqsave(&ioc->fault_reset_work_lock, flags);
+ wq = ioc->reset_work_q;
+ ioc->reset_work_q = NULL;
+ spin_unlock_irqrestore(&ioc->fault_reset_work_lock, flags);
+ cancel_delayed_work(&ioc->fault_reset_work);
+ destroy_workqueue(wq);
+
sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
remove_proc_entry(pname, NULL);
EXPORT_SYMBOL(mpt_suspend);
#endif
EXPORT_SYMBOL(ioc_list);
- EXPORT_SYMBOL(mpt_proc_root_dir);
EXPORT_SYMBOL(mpt_register);
EXPORT_SYMBOL(mpt_deregister);
EXPORT_SYMBOL(mpt_event_register);
* For use with LSI PCI chip/adapters
* running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Corporation
+ * Copyright (c) 1999-2008 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
- #define COPYRIGHT "Copyright (c) 1999-2007 LSI Corporation"
+ #define COPYRIGHT "Copyright (c) 1999-2008 LSI Corporation"
#define MODULEAUTHOR "LSI Corporation"
#include "mptbase.h"
#include "mptctl.h"
mptctl_fasync(int fd, struct file *filep, int mode)
{
MPT_ADAPTER *ioc;
+ int ret;
+ lock_kernel();
list_for_each_entry(ioc, &ioc_list, list)
ioc->aen_event_read_flag=0;
- return fasync_helper(fd, filep, mode, &async_queue);
+ ret = fasync_helper(fd, filep, mode, &async_queue);
+ unlock_kernel();
+ return ret;
}
static int
* For use with LSI PCI chip/adapter(s)
* running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Corporation
+ * Copyright (c) 1999-2008 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
spi_offset(starget) = 0;
+ spi_period(starget) = 0xFF;
mptspi_write_width(starget, 0);
return 0;
static int
mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
- struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
int rc;
rc = mptscsih_ioc_reset(ioc, reset_phase);
- if (reset_phase == MPT_IOC_POST_RESET)
+ /* only try to do a renegotiation if we're properly set up
+ * if we get an ioc fault on bringup, ioc->sh will be NULL */
+ if (reset_phase == MPT_IOC_POST_RESET &&
+ ioc->sh) {
+ struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+
mptspi_dv_renegotiate(hd);
+ }
return rc;
}
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/delay.h>
unsigned minor_number = iminor(inode);
int err = -ENODEV;
+ lock_kernel(); /* BKL pushdown: nothing else protects this list */
list_for_each_entry(aac, &aac_devices, entry) {
if (aac->id == minor_number) {
file->private_data = aac;
break;
}
}
+ unlock_kernel();
return err;
}
return len;
}
- ssize_t aac_show_serial_number(struct device *device,
+ static ssize_t aac_show_serial_number(struct device *device,
struct device_attribute *attr, char *buf)
{
struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata;
/* Now reset the ESP chip */
scsi_esp_cmd(esp, ESP_CMD_RC);
scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+ if (esp->rev == FAST)
+ esp_write8(ESP_CONFIG2_FENAB, ESP_CFG2);
scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
- /* Reload the configuration registers */
- esp_write8(esp->cfact, ESP_CFACT);
-
- esp->prev_stp = 0;
- esp_write8(esp->prev_stp, ESP_STP);
-
- esp->prev_soff = 0;
- esp_write8(esp->prev_soff, ESP_SOFF);
-
- esp_write8(esp->neg_defp, ESP_TIMEO);
-
/* This is the only point at which it is reliable to read
* the ID-code for a fast ESP chip variants.
*/
break;
}
+ /* Reload the configuration registers */
+ esp_write8(esp->cfact, ESP_CFACT);
+
+ esp->prev_stp = 0;
+ esp_write8(esp->prev_stp, ESP_STP);
+
+ esp->prev_soff = 0;
+ esp_write8(esp->prev_soff, ESP_SOFF);
+
+ esp_write8(esp->neg_defp, ESP_TIMEO);
+
/* Eat any bitrot in the chip */
esp_read8(ESP_INTRPT);
udelay(100);
}
EXPORT_SYMBOL(scsi_esp_unregister);
+static int esp_target_alloc(struct scsi_target *starget)
+{
+ struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
+ struct esp_target_data *tp = &esp->target[starget->id];
+
+ tp->starget = starget;
+
+ return 0;
+}
+
+static void esp_target_destroy(struct scsi_target *starget)
+{
+ struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
+ struct esp_target_data *tp = &esp->target[starget->id];
+
+ tp->starget = NULL;
+}
+
static int esp_slave_alloc(struct scsi_device *dev)
{
struct esp *esp = shost_priv(dev->host);
return -ENOMEM;
dev->hostdata = lp;
- tp->starget = dev->sdev_target;
-
spi_min_period(tp->starget) = esp->min_period;
spi_max_offset(tp->starget) = 15;
.name = "esp",
.info = esp_info,
.queuecommand = esp_queuecommand,
+ .target_alloc = esp_target_alloc,
+ .target_destroy = esp_target_destroy,
.slave_alloc = esp_slave_alloc,
.slave_configure = esp_slave_configure,
.slave_destroy = esp_slave_destroy,
kfree(shost);
}
- struct device_type scsi_host_type = {
+ static struct device_type scsi_host_type = {
.name = "scsi_host",
.release = scsi_host_dev_release,
};
*
* Return value:
* A pointer to located Scsi_Host or NULL.
+ *
+ * The caller must do a scsi_host_put() to drop the reference
+ * that scsi_host_get() took. The put_device() below dropped
+ * the reference from class_find_device().
**/
struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
{
struct Scsi_Host *shost = ERR_PTR(-ENXIO);
cdev = class_find_device(&shost_class, &hostnum, __scsi_host_match);
- if (cdev)
+ if (cdev) {
shost = scsi_host_get(class_to_shost(cdev));
-
+ put_device(cdev);
+ }
return shost;
}
EXPORT_SYMBOL(scsi_host_lookup);
};
#undef SP
- static struct kmem_cache *scsi_bidi_sdb_cache;
+ static struct kmem_cache *scsi_sdb_cache;
static void scsi_run_queue(struct request_queue *q);
*/
blk_execute_rq(req->q, NULL, req, 1);
+ /*
+ * Some devices (USB mass-storage in particular) may transfer
+ * garbage data together with a residue indicating that the data
+ * is invalid. Prevent the garbage from being misinterpreted
+ * and prevent security leaks by zeroing out the excess data.
+ */
+ if (unlikely(req->data_len > 0 && req->data_len <= bufflen))
+ memset(buffer + (bufflen - req->data_len), 0, req->data_len);
+
ret = req->errors;
out:
blk_put_request(req);
struct scsi_data_buffer *bidi_sdb =
cmd->request->next_rq->special;
scsi_free_sgtable(bidi_sdb);
- kmem_cache_free(scsi_bidi_sdb_cache, bidi_sdb);
+ kmem_cache_free(scsi_sdb_cache, bidi_sdb);
cmd->request->next_rq->special = NULL;
}
}
if (blk_bidi_rq(cmd->request)) {
struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc(
- scsi_bidi_sdb_cache, GFP_ATOMIC);
+ scsi_sdb_cache, GFP_ATOMIC);
if (!bidi_sdb) {
error = BLKPREP_DEFER;
goto err_exit;
if (ret != BLKPREP_OK)
return ret;
+
+ if (unlikely(sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh
+ && sdev->scsi_dh_data->scsi_dh->prep_fn)) {
+ ret = sdev->scsi_dh_data->scsi_dh->prep_fn(sdev, req);
+ if (ret != BLKPREP_OK)
+ return ret;
+ }
+
/*
* Filesystem requests must transfer data.
*/
printk("scsi%d unblocking host at zero depth\n",
shost->host_no));
} else {
- blk_plug_device(q);
return 0;
}
}
return -ENOMEM;
}
- scsi_bidi_sdb_cache = kmem_cache_create("scsi_bidi_sdb",
- sizeof(struct scsi_data_buffer),
- 0, 0, NULL);
- if (!scsi_bidi_sdb_cache) {
- printk(KERN_ERR "SCSI: can't init scsi bidi sdb cache\n");
+ scsi_sdb_cache = kmem_cache_create("scsi_data_buffer",
+ sizeof(struct scsi_data_buffer),
+ 0, 0, NULL);
+ if (!scsi_sdb_cache) {
+ printk(KERN_ERR "SCSI: can't init scsi sdb cache\n");
goto cleanup_io_context;
}
if (!sgp->slab) {
printk(KERN_ERR "SCSI: can't init sg slab %s\n",
sgp->name);
- goto cleanup_bidi_sdb;
+ goto cleanup_sdb;
}
sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE,
if (!sgp->pool) {
printk(KERN_ERR "SCSI: can't init sg mempool %s\n",
sgp->name);
- goto cleanup_bidi_sdb;
+ goto cleanup_sdb;
}
}
return 0;
- cleanup_bidi_sdb:
+ cleanup_sdb:
for (i = 0; i < SG_MEMPOOL_NR; i++) {
struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
if (sgp->pool)
if (sgp->slab)
kmem_cache_destroy(sgp->slab);
}
- kmem_cache_destroy(scsi_bidi_sdb_cache);
+ kmem_cache_destroy(scsi_sdb_cache);
cleanup_io_context:
kmem_cache_destroy(scsi_io_context_cache);
int i;
kmem_cache_destroy(scsi_io_context_cache);
- kmem_cache_destroy(scsi_bidi_sdb_cache);
+ kmem_cache_destroy(scsi_sdb_cache);
for (i = 0; i < SG_MEMPOOL_NR; i++) {
struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsicam.h>
- #include <scsi/sd.h>
+ #include "sd.h"
#include "scsi_logging.h"
MODULE_AUTHOR("Eric Youngdale");
}
}
- static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
- {
- return container_of(disk->private_data, struct scsi_disk, driver);
- }
-
static struct scsi_disk *__scsi_disk_get(struct gendisk *disk)
{
struct scsi_disk *sdkp = NULL;
cmd[1] = 1; /* Return immediately */
memset((void *) &cmd[2], 0, 8);
cmd[4] = 1; /* Start spin cycle */
+ if (sdkp->device->start_stop_pwr_cond)
+ cmd[4] |= 1 << 4;
scsi_execute_req(sdkp->device, cmd, DMA_NONE,
NULL, 0, &sshdr,
SD_TIMEOUT, SD_MAX_RETRIES);
if (start)
cmd[4] |= 1; /* START */
+ if (sdp->start_stop_pwr_cond)
+ cmd[4] |= start ? 1 << 4 : 3 << 4; /* Active or Standby */
+
if (!scsi_device_online(sdp))
return -ENODEV;
#include <linux/delay.h>
#include <linux/scatterlist.h>
#include <linux/blktrace_api.h>
+#include <linux/smp_lock.h>
#include "scsi.h"
#include <scsi/scsi_dbg.h>
int tablesize);
static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
Sg_request * srp);
-static ssize_t sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
- int blocking, int read_only, Sg_request ** o_srp);
+static ssize_t sg_new_write(Sg_fd *sfp, struct file *file,
+ const char __user *buf, size_t count, int blocking,
+ int read_only, Sg_request **o_srp);
static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
unsigned char *cmnd, int timeout, int blocking);
static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
static Sg_request *sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
static int sg_res_in_use(Sg_fd * sfp);
-static int sg_allow_access(unsigned char opcode, char dev_type);
static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
static Sg_device *sg_get_dev(int dev);
#ifdef CONFIG_SCSI_PROC_FS
int res;
int retval;
+ lock_kernel();
nonseekable_open(inode, filp);
SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
sdp = sg_get_dev(dev);
- if ((!sdp) || (!sdp->device))
+ if ((!sdp) || (!sdp->device)) {
+ unlock_kernel();
return -ENXIO;
- if (sdp->detached)
+ }
+ if (sdp->detached) {
+ unlock_kernel();
return -ENODEV;
+ }
/* This driver's module count bumped by fops_get in <linux/fs.h> */
/* Prevent the device driver from vanishing while we sleep */
retval = scsi_device_get(sdp->device);
- if (retval)
+ if (retval) {
+ unlock_kernel();
return retval;
+ }
if (!((flags & O_NONBLOCK) ||
scsi_block_when_processing_errors(sdp->device))) {
retval = -ENOMEM;
goto error_out;
}
+ unlock_kernel();
return 0;
error_out:
scsi_device_put(sdp->device);
+ unlock_kernel();
return retval;
}
return -EFAULT;
blocking = !(filp->f_flags & O_NONBLOCK);
if (old_hdr.reply_len < 0)
- return sg_new_write(sfp, buf, count, blocking, 0, NULL);
+ return sg_new_write(sfp, filp, buf, count, blocking, 0, NULL);
if (count < (SZ_SG_HEADER + 6))
return -EIO; /* The minimum scsi command length is 6 bytes. */
}
static ssize_t
-sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
- int blocking, int read_only, Sg_request ** o_srp)
+sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
+ size_t count, int blocking, int read_only,
+ Sg_request **o_srp)
{
int k;
Sg_request *srp;
sg_remove_request(sfp, srp);
return -EFAULT;
}
- if (read_only &&
- (!sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
+ if (read_only && !blk_verify_command(file, cmnd)) {
sg_remove_request(sfp, srp);
return -EPERM;
}
if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
return -EFAULT;
result =
- sg_new_write(sfp, p, SZ_SG_IO_HDR,
+ sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
blocking, read_only, &srp);
if (result < 0)
return result;
case SG_SCSI_RESET_DEVICE:
val = SCSI_TRY_RESET_DEVICE;
break;
+ case SG_SCSI_RESET_TARGET:
+ val = SCSI_TRY_RESET_TARGET;
+ break;
case SG_SCSI_RESET_BUS:
val = SCSI_TRY_RESET_BUS;
break;
if (copy_from_user(&opcode, siocp->data, 1))
return -EFAULT;
- if (!sg_allow_access(opcode, sdp->device->type))
+ if (!blk_verify_command(filp, &opcode))
return -EPERM;
}
return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p);
__free_pages(page, order);
}
-#ifndef MAINTENANCE_IN_CMD
-#define MAINTENANCE_IN_CMD 0xa3
-#endif
-
-static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE,
- INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
- READ_16, MODE_SENSE, MODE_SENSE_10, LOG_SENSE, REPORT_LUNS,
- SERVICE_ACTION_IN, RECEIVE_DIAGNOSTIC, READ_LONG, MAINTENANCE_IN_CMD
-};
-
-static int
-sg_allow_access(unsigned char opcode, char dev_type)
-{
- int k;
-
- if (TYPE_SCANNER == dev_type) /* TYPE_ROM maybe burner */
- return 1;
- for (k = 0; k < sizeof (allow_ops); ++k) {
- if (opcode == allow_ops[k])
- return 1;
- }
- return 0;
-}
-
#ifdef CONFIG_SCSI_PROC_FS
static int
sg_idr_max_id(int id, void *p, void *data)
unsigned no_start_on_add:1; /* do not issue start on add */
unsigned allow_restart:1; /* issue START_UNIT in error handler */
unsigned manage_start_stop:1; /* Let HLD (sd) manage start/stop */
+ unsigned start_stop_pwr_cond:1; /* Set power cond. in START_STOP_UNIT */
unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
unsigned select_no_atn:1;
unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */
struct execute_work ew; /* used to get process context on put */
+ struct scsi_dh_data *scsi_dh_data;
enum scsi_device_state sdev_state;
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
+
+ struct scsi_device_handler {
+ /* Used by the infrastructure */
+ struct list_head list; /* list of scsi_device_handlers */
+ struct notifier_block nb;
+
+ /* Filled by the hardware handler */
+ struct module *module;
+ const char *name;
+ int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
+ int (*activate)(struct scsi_device *);
+ int (*prep_fn)(struct scsi_device *, struct request *);
+ };
+
+ struct scsi_dh_data {
+ struct scsi_device_handler *scsi_dh;
+ char buf[0];
+ };
+
#define to_scsi_device(d) \
container_of(d, struct scsi_device, sdev_gendev)
#define class_to_sdev(d) \
uint, uint, uint, void *hostdata);
extern int scsi_add_device(struct Scsi_Host *host, uint channel,
uint target, uint lun);
+ extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh);
extern void scsi_remove_device(struct scsi_device *);
+ extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
sha1.o irq_regs.o reciprocal_div.o argv_split.o \
proportions.o prio_heap.o ratelimit.o
+ifdef CONFIG_FTRACE
+# Do not profile string.o, since it may be used in early boot or vdso
+CFLAGS_REMOVE_string.o = -pg
+# Also do not profile any debug utilities
+CFLAGS_REMOVE_spinlock_debug.o = -pg
+CFLAGS_REMOVE_list_debug.o = -pg
+CFLAGS_REMOVE_debugobjects.o = -pg
+endif
+
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
obj-$(CONFIG_CRC16) += crc16.o
+ obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o
obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o
obj-$(CONFIG_CRC32) += crc32.o
obj-$(CONFIG_CRC7) += crc7.o