public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/10][RFC] linux-iscsi driver
@ 2005-01-10 22:57 Mike Christie
  0 siblings, 0 replies; only message in thread
From: Mike Christie @ 2005-01-10 22:57 UTC (permalink / raw)
  To: linux-scsi

[-- Attachment #1: Type: text/plain, Size: 80 bytes --]

Driver file implementing the SCSI template functions
and module initialization.

[-- Attachment #2: 03-scsi-tmpl.patch --]
[-- Type: text/x-patch, Size: 21100 bytes --]

diff -Naurp scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-initiator.c scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-initiator.c
--- scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-initiator.c	1969-12-31 16:00:00.000000000 -0800
+++ scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-initiator.c	2005-01-10 12:19:58.490683743 -0800
@@ -0,0 +1,581 @@
+/*
+ * iSCSI driver for Linux
+ * Copyright (C) 2001 Cisco Systems, Inc.
+ * Copyright (C) 2004 Mike Christie
+ * Copyright (C) 2004 IBM Corporation
+ * maintained by linux-iscsi-devel@lists.sourceforge.net
+ *
+ * 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.
+ *
+ * This file contains interfaces required by SCSI mid layer, module
+ * initialization and shutdown routines.
+ */
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/in.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#include "iscsi-sfnet.h"
+#include "iscsi-session.h"
+#include "iscsi-protocol.h"
+#include "iscsi-task.h"
+
+/*
+ *  IMPORTANT NOTE: to prevent deadlock, when holding multiple locks,
+ *  the following locking order must be followed at all times:
+ *
+ *  session->portal_lock      - access to a session's portal info
+ *  session->task_lock        - access to a session's collections of tasks
+ *  host_lock                 - mid-layer acquires before calling queuecommand,
+ * 				and eh_*.
+ *
+ *  Note for grabbing task_lock: queuecommand and eh_timed_out are invoked in
+ *  soft_irq context. The former can be invoked in process context as well. 
+ *  Every other function where we grab task_lock, we have process context.
+ *  Hence we use spin_lock in eh_timed_out and spin_lock_bh every where else to
+ *  grab the task lock.
+ */
+
+MODULE_AUTHOR("Cisco Systems, Inc.");
+MODULE_DESCRIPTION("iSCSI initiator");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ISCSI_DRIVER_VERSION);
+
+kmem_cache_t *iscsi_task_cache;
+static struct scsi_transport_template *iscsi_transportt;
+
+/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
+#define SNA32_CHECK 2147483648UL
+
+int
+iscsi_sna_lt(u32 n1, u32 n2)
+{
+	return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
+			    (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
+}
+
+/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
+int
+iscsi_sna_lte(u32 n1, u32 n2)
+{
+	return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
+			    (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
+}
+
+/* mark a scsi_cmnd as having a LUN communication failure */
+static inline void
+set_lun_comm_failure(struct scsi_cmnd *sc)
+{
+	sc->sense_buffer[0] = 0x70;
+	sc->sense_buffer[2] = NOT_READY;
+	sc->sense_buffer[7] = 0x6;
+	sc->sense_buffer[12] = 0x08;
+	sc->sense_buffer[13] = 0x00;
+}
+
+u32
+iscsi_command_attr(struct scsi_cmnd *cmd)
+{
+	unsigned int attr = ISCSI_ATTR_UNTAGGED;
+	char msg[2];
+
+	if (scsi_populate_tag_msg(cmd, msg) == 2) {
+		switch (msg[0]) {
+		case MSG_SIMPLE_TAG:
+			attr = ISCSI_ATTR_SIMPLE;
+			break;
+		case MSG_HEAD_TAG:
+			attr = ISCSI_ATTR_HEAD_OF_QUEUE;
+			break;
+		case MSG_ORDERED_TAG:
+			attr = ISCSI_ATTR_ORDERED;
+			break;
+		};
+	}
+
+	return attr;
+}
+
+static int
+iscsi_slave_configure(struct scsi_device *sdev)
+{
+	int depth = 1, tag = 0;
+
+        /*
+	 * TODO (one day) - when tcq is not supported we should
+	 * internally queue a command to have one ready to go right
+	 * away when the outstanding one completes.
+         */
+	if (sdev->tagged_supported) {
+		scsi_activate_tcq(sdev, ISCSI_CMDS_PER_LUN);
+		depth = ISCSI_CMDS_PER_LUN;
+		tag = MSG_ORDERED_TAG;
+	}
+
+	scsi_adjust_queue_depth(sdev, tag, depth);
+	return 0;
+}
+
+/**
+ * iscsi_eh_timed_out - handle scsi command timeouts
+ * sc: scsi command
+ *
+ * Note:
+ *    In the normal case where the session is ok or the command was queued
+ *    when the session was down (and it never came up but did not yet timeout
+ *    - TODO use device block/unblock), we will fail the command here if
+ *    we can. For all other race cases where for example the session changed
+ *    state at the same time the command timed out but we had the task lock
+ *    we just ask for more time since those events will clean themselves up.
+ **/
+static enum scsi_eh_timer_return
+iscsi_eh_timed_out(struct scsi_cmnd *sc)
+{
+	struct Scsi_Host *shost = sc->device->host;
+	struct iscsi_session *session = (struct iscsi_session *)shost->hostdata;
+	struct iscsi_task *task;
+	enum scsi_eh_timer_return ret = EH_RESET_TIMER;
+	int result = DID_BUS_BUSY << 16;
+
+	spin_lock(&session->task_lock);
+
+	task = (struct iscsi_task *)sc->SCp.ptr;
+	if (!task) {
+		/*
+		 * completed while timer was firing
+		 */
+		ret = EH_HANDLED;
+		goto done;
+	}
+
+	if (test_bit(SESSION_ESTABLISHED, &session->control_bits))
+		ret = EH_NOT_HANDLED;
+	else if (test_bit(SESSION_REPLACEMENT_TIMEDOUT, &session->control_bits))
+		result = DID_NO_CONNECT << 16;
+
+	if (task->itt == ISCSI_RSVD_TASK_TAG) {
+		sc->result = result;
+		__iscsi_complete_task(task);
+		ret = EH_HANDLED;
+	}
+
+ done:
+	spin_unlock(&session->task_lock);
+
+	return ret;
+}
+
+static int
+iscsi_eh_abort(struct scsi_cmnd *sc)
+{
+	struct Scsi_Host *shost = sc->device->host;
+	struct iscsi_session *session = (struct iscsi_session *)shost->hostdata;
+	struct iscsi_task *task, *tmf_task;
+	int ret = FAILED;
+
+	spin_unlock_irq(shost->host_lock);
+	spin_lock_bh(&session->task_lock);
+
+	/*
+	 * TODO must fix these type of tests
+	 */
+	if (!test_bit(SESSION_ESTABLISHED, &session->control_bits))
+		goto done;
+
+	task = (struct iscsi_task *)sc->SCp.ptr;
+	if (!task) {
+		iscsi_host_err(session, "eh_abort cmnd already done\n");
+		ret = SUCCESS;
+		goto done;
+	}
+
+	if (task->itt == ISCSI_RSVD_TASK_TAG) {
+		__iscsi_complete_task(task);
+		ret = SUCCESS;
+		goto done;
+	}
+
+	/*
+	 * TODO need a iscsi_dev_info
+	 */
+	iscsi_host_info(session, "Sending ABORT TASK for task itt %u\n",
+			task->itt);
+
+	tmf_task = session->mgmt_task;
+	memset(tmf_task, 0, sizeof(*tmf_task));
+	iscsi_init_task(tmf_task);
+	tmf_task->session = session;
+	tmf_task->lun = task->lun;
+	/*
+	 * this will become the refcmdsn
+	 */
+	tmf_task->cmdsn = task->cmdsn;
+	tmf_task->rtt = task->itt;
+	set_bit(ISCSI_TASK_ABORT, &tmf_task->flags);
+
+	if (!iscsi_exec_task_mgmt(tmf_task, session->abort_timeout)) {
+		ret = SUCCESS;
+		goto done;
+	}
+	/*
+	 * TMF may have failed if the task completed first (check here)
+	 */
+	if (!sc->SCp.ptr)
+		ret = SUCCESS;
+ done:
+	spin_unlock_bh(&session->task_lock);
+	spin_lock_irq(shost->host_lock);
+
+	return ret;
+}
+
+static int
+iscsi_eh_device_reset(struct scsi_cmnd *sc)
+{
+	struct Scsi_Host *shost = sc->device->host;
+	struct iscsi_session *session = (struct iscsi_session *)shost->hostdata;
+	struct iscsi_task *task;
+	int ret = FAILED;
+
+	spin_unlock_irq(shost->host_lock);
+	spin_lock_bh(&session->task_lock);
+
+	if (!test_bit(SESSION_ESTABLISHED, &session->control_bits))
+		goto done;
+
+	task = session->mgmt_task;
+	memset(task, 0, sizeof(*task));
+	iscsi_init_task(task);
+	task->session = session;
+	task->lun = sc->device->lun;
+	__set_bit(ISCSI_TASK_ABORT_TASK_SET, &task->flags);
+
+	/*
+	 * need a iscsi_dev_info
+	 */
+	iscsi_host_info(session, "Sending ABORT TASK SET\n");
+	if (!iscsi_exec_task_mgmt(task, session->abort_timeout)) {
+		ret = SUCCESS;
+		goto done;
+	}
+
+	iscsi_init_task(task);
+	__set_bit(ISCSI_TASK_LU_RESET, &task->flags);
+
+	iscsi_host_info(session, "Sending LU RESET\n");
+ 	if (!iscsi_exec_task_mgmt(task, session->reset_timeout))
+		ret = SUCCESS;
+ done:
+	spin_unlock_bh(&session->task_lock);
+	spin_lock_irq(shost->host_lock);
+
+	return ret;
+}
+
+static int
+iscsi_eh_host_reset(struct scsi_cmnd *sc)
+{
+	struct Scsi_Host *shost = sc->device->host;
+	struct iscsi_session *session = (struct iscsi_session *)shost->hostdata;
+	struct iscsi_task *task;
+	int ret = FAILED;
+
+	spin_unlock_irq(shost->host_lock);
+	spin_lock_bh(&session->task_lock);
+
+	if (!test_bit(SESSION_ESTABLISHED, &session->control_bits))
+		goto done;
+
+	task = session->mgmt_task;
+	memset(task, 0, sizeof(*task));
+	iscsi_init_task(task);
+	task->session = session;
+	__set_bit(ISCSI_TASK_TGT_WARM_RESET, &task->flags);
+
+	iscsi_host_info(session, "Sending TARGET WARM RESET\n");
+	if (iscsi_exec_task_mgmt(task, session->reset_timeout))
+		/*
+		 * no other options
+		 */
+		iscsi_drop_session(session);
+
+ done:
+	/*
+	 * if we failed, scsi-ml will put us offline
+	 * and if we were successful it will redrive the
+	 * commands, so we clean everything up from our side
+	 * so scsi-ml can retake ownership of the commands.
+	 * (At this point the tx and rx threads will not be
+	 * touching the commands since either the session
+	 * was dropped or we just did a target reset)
+	 */
+	iscsi_flush_queues(session, ISCSI_MAX_LUNS, DID_BUS_BUSY);
+
+	spin_unlock_bh(&session->task_lock);
+	if (iscsi_wait_for_session(session, 0))
+		ret = SUCCESS;
+	spin_lock_irq(shost->host_lock);
+
+	return ret;
+}
+
+void
+iscsi_complete_command(struct scsi_cmnd *sc)
+{
+	sc->SCp.ptr = NULL;
+	sc->scsi_done(sc);
+}
+
+/**
+ * iscsi_queuecommand - queuecommand interface for the iSCSI driver.
+ * @sc: scsi command from the midlayer
+ * @done: Call back function to be called once the command is executed.
+ **/
+static int
+iscsi_queuecommand(struct scsi_cmnd *sc, void (*done) (struct scsi_cmnd *))
+{
+	struct Scsi_Host *host = sc->device->host;
+	struct iscsi_session *session = (struct iscsi_session *)host->hostdata;
+	struct iscsi_task *task;
+	int ret = 0;
+
+	spin_unlock_irq(host->host_lock);
+
+	/*
+	 * record whether I/O commands have been ever been sent on this
+	 * session, to help us decide when we need the  session and should
+	 * retry logins regardless of the login status. Ignore all the
+	 * commands sent by default as part of the LUN being scanned or a
+	 * device being opened, so that sessions that have always been idle
+	 * can be dropped.  Of course, this  is always true for disks, since
+	 * Linux will do reads  looking for a partition table.
+	 */
+	switch (sc->cmnd[0]) {
+	case INQUIRY:
+	case REPORT_LUNS:
+	case TEST_UNIT_READY:
+	case READ_CAPACITY:
+	case START_STOP:
+	case MODE_SENSE:
+		break;
+	default:
+		session->commands_queued = 1;
+		break;
+	}
+
+	if (test_bit(SESSION_REPLACEMENT_TIMEDOUT, &session->control_bits)) {
+		if (printk_ratelimit())
+			iscsi_host_warn(session, "lun%u: Session terminating, "
+					"failing to queue cdb 0x%x and any "
+					"following commands\n", sc->device->lun,					sc->cmnd[0]);
+		goto fail;
+	}
+
+	/* make sure we can complete it properly later */
+	sc->scsi_done = done;
+	sc->result = 0;
+	memset(&sc->SCp, 0, sizeof(sc->SCp));
+
+	spin_lock_bh(&session->task_lock);
+
+	/*
+	 * alloc a task and add it to the pending queue so
+	 * the tx-thread will run it
+	 */ 
+	task = iscsi_alloc_task(session);
+	if (!task) {
+		ret = SCSI_MLQUEUE_HOST_BUSY;
+		goto done;
+	}
+
+	task->lun = sc->device->lun;
+	task->scsi_cmnd = sc;
+	sc->SCp.ptr = (char *)task;
+	list_add_tail(&task->queue, &session->pending_queue);
+
+	iscsi_wake_tx_thread(TX_SCSI_COMMAND, session);
+ done:
+	spin_unlock_bh(&session->task_lock);
+	spin_lock_irq(host->host_lock);
+	return ret;
+
+ fail:
+	spin_lock_irq(host->host_lock);
+	sc->result = DID_NO_CONNECT << 16;
+	sc->resid = sc->request_bufflen;
+	set_lun_comm_failure(sc);
+
+	done(sc);
+	return 0;
+}
+
+int
+iscsi_destroy_host(struct Scsi_Host *shost)
+{
+	struct iscsi_session *session = (struct iscsi_session *)shost->hostdata;
+
+	if (!test_bit(SESSION_CREATED, &session->control_bits))
+		return -EINVAL;
+
+	if (test_and_set_bit(SESSION_RELEASING, &session->control_bits))
+		return -EINVAL;
+
+	scsi_remove_host(shost);
+	iscsi_destroy_session(session);
+	scsi_host_put(shost);
+	return 0;
+}
+
+static struct scsi_host_template iscsi_driver_template = {
+	.name = "SFNet iSCSI driver",
+	.proc_name = ISCSI_PROC_NAME,
+	.module = THIS_MODULE,
+	.queuecommand = iscsi_queuecommand,
+	.eh_timed_out = iscsi_eh_timed_out,
+	.eh_abort_handler = iscsi_eh_abort,
+	.eh_device_reset_handler = iscsi_eh_device_reset,
+	.eh_host_reset_handler = iscsi_eh_host_reset,
+	.skip_settle_delay = 1,
+	.slave_configure = iscsi_slave_configure,
+	.this_id = -1,
+	.can_queue = ISCSI_CANQUEUE,
+	.sg_tablesize = ISCSI_MAX_SG,
+	.cmd_per_lun = ISCSI_CMDS_PER_LUN,
+	.use_clustering = ENABLE_CLUSTERING,
+	.max_sectors = 256,
+	.emulated = 1,
+	.shost_attrs = iscsi_host_attrs,
+};
+
+int
+iscsi_create_host(struct iscsi_session_ioctl *ioctld)
+{
+	struct Scsi_Host *shost;
+	struct iscsi_session *session;
+	int rc;
+
+	shost = scsi_host_alloc(&iscsi_driver_template, sizeof(*session));
+	if (!shost) 
+		return -ENOMEM;
+
+	shost->max_id = ISCSI_MAX_TARGETS;
+	shost->max_lun = ISCSI_MAX_LUNS;
+	shost->max_channel = ISCSI_MAX_CHANNELS;
+	shost->max_cmd_len = ISCSI_MAX_CMD_LEN;
+	shost->transportt = iscsi_transportt;
+
+	session = (struct iscsi_session *)shost->hostdata;
+	memset(session, 0, sizeof(*session));
+	session->shost = shost;
+
+	rc = iscsi_create_session(session, ioctld);
+	if (rc) {
+		scsi_host_put(shost);
+		return rc;
+	}
+
+	rc = scsi_add_host(shost, NULL);
+	if (rc) {
+		iscsi_destroy_session(session);
+		scsi_host_put(shost);
+		return rc;
+	}
+
+	scsi_scan_host(shost);
+	set_bit(SESSION_CREATED, &session->control_bits);
+
+	return 0;
+}
+
+/*
+ * This function must only be called when the sysfs and
+ * ioctl interfaces are inaccessible. For example when
+ * the module_exit function is executed the driver's sysfs
+ * and ioctl entry points will return "no device".
+ */
+static void
+iscsi_destroy_all_hosts(void)
+{
+	struct iscsi_session *session, *tmp;
+
+	list_for_each_entry_safe(session, tmp, &iscsi_sessions, list)
+		iscsi_destroy_host(session->shost);
+}
+
+static int
+iscsi_reboot_notifier_function(struct notifier_block *this,
+			       unsigned long code, void *unused)
+{
+	iscsi_destroy_all_hosts();
+	iscsi_notice("Driver shutdown completed\n");
+	return NOTIFY_DONE;
+}
+
+/* XXX move this to driver model shutdown */
+static struct notifier_block iscsi_reboot_notifier = {
+	.notifier_call = iscsi_reboot_notifier_function,
+	.next = NULL,
+	.priority = 255, /* priority, might need to have a
+			  * relook at the value
+			  */
+};
+
+static int
+__init iscsi_init(void)
+{
+	iscsi_notice("%s (%s) built for Linux %s\n", ISCSI_DRIVER_VERSION,
+		     ISCSI_DATE, UTS_RELEASE);
+
+	/* pool of iscsi tasks */
+	iscsi_task_cache = kmem_cache_create("iscsi_task_cache",
+					     sizeof(struct iscsi_task), 0,
+					     SLAB_NO_REAP, NULL, NULL);
+
+	if (!iscsi_task_cache) {
+		iscsi_err("kmem_cache_create failed\n");
+		return -ENOMEM;
+	}
+
+	iscsi_transportt = iscsi_attach_transport(&iscsi_fnt);
+	if (!iscsi_transportt)
+		goto free_cache;
+
+	if (iscsi_register_interface())
+		goto release_transport;
+
+	register_reboot_notifier(&iscsi_reboot_notifier);
+	return 0;
+
+ release_transport:
+	iscsi_release_transport(iscsi_transportt);
+ free_cache:
+	kmem_cache_destroy(iscsi_task_cache);
+	iscsi_err("Failed to init driver\n");
+	return -ENODEV;
+}
+
+static void
+__exit iscsi_cleanup(void)
+{
+	unregister_reboot_notifier(&iscsi_reboot_notifier);
+	iscsi_unregister_interface();
+	iscsi_destroy_all_hosts();
+	iscsi_release_transport(iscsi_transportt);
+	kmem_cache_destroy(iscsi_task_cache);
+}
+module_init(iscsi_init);
+module_exit(iscsi_cleanup);
diff -Naurp scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-sfnet.h scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-sfnet.h
--- scsi-misc-2.6.orig/drivers/scsi/iscsi-sfnet/iscsi-sfnet.h	1969-12-31 16:00:00.000000000 -0800
+++ scsi-misc-2.6.patch/drivers/scsi/iscsi-sfnet/iscsi-sfnet.h	2005-01-10 12:20:05.306809612 -0800
@@ -0,0 +1,130 @@
+/*
+ * iSCSI driver for Linux
+ * Copyright (C) 2001 Cisco Systems, Inc.
+ * Copyright (C) 2004 Mike Christie
+ * Copyright (C) 2004 IBM Corporation
+ * maintained by linux-iscsi-devel@lists.sourceforge.net
+ *
+ * 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.
+ *
+ * Misc definitions for the iSCSI kernel module
+ */
+#ifndef ISCSI_SFNET_H_
+#define ISCSI_SFNET_H_
+
+#include <linux/socket.h>
+#include <linux/random.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+struct iscsi_session;
+struct iscsi_session_ioctl;
+struct iscsi_task;
+struct iscsi_hdr;
+
+#define ISCSI_DRIVER_VERSION	"4:0.1.10.1"
+#define ISCSI_DATE		"3-Jan-2005"
+
+/* TODO (one day): compeltely test 16 byte cmd len support */
+#define ISCSI_MAX_CMD_LEN	12
+#define ISCSI_CMDS_PER_LUN	32
+#define ISCSI_MAX_CMDS_PER_LUN	128
+#define ISCSI_CANQUEUE		8192
+#define ISCSI_MAX_SG		64
+#define ISCSI_MAX_LUNS		256
+#define ISCSI_MAX_TARGETS	1
+#define ISCSI_MAX_CHANNELS	0
+
+#define ISCSI_PROC_NAME 	"iscsi-sfnet"
+
+#define iscsi_host_err(s, fmt, args...) \
+	printk(KERN_ERR "iscsi-sfnet:host%d: "fmt, s->shost->host_no, ##args)
+#define iscsi_err(fmt, args...) \
+	printk(KERN_ERR "iscsi-sfnet: "fmt, ##args)
+
+#define iscsi_host_warn(s, fmt, args...) \
+	printk(KERN_WARNING "iscsi-sfnet:host%d: "fmt, s->shost->host_no, \
+	       ##args)
+#define iscsi_warn(fmt, args...) \
+	printk(KERN_WARNING "iscsi-sfnet: "fmt, ##args)
+
+#define iscsi_host_notice(s, fmt, args...) \
+	printk(KERN_NOTICE "iscsi-sfnet:host%d: "fmt, s->shost->host_no, ##args)
+#define iscsi_notice(fmt, args...) \
+	printk(KERN_NOTICE "iscsi-sfnet: "fmt, ##args)
+
+#define iscsi_host_info(s, fmt, args...) \
+	printk(KERN_INFO "iscsi-sfnet:host%d: "fmt, s->shost->host_no, ##args)
+#define iscsi_info(fmt, args...) \
+	printk(KERN_INFO "iscsi-sfnet: "fmt, ##args)
+
+/* miscalleneous routines */
+extern unsigned int iscsi_command_attr(struct scsi_cmnd *sc);
+extern void iscsi_complete_command(struct scsi_cmnd *sc);
+
+/* Routines related to Serial Number Arithmetic */
+extern int iscsi_sna_lt(u32 n1, u32 n2);
+extern int iscsi_sna_lte(u32 n1, u32 n2);
+
+/*
+ * IO return values the driver uses in the send, recv
+ * and network code. 
+ */
+enum {
+	ISCSI_IO_SUCCESS,
+	ISCSI_IO_ERR,
+	ISCSI_IO_CRC32C_ERR,
+	ISCSI_IO_INTR,
+	ISCSI_IO_INVALID_OP,
+};
+
+/* Routines to build and transmit iSCSI PDUs and/or data */
+extern void iscsi_send_scsi_cmnd(struct iscsi_task *task);
+extern void iscsi_send_task_mgmt(struct iscsi_session *session);
+extern void iscsi_send_r2t_data(struct iscsi_session *session);
+extern void iscsi_send_nop_replys(struct iscsi_session *session);
+extern void iscsi_send_logout(struct iscsi_session *session);
+extern void iscsi_send_nop_out(struct iscsi_session *session);
+extern void iscsi_queue_unsolicited_data(struct iscsi_task *task);
+extern int iscsi_send_pdu(struct iscsi_session *session, struct iscsi_hdr *hdr,
+			  int hdr_digest, char *data, int data_digest);
+extern int iscsi_recv_pdu(struct iscsi_session *session, struct iscsi_hdr *hdr,
+			  int hdr_digest, char *data, int data_len,
+			  int data_digest);
+
+/* Routines to send and receive data on TCP/IP sockets */
+extern int iscsi_recvmsg(struct iscsi_session *session, struct kvec *iov,
+			 size_t iovn, size_t size);
+extern int iscsi_sendmsg(struct iscsi_session *session, struct kvec *iov,
+			 size_t iovn, size_t size);
+extern int iscsi_sendpage(struct iscsi_session *session, int flags,
+			  struct page *pg, unsigned int pg_offset,
+			  unsigned int len);
+extern int iscsi_connect(struct iscsi_session *session);
+extern void iscsi_disconnect(struct iscsi_session *session);
+
+/* Register a driver interface */
+extern int iscsi_register_interface(void);
+extern void iscsi_unregister_interface(void);
+
+/* ioctl and sysfs uses these routines to interact with the initiator */
+extern int iscsi_destroy_host(struct Scsi_Host *shost);
+extern int iscsi_create_host(struct iscsi_session_ioctl *ioctld);
+
+/* Global variables */
+extern struct class_device_attribute *iscsi_host_attrs[];
+extern struct iscsi_function_template iscsi_fnt;
+
+#endif

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-01-10 22:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-10 22:57 [PATCH 3/10][RFC] linux-iscsi driver Mike Christie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox