public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30
@ 2009-01-25 14:46 Boaz Harrosh
  2009-01-25 14:50 ` [PATCH 01/16] major.h: char-major number for OSD device driver Boaz Harrosh
                   ` (15 more replies)
  0 siblings, 16 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 14:46 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd mailing-list

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

James hi.

Since we missed the 2.6.29 merge window, sigh, I'm taking the opportunity to
refresh the patchset. It's basically the same, but for a few changes listed
below:
- Exact same submitted code is now compilable as a user-mode library so
  utilities like exofs.mkfs can be compiled as regular application.
  When compiling in user-mode using my preferred -W switches to gcc I've
  unearthed little warnings, which are now fixed. Mainly:
  * signed/unsigned comparison
  * char * pointing to a const string (This one is grave in my opinion)
  * more missing statics.
  * ...
- I have added an API to the osd_uld for test modules to register an ioctl
  test vector. In the last patchset, as requested, I have removed the tests
  code from upstream submission. This meant that the out-of-tree git was
  patching the osd_uld.c and Kbuild kernel files in-order to add the tests.
  This is an administrative night-mare both for developers and users alike.
  Since they must patch their running kernel and install/replace distro modules.
  So I put the osd_ktests.c code in its own module and enable it to register
  at run-time into the running osd_uld, though injecting tests into running code.

Please take these patches off my hands this time ASAP, and let them rot in
scsi-misc until 2.6.30 merge-window ;)

[A patch is attached that showed what was changed from last time.]
---
here is the usual stuff for first-time viewers

OSD (Object-Based Storage Device) is a T10 SCSI command set that is designed
to provide efficient operation of input/output logical units that manage the
allocation, placement, and accessing of variable-size data-storage containers,
called objects. Objects are intended to contain operating system and application
constructs. Each object has associated attributes attached to it, which are
integral part of the object and provide metadata about the object. The standard
defines some common obligatory attributes, but user attributes can be added as
needed.

The patches are cut over scsi-misc-2.6-7e106029 but apply cleanly over
Linus git.

To try out and run the library please visit
http://open-osd.org and follow the instructions there.

The submitted patchset is also available via git at:
   git://git.open-osd.org/linux-open-osd.git osd
   http://git.open-osd.org/gitweb.cgi?p=linux-open-osd.git;a=shortlog;h=osd

here is the list of patches:

[PATCH 01/16] major.h: char-major number for OSD device driver
  Request for a new char-device major number

[PATCH 02/16] scsi: OSD_TYPE
  The OSD scsi type constant definition.

[PATCH 03/16] libosd: OSDv1 Headers
[PATCH 04/16] libosd: OSDv1 preliminary implementation
  Most basic, but usable library module (libosd.ko) including
  Kbuild file.

[PATCH 05/16] osd_uld: OSD scsi ULD
[PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel
  These patches add a scsi ULD for OSD type devices. Please see
  commit logs for details.

[PATCH 07/16] libosd: attributes Support
[PATCH 08/16] libosd: OSD Security processing stubs
[PATCH 09/16] libosd: Add Flush and List-objects support
[PATCH 10/16] libosd: Not implemented commands
[PATCH 11/16] libosd: OSD version 2 Support
[PATCH 12/16] libosd: OSDv2 auto detection
[PATCH 13/16] libosd: SCSI/OSD Sense decoding support
  Up to here this is a fairly complete body of work, to support
  both OSD1 and OSD2 targets. Main pieces that are still missing
  from the library at this point are: The OSD2 capabilities structure,
  do to lack of an OSD target that supports it. And the absence of any
  OSD-security methods other then NO_SECURITY. These will come in future
  versions.

[PATCH 14/16] osd: Documentation for OSD library
  Some reading about OSD in general and further usability instructions.
  Please comment on anything missing from this document.

[PATCH 15/16] osd: Kconfig file for in-tree builds
[PATCH 16/16] scsi: Add osd library to build system
  The in-tree compilation is only enabled at the end of the patchset.
  Run your favorite configure-tool to enable the library and osd_uld
  compilation. Default is off.
  The patchset is however fully bisectable, and compilable from the beginning,
  (by applying these 2 patches first).

The open-osd team
Boaz Harrosh


[-- Attachment #2: diff_osd-for-29_to_osd-for-30.patch --]
[-- Type: text/x-patch, Size: 15726 bytes --]

git diff --stat -p -R 2abc3b5d42d4c16e57d8fdd2e3475402f10d468b 95256f25df7dc7e18f0e8652b6a0309913d4dabe
 drivers/scsi/osd/Kbuild          |    8 +++-
 drivers/scsi/osd/osd_initiator.c |   48 ++++++++++++++----------
 drivers/scsi/osd/osd_ktests.c    |   75 +++++++++++++++++++++++++++++---------
 drivers/scsi/osd/osd_ktests.h    |    4 +--
 drivers/scsi/osd/osd_uld.c       |   44 +++++++++++++++++++----
 include/scsi/osd_initiator.h     |    5 +++
 6 files changed, 134 insertions(+), 50 deletions(-)

diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild
index 29f7ddd..c35fe80 100644
--- a/drivers/scsi/osd/Kbuild
+++ b/drivers/scsi/osd/Kbuild
@@ -32,7 +32,11 @@ ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1
 # if we are built out-of-tree and the hosting kernel has OSD headers
 # then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing
 # this it will work. This might break in future kernels
-KBUILD_CPPFLAGS := -I$(OSD_INC) $(KBUILD_CPPFLAGS)
+LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE)
+
+# osd_ktests.ko is only built out of tree
+#   see git://git.open-osd.org open-osd for latest code
+obj-m += osd_ktests.o
 
 endif
 
@@ -41,5 +45,5 @@ libosd-y := osd_initiator.o
 obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
 
 # osd.ko - SCSI ULD and char-device
-osd-y := osd_uld.o osd_ktests.o
+osd-y := osd_uld.o
 obj-$(CONFIG_SCSI_OSD_ULD) += osd.o
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 11bf42b..0bbbf27 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -48,6 +48,10 @@
 
 #include "osd_debug.h"
 
+#ifndef __unused
+#    define __unused			__attribute__((unused))
+#endif
+
 enum { OSD_REQ_RETRIES = 1 };
 
 MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
@@ -62,7 +66,7 @@ static inline void build_test(void)
 	BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN);
 }
 
-static char *_osd_ver_desc(struct osd_request *or)
+static const char *_osd_ver_desc(struct osd_request *or)
 {
 	return osd_req_is_ver1(or) ? "OSD1" : "OSD2";
 }
@@ -157,8 +161,8 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
 		((char *)pFirst)[4], ((char *)pFirst)[5]);
 
 	if (a < nelem) { /* IBM-OSD-SIM bug, Might not have it */
-		int len = get_attrs[a].len;
-		u8 sid_dump[32*4 + 2]; /* 2nibbles+space+ASCII */
+		unsigned len = get_attrs[a].len;
+		char sid_dump[32*4 + 2]; /* 2nibbles+space+ASCII */
 
 		hex_dump_to_buffer(get_attrs[a].val_ptr, len, 32, 1,
 				   sid_dump, sizeof(sid_dump), true);
@@ -345,7 +349,7 @@ static void _abort_unexecuted_bios(struct request *rq)
 	}
 }
 
-static void _osd_free_seg(struct osd_request *or,
+static void _osd_free_seg(struct osd_request *or __unused,
 	struct _osd_req_data_segment *seg)
 {
 	if (!seg->buff || !seg->alloc_size)
@@ -834,7 +838,7 @@ static int _append_map_kern(struct request *req,
 }
 
 static int _req_append_segment(struct osd_request *or,
-	int padding, struct _osd_req_data_segment *seg,
+	unsigned padding, struct _osd_req_data_segment *seg,
 	struct _osd_req_data_segment *last_seg, struct _osd_io_info *io)
 {
 	void *pad_buff;
@@ -869,7 +873,7 @@ static int _req_append_segment(struct osd_request *or,
 static int _osd_req_finalize_set_attr_list(struct osd_request *or)
 {
 	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
-	int padding;
+	unsigned padding;
 	int ret;
 
 	if (!or->set_attr.total_bytes) {
@@ -1016,7 +1020,8 @@ static int _osd_req_finalize_get_attr_list(struct osd_request *or)
 int osd_req_decode_get_attr_list(struct osd_request *or,
 	struct osd_attr *oa, int *nelem, void **iterator)
 {
-	unsigned cur_bytes, returned_bytes, n;
+	unsigned cur_bytes, returned_bytes;
+	int n;
 	const unsigned sizeof_attr_list = _osd_req_sizeof_alist_header(or);
 	void *cur_p;
 
@@ -1124,7 +1129,7 @@ EXPORT_SYMBOL(osd_req_add_get_attr_page);
 static int _osd_req_finalize_attr_page(struct osd_request *or)
 {
 	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
-	int in_padding, out_padding;
+	unsigned in_padding, out_padding;
 	int ret;
 
 	/* returned page */
@@ -1159,7 +1164,7 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or,
 			.buff = &or->out_data_integ,
 			.total_bytes = sizeof(or->out_data_integ),
 		};
-		int pad;
+		unsigned pad;
 
 		or->out_data_integ.data_bytes = cpu_to_be64(
 			or->out.bio ? or->out.bio->bi_size : 0);
@@ -1187,7 +1192,7 @@ static int _osd_req_finalize_data_integrity(struct osd_request *or,
 			.buff = &or->in_data_integ,
 			.total_bytes = sizeof(or->in_data_integ),
 		};
-		int pad;
+		unsigned pad;
 
 		sec_parms->data_in_integrity_check_offset =
 			osd_req_encode_offset(or, or->in.total_bytes, &pad);
@@ -1346,7 +1351,7 @@ EXPORT_SYMBOL(osd_finalize_request);
 
 int osd_req_decode_sense_full(struct osd_request *or,
 	struct osd_sense_info *osi, bool silent,
-	struct osd_obj_id *bad_obj_list, int max_obj,
+	struct osd_obj_id *bad_obj_list __unused, int max_obj __unused,
 	struct osd_attr *bad_attr_list, int max_attr)
 {
 	int sense_len, original_sense_len;
@@ -1364,10 +1369,11 @@ int osd_req_decode_sense_full(struct osd_request *or,
 
 	ssdb = or->request->sense;
 	sense_len = or->request->sense_len;
-	if ((sense_len < sizeof(*ssdb) || !ssdb->sense_key)) {
-		OSD_ERR("Block-layer returned error(%x) but sense is empty\n",
-			or->request->errors);
-		return 0;
+	if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) {
+		OSD_ERR("Block-layer returned error(0x%x) but "
+			"sense_len(%u) || key(%d) is empty\n",
+			or->request->errors, sense_len, ssdb->sense_key);
+		return -EIO;
 	}
 
 	if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) {
@@ -1456,8 +1462,9 @@ int osd_req_decode_sense_full(struct osd_request *or,
 		{
 			struct osd_sense_response_integrity_check_descriptor
 				*osricd = cur_descriptor;
-			const int len = sizeof(osricd->integrity_check_value);
-			u8 key_dump[len*4 + 2]; /* 2nibbles+space+ASCII */
+			const unsigned len =
+					  sizeof(osricd->integrity_check_value);
+			char key_dump[len*4 + 2]; /* 2nibbles+space+ASCII */
 
 			hex_dump_to_buffer(osricd->integrity_check_value, len,
 				       32, 1, key_dump, sizeof(key_dump), true);
@@ -1590,16 +1597,17 @@ void osd_set_caps(struct osd_cdb *cdb, const void *caps)
 	memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN);
 }
 
-bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms)
+bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused)
 {
 	return false;
 }
 
-void osd_sec_sign_cdb(struct osd_cdb *ocdb, const u8 *cap_key)
+void osd_sec_sign_cdb(struct osd_cdb *ocdb __unused, const u8 *cap_key __unused)
 {
 }
 
-void osd_sec_sign_data(void *data_integ, struct bio *bio, const u8 *cap_key)
+void osd_sec_sign_data(void *data_integ __unused,
+		       struct bio *bio __unused, const u8 *cap_key __unused)
 {
 }
 
diff --git a/drivers/scsi/osd/osd_ktests.c b/drivers/scsi/osd/osd_ktests.c
index d098323..73130a0 100644
--- a/drivers/scsi/osd/osd_ktests.c
+++ b/drivers/scsi/osd/osd_ktests.c
@@ -38,7 +38,6 @@
  *
  */
 #include <asm/unaligned.h>
-#include <linux/vmalloc.h>
 #include <scsi/scsi_device.h>
 
 #include <scsi/osd_initiator.h>
@@ -48,6 +47,10 @@
 #include "osd_ktests.h"
 #include "osd_debug.h"
 
+#ifndef __unused
+#    define __unused			__attribute__((unused))
+#endif
+
 enum {
 	K = 1024,
 	M = 1024 * K,
@@ -57,14 +60,16 @@ enum {
 const u64 format_total_capacity = 128 * M;
 const osd_id first_par_id = 0x17171717L;
 const osd_id first_obj_id = 0x18181818L;
-const unsigned BUFF_SIZE = PAGE_SIZE;
+const unsigned BUFF_SIZE = 4 * K;
 
 const int num_partitions = 1;
 const int num_objects = 2; /* per partition */
 
-int test_exec(struct osd_request *or, void *caps, const struct osd_obj_id *obj)
+static int test_exec(struct osd_request *or, void *caps,
+		     const struct osd_obj_id *obj)
 {
 	int ret;
+	struct osd_sense_info osi;
 
 	osd_sec_init_nosec_doall_caps(caps, obj, false, true);
 	ret = osd_finalize_request(or, 0, caps, NULL);
@@ -72,14 +77,14 @@ int test_exec(struct osd_request *or, void *caps, const struct osd_obj_id *obj)
 		return ret;
 
 	ret = osd_execute_request(or);
-	/* osd_req_decode_sense(or, ret); */
+	osd_req_decode_sense(or, &osi);
 	return ret;
 }
 
 #define KTEST_START_REQ(osd_dev, or) do { \
 	or = osd_start_request(osd_dev, GFP_KERNEL); \
 	if (!or) { \
-		OSD_ERR("Error @%s:%d: osd_start_request", __func__,\
+		OSD_ERR("Error @%s:%d: osd_start_request\n", __func__,\
 			__LINE__); \
 		return -ENOMEM; \
 	} \
@@ -95,7 +100,7 @@ int test_exec(struct osd_request *or, void *caps, const struct osd_obj_id *obj)
 	OSD_DEBUG(msg "\n"); \
 } while (0)
 
-int ktest_format(struct osd_dev *osd_dev)
+static int ktest_format(struct osd_dev *osd_dev)
 {
 	struct osd_request *or;
 	u8 g_caps[OSD_CAP_LEN];
@@ -107,7 +112,7 @@ int ktest_format(struct osd_dev *osd_dev)
 	return 0;
 }
 
-int ktest_creat_par(struct osd_dev *osd_dev)
+static int ktest_creat_par(struct osd_dev *osd_dev)
 {
 	struct osd_request *or;
 	u8 g_caps[OSD_CAP_LEN];
@@ -128,7 +133,7 @@ int ktest_creat_par(struct osd_dev *osd_dev)
 	return 0;
 }
 
-int ktest_creat_obj(struct osd_dev *osd_dev)
+static int ktest_creat_obj(struct osd_dev *osd_dev)
 {
 	struct osd_request *or;
 	u8 g_caps[OSD_CAP_LEN];
@@ -150,7 +155,7 @@ int ktest_creat_obj(struct osd_dev *osd_dev)
 	return 0;
 }
 
-int ktest_write_obj(struct osd_dev *osd_dev, void *write_buff)
+static int ktest_write_obj(struct osd_dev *osd_dev, void *write_buff)
 {
 	struct request_queue *req_q = osd_dev->scsi_device->request_queue;
 	struct osd_request *or;
@@ -183,7 +188,7 @@ int ktest_write_obj(struct osd_dev *osd_dev, void *write_buff)
 	return 0;
 }
 
-int ktest_read_obj(struct osd_dev *osd_dev, void *write_buff, void *read_buff)
+static int ktest_read_obj(struct osd_dev *osd_dev, void *write_buff, void *read_buff)
 {
 	struct request_queue *req_q = osd_dev->scsi_device->request_queue;
 	struct osd_request *or;
@@ -211,14 +216,14 @@ int ktest_read_obj(struct osd_dev *osd_dev, void *write_buff, void *read_buff)
 			KTEST_EXEC_END(or, &obj, g_caps, "read");
 			read_bio = NULL;
 			if (memcmp(read_buff, write_buff, BUFF_SIZE))
-				OSD_ERR("!!! Read did not compare");
+				OSD_ERR("!!! Read did not compare\n");
 			offset += BUFF_SIZE;
 		}
 
 	return 0;
 }
 
-int ktest_remove_obj(struct osd_dev *osd_dev)
+static int ktest_remove_obj(struct osd_dev *osd_dev)
 {
 	struct osd_request *or;
 	u8 g_caps[OSD_CAP_LEN];
@@ -240,7 +245,7 @@ int ktest_remove_obj(struct osd_dev *osd_dev)
 	return 0;
 }
 
-int ktest_remove_par(struct osd_dev *osd_dev)
+static int ktest_remove_par(struct osd_dev *osd_dev)
 {
 	struct osd_request *or;
 	u8 g_caps[OSD_CAP_LEN];
@@ -261,7 +266,7 @@ int ktest_remove_par(struct osd_dev *osd_dev)
 	return 0;
 }
 
-int ktest_write_read_attr(struct osd_dev *osd_dev, void *buff,
+static int ktest_write_read_attr(struct osd_dev *osd_dev, void *buff,
 	bool doread, bool doset, bool doget)
 {
 	struct request_queue *req_q = osd_dev->scsi_device->request_queue;
@@ -269,7 +274,7 @@ int ktest_write_read_attr(struct osd_dev *osd_dev, void *buff,
 	char g_caps[OSD_CAP_LEN];
 	int ret;
 	struct bio *bio;
-	char *domsg;
+	const char *domsg;
 	/* set attrs */
 	static char name[] = "ktest_write_read_attr";
 	__be64 max_len = cpu_to_be64(0x80000000L);
@@ -310,7 +315,6 @@ int ktest_write_read_attr(struct osd_dev *osd_dev, void *buff,
 	if (doget)
 		osd_req_add_get_attr_list(or, get_attrs, 2);
 
-/*	KTEST_EXEC_END(or, &obj, "");*/
 	ret = test_exec(or, g_caps, &obj);
 	if (!ret && doget) {
 		void *iter = NULL, *pFirst, *pSec;
@@ -346,11 +350,13 @@ int ktest_write_read_attr(struct osd_dev *osd_dev, void *buff,
 	return 0;
 }
 
-int do_test_17(struct osd_dev *od)
+int do_test_17(struct osd_dev *od, unsigned cmd __unused,
+		unsigned long arg __unused)
 {
 	void *write_buff = NULL;
 	void *read_buff = NULL;
-	int ret = -ENOMEM, i;
+	int ret = -ENOMEM;
+	unsigned i;
 
 /* osd_format */
 	if (ktest_format(od))
@@ -429,6 +435,14 @@ int do_test_17(struct osd_dev *od)
 	if (ret)
 		goto dev_fini;
 
+/* Error to test sense handling */
+	ret = ktest_write_obj(od, write_buff);
+	if (!ret) {
+		OSD_INFO("Error was expected written to none existing object\n");
+		ret = -EIO;
+	} else
+		ret =  0; /* good this test should fail */
+
 /* good and done */
 	OSD_INFO("test17: All good and done\n");
 dev_fini:
@@ -439,3 +453,28 @@ dev_fini:
 
 	return ret;
 }
+
+#ifdef __KERNEL__
+static const char *osd_ktests_version = "open-osd osd_ktests 0.1.0";
+
+MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
+MODULE_DESCRIPTION("open-osd Kernel tests Driver osd_ktests.ko");
+MODULE_LICENSE("GPL");
+
+static int __init osd_uld_init(void)
+{
+	OSD_INFO("LOADED %s\n", osd_ktests_version);
+	osduld_register_test(OSD_TEST_ALL, do_test_17);
+	return 0;
+}
+
+static void __exit osd_uld_exit(void)
+{
+	osduld_unregister_test(OSD_TEST_ALL);
+	OSD_INFO("UNLOADED %s\n", osd_ktests_version);
+}
+
+module_init(osd_uld_init);
+module_exit(osd_uld_exit);
+
+#endif
diff --git a/drivers/scsi/osd/osd_ktests.h b/drivers/scsi/osd/osd_ktests.h
index b625ee5..cde65ca 100644
--- a/drivers/scsi/osd/osd_ktests.h
+++ b/drivers/scsi/osd/osd_ktests.h
@@ -24,8 +24,6 @@
 
 enum { OSD_TEST_ALL = 17 };
 
-#ifdef __KERNEL__
-extern int do_test_17(struct osd_dev *od);
-#endif /* __KERNEL__ */
+int do_test_17(struct osd_dev *od, unsigned cmd, unsigned long arg);
 
 #endif /*ndef __OSD_KTESTS_H__*/
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index d8f65ad..f8b1a74 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -58,7 +58,6 @@
 #include <scsi/osd_initiator.h>
 #include <scsi/osd_sec.h>
 
-#include "osd_ktests.h"
 #include "osd_debug.h"
 
 #ifndef TYPE_OSD
@@ -118,18 +117,49 @@ static int osd_uld_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
+/* FIXME: Only one vector for now */
+unsigned g_test_ioctl;
+do_test_fn *g_do_test;
+
+int osduld_register_test(unsigned ioctl, do_test_fn *do_test)
+{
+	if (g_test_ioctl)
+		return -EINVAL;
+
+	g_test_ioctl = ioctl;
+	g_do_test = do_test;
+	return 0;
+}
+EXPORT_SYMBOL(osduld_register_test);
+
+void osduld_unregister_test(unsigned ioctl)
+{
+	if (ioctl == g_test_ioctl) {
+		g_test_ioctl = 0;
+		g_do_test = NULL;
+	}
+}
+EXPORT_SYMBOL(osduld_unregister_test);
+
+static do_test_fn *_find_ioctl(unsigned cmd)
+{
+	if (g_test_ioctl == cmd)
+		return g_do_test;
+	else
+		return NULL;
+}
+
 static long osd_uld_ioctl(struct file *file, unsigned int cmd,
 	unsigned long arg)
 {
 	struct osd_uld_device *oud = file->private_data;
 	int ret;
+	do_test_fn *do_test;
 
-	switch (cmd) {
-	case OSD_TEST_ALL:
-		OSD_DEBUG("Kernel test %d: osd_uld_device=%p\n", cmd, oud);
-		ret = do_test_17(&oud->od);
-		break;
-	default:
+	do_test = _find_ioctl(cmd);
+	if (do_test)
+		ret = do_test(&oud->od, cmd, arg);
+	else {
 		OSD_ERR("Unknown ioctl %d: osd_uld_device=%p\n", cmd, oud);
 		ret = -ENOIOCTLCMD;
 	}
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index 83b6976..b24d961 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -58,6 +58,11 @@ struct osd_dev {
 struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/
 void osduld_put_device(struct osd_dev *od);
 
+/* Add/remove test ioctls from external modules */
+typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
+int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
+void osduld_unregister_test(unsigned ioctl);
+
 /* These are called by uld at probe time */
 void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
 void osd_dev_fini(struct osd_dev *od);

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 01/16] major.h: char-major number for OSD device driver
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
@ 2009-01-25 14:50 ` Boaz Harrosh
  2009-01-25 14:51 ` [PATCH 02/16] scsi: OSD_TYPE Boaz Harrosh
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 14:50 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

We need a major for a char device for our OSD device driver.
Attached is a proposed patch for the Documentation/devices.txt
and include/linux/major.h files.

I have allocated the *260* char device as it looked like the next
available on the lanana.org web-site
(http://lanana.org/docs/device-list/devices-2.6+.txt)

Any number will do. Please allocate a number for us

(See http:/open-osd.org for further information)

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
CC: Torben Mathiasen <device@lanana.org>
---
 Documentation/devices.txt |    6 ++++++
 include/linux/major.h     |    1 +
 2 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 2be0824..62254d4 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -3145,6 +3145,12 @@ Your cooperation is appreciated.
 		  1 = /dev/blockrom1	Second ROM card's translation layer interface
 		  ...
 
+260 char	OSD (Object-based-device) SCSI Device
+		  0 = /dev/osd0		First OSD Device
+		  1 = /dev/osd1		Second OSD Device
+		  ...
+		  255 = /dev/osd255	256th OSD Device
+
  ****	ADDITIONAL /dev DIRECTORY ENTRIES
 
 This section details additional entries that should or may exist in
diff --git a/include/linux/major.h b/include/linux/major.h
index 8824945..058ec15 100644
--- a/include/linux/major.h
+++ b/include/linux/major.h
@@ -171,5 +171,6 @@
 #define VIOTAPE_MAJOR		230
 
 #define BLOCK_EXT_MAJOR		259
+#define SCSI_OSD_MAJOR		260	/* open-osd's OSD scsi device */
 
 #endif
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 02/16] scsi: OSD_TYPE
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
  2009-01-25 14:50 ` [PATCH 01/16] major.h: char-major number for OSD device driver Boaz Harrosh
@ 2009-01-25 14:51 ` Boaz Harrosh
  2009-01-25 14:54 ` [PATCH 03/16] libosd: OSDv1 Headers Boaz Harrosh
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 14:51 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

- Define the OSD_TYPE scsi device and let it show up in scans

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
---
 drivers/scsi/scsi_scan.c |    1 +
 include/scsi/scsi.h      |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 66505bb..be01089 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -796,6 +796,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
 	case TYPE_ENCLOSURE:
 	case TYPE_COMM:
 	case TYPE_RAID:
+	case TYPE_OSD:
 		sdev->writeable = 1;
 		break;
 	case TYPE_ROM:
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index a109165..de1cef2 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -263,6 +263,7 @@ static inline int scsi_status_is_good(int status)
 #define TYPE_RAID           0x0c
 #define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
 #define TYPE_RBC	    0x0e
+#define TYPE_OSD            0x11
 #define TYPE_NO_LUN         0x7f
 
 /* SCSI protocols; these are taken from SPC-3 section 7.5 */
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 03/16] libosd: OSDv1 Headers
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
  2009-01-25 14:50 ` [PATCH 01/16] major.h: char-major number for OSD device driver Boaz Harrosh
  2009-01-25 14:51 ` [PATCH 02/16] scsi: OSD_TYPE Boaz Harrosh
@ 2009-01-25 14:54 ` Boaz Harrosh
  2009-01-25 14:55 ` [PATCH 04/16] libosd: OSDv1 preliminary implementation Boaz Harrosh
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 14:54 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Headers only patch.

osd_protocol.h
	Contains a C-fied definition of the T10 OSD standard
osd_types.h
	Contains CPU order common used types
osd_initiator.h
	API definition of the osd_initiator library
osd_sec.h
	Contains High level API for the security manager.

[Note that checkpatch spews errors on things that are valid in this context
and will not be fixed]

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 include/scsi/osd_initiator.h |  332 ++++++++++++++++++++++++++++
 include/scsi/osd_protocol.h  |  497 ++++++++++++++++++++++++++++++++++++++++++
 include/scsi/osd_sec.h       |   45 ++++
 include/scsi/osd_types.h     |   40 ++++
 4 files changed, 914 insertions(+), 0 deletions(-)
 create mode 100644 include/scsi/osd_initiator.h
 create mode 100644 include/scsi/osd_protocol.h
 create mode 100644 include/scsi/osd_sec.h
 create mode 100644 include/scsi/osd_types.h

diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
new file mode 100644
index 0000000..1d92247
--- /dev/null
+++ b/include/scsi/osd_initiator.h
@@ -0,0 +1,332 @@
+/*
+ * osd_initiator.h - OSD initiator API definition
+ *
+ * Copyright (C) 2008 Panasas Inc.  All rights reserved.
+ *
+ * Authors:
+ *   Boaz Harrosh <bharrosh@panasas.com>
+ *   Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ */
+#ifndef __OSD_INITIATOR_H__
+#define __OSD_INITIATOR_H__
+
+#include "osd_protocol.h"
+#include "osd_types.h"
+
+#include <linux/blkdev.h>
+
+/* Note: "NI" in comments below means "Not Implemented yet" */
+
+/*
+ * Object-based Storage Device.
+ * This object represents an OSD device.
+ * It is not a full linux device in any way. It is only
+ * a place to hang resources associated with a Linux
+ * request Q and some default properties.
+ */
+struct osd_dev {
+	struct scsi_device *scsi_device;
+	unsigned def_timeout;
+};
+
+void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
+void osd_dev_fini(struct osd_dev *od);
+
+struct osd_request;
+typedef void (osd_req_done_fn)(struct osd_request *or, void *private);
+
+struct osd_request {
+	struct osd_cdb cdb;
+	struct osd_data_out_integrity_info out_data_integ;
+	struct osd_data_in_integrity_info in_data_integ;
+
+	struct osd_dev *osd_dev;
+	struct request *request;
+
+	struct _osd_req_data_segment {
+		void *buff;
+		unsigned alloc_size; /* 0 here means: don't call kfree */
+		unsigned total_bytes;
+	} set_attr, enc_get_attr, get_attr;
+
+	struct _osd_io_info {
+		struct bio *bio;
+		u64 total_bytes;
+		struct request *req;
+		struct _osd_req_data_segment *last_seg;
+		u8 *pad_buff;
+	} out, in;
+
+	gfp_t alloc_flags;
+	unsigned timeout;
+	unsigned retries;
+	u8 sense[OSD_MAX_SENSE_LEN];
+	enum osd_attributes_mode attributes_mode;
+
+	osd_req_done_fn *async_done;
+	void *async_private;
+	int async_error;
+};
+
+/*
+ * How to use the osd library:
+ *
+ * osd_start_request
+ *	Allocates a request.
+ *
+ * osd_req_*
+ *	Call one of, to encode the desired operation.
+ *
+ * osd_add_{get,set}_attr
+ *	Optionally add attributes to the CDB, list or page mode.
+ *
+ * osd_finalize_request
+ *	Computes final data out/in offsets and signs the request,
+ *	making it ready for execution.
+ *
+ * osd_execute_request
+ *	May be called to execute it through the block layer. Other wise submit
+ *	the associated block request in some other way.
+ *
+ * After execution:
+ * osd_req_decode_sense
+ *	Decodes sense information to verify execution results.
+ *
+ * osd_req_decode_get_attr
+ *	Retrieve osd_add_get_attr_list() values if used.
+ *
+ * osd_end_request
+ *	Must be called to deallocate the request.
+ */
+
+/**
+ * osd_start_request - Allocate and initialize an osd_request
+ *
+ * @osd_dev:    OSD device that holds the scsi-device and default values
+ *              that the request is associated with.
+ * @gfp:        The allocation flags to use for request allocation, and all
+ *              subsequent allocations. This will be stored at
+ *              osd_request->alloc_flags, can be changed by user later
+ *
+ * Allocate osd_request and initialize all members to the
+ * default/initial state.
+ */
+struct osd_request *osd_start_request(struct osd_dev *od, gfp_t gfp);
+
+enum osd_req_options {
+	OSD_REQ_FUA = 0x08,	/* Force Unit Access */
+	OSD_REQ_DPO = 0x10,	/* Disable Page Out */
+
+	OSD_REQ_BYPASS_TIMESTAMPS = 0x80,
+};
+
+/**
+ * osd_finalize_request - Sign request and prepare request for execution
+ *
+ * @or:		osd_request to prepare
+ * @options:	combination of osd_req_options bit flags or 0.
+ * @cap:	A Pointer to an OSD_CAP_LEN bytes buffer that is received from
+ *              The security manager as capabilities for this cdb.
+ * @cap_key:	The cryptographic key used to sign the cdb/data. Can be null
+ *              if NOSEC is used.
+ *
+ * The actual request and bios are only allocated here, so are the get_attr
+ * buffers that will receive the returned attributes. Copy's @cap to cdb.
+ * Sign the cdb/data with @cap_key.
+ */
+int osd_finalize_request(struct osd_request *or,
+	u8 options, const void *cap, const u8 *cap_key);
+
+/**
+ * osd_execute_request - Execute the request synchronously through block-layer
+ *
+ * @or:		osd_request to Executed
+ *
+ * Calls blk_execute_rq to q the command and waits for completion.
+ */
+int osd_execute_request(struct osd_request *or);
+
+/**
+ * osd_execute_request_async - Execute the request without waitting.
+ *
+ * @or:                      - osd_request to Executed
+ * @done: (Optional)         - Called at end of execution
+ * @private:                 - Will be passed to @done function
+ *
+ * Calls blk_execute_rq_nowait to queue the command. When execution is done
+ * optionally calls @done with @private as parameter. @or->async_error will
+ * have the return code
+ */
+int osd_execute_request_async(struct osd_request *or,
+	osd_req_done_fn *done, void *private);
+
+/**
+ * osd_end_request - return osd_request to free store
+ *
+ * @or:		osd_request to free
+ *
+ * Deallocate all osd_request resources (struct req's, BIOs, buffers, etc.)
+ */
+void osd_end_request(struct osd_request *or);
+
+/*
+ * CDB Encoding
+ *
+ * Note: call only one of the following methods.
+ */
+
+/*
+ * Device commands
+ */
+void osd_req_set_master_seed_xchg(struct osd_request *or, ...);/* NI */
+void osd_req_set_master_key(struct osd_request *or, ...);/* NI */
+
+void osd_req_format(struct osd_request *or, u64 tot_capacity);
+
+/* list all partitions
+ * @list header must be initialized to zero on first run.
+ *
+ * Call osd_is_obj_list_done() to find if we got the complete list.
+ */
+int osd_req_list_dev_partitions(struct osd_request *or,
+	osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem);
+
+void osd_req_flush_obsd(struct osd_request *or,
+	enum osd_options_flush_scope_values);
+
+void osd_req_perform_scsi_command(struct osd_request *or,
+	const u8 *cdb, ...);/* NI */
+void osd_req_task_management(struct osd_request *or, ...);/* NI */
+
+/*
+ * Partition commands
+ */
+void osd_req_create_partition(struct osd_request *or, osd_id partition);
+void osd_req_remove_partition(struct osd_request *or, osd_id partition);
+
+void osd_req_set_partition_key(struct osd_request *or,
+	osd_id partition, u8 new_key_id[OSD_CRYPTO_KEYID_SIZE],
+	u8 seed[OSD_CRYPTO_SEED_SIZE]);/* NI */
+
+/* list all collections in the partition
+ * @list header must be init to zero on first run.
+ *
+ * Call osd_is_obj_list_done() to find if we got the complete list.
+ */
+int osd_req_list_partition_collections(struct osd_request *or,
+	osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
+	unsigned nelem);
+
+/* list all objects in the partition
+ * @list header must be init to zero on first run.
+ *
+ * Call osd_is_obj_list_done() to find if we got the complete list.
+ */
+int osd_req_list_partition_objects(struct osd_request *or,
+	osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
+	unsigned nelem);
+
+void osd_req_flush_partition(struct osd_request *or,
+	osd_id partition, enum osd_options_flush_scope_values);
+
+/*
+ * Collection commands
+ */
+void osd_req_create_collection(struct osd_request *or,
+	const struct osd_obj_id *);/* NI */
+void osd_req_remove_collection(struct osd_request *or,
+	const struct osd_obj_id *);/* NI */
+
+/* list all objects in the collection */
+int osd_req_list_collection_objects(struct osd_request *or,
+	const struct osd_obj_id *, osd_id initial_id,
+	struct osd_obj_id_list *list, unsigned nelem);
+
+/* V2 only filtered list of objects in the collection */
+void osd_req_query(struct osd_request *or, ...);/* NI */
+
+void osd_req_flush_collection(struct osd_request *or,
+	const struct osd_obj_id *, enum osd_options_flush_scope_values);
+
+void osd_req_get_member_attrs(struct osd_request *or, ...);/* V2-only NI */
+void osd_req_set_member_attrs(struct osd_request *or, ...);/* V2-only NI */
+
+/*
+ * Object commands
+ */
+void osd_req_create_object(struct osd_request *or, struct osd_obj_id *);
+void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *);
+
+void osd_req_write(struct osd_request *or,
+	const struct osd_obj_id *, struct bio *data_out, u64 offset);
+void osd_req_append(struct osd_request *or,
+	const struct osd_obj_id *, struct bio *data_out);/* NI */
+void osd_req_create_write(struct osd_request *or,
+	const struct osd_obj_id *, struct bio *data_out, u64 offset);/* NI */
+void osd_req_clear(struct osd_request *or,
+	const struct osd_obj_id *, u64 offset, u64 len);/* NI */
+void osd_req_punch(struct osd_request *or,
+	const struct osd_obj_id *, u64 offset, u64 len);/* V2-only NI */
+
+void osd_req_flush_object(struct osd_request *or,
+	const struct osd_obj_id *, enum osd_options_flush_scope_values,
+	/*V2*/ u64 offset, /*V2*/ u64 len);
+
+void osd_req_read(struct osd_request *or,
+	const struct osd_obj_id *, struct bio *data_in, u64 offset);
+
+/*
+ * Root/Partition/Collection/Object Attributes commands
+ */
+
+/* get before set */
+void osd_req_get_attributes(struct osd_request *or, const struct osd_obj_id *);
+
+/* set before get */
+void osd_req_set_attributes(struct osd_request *or, const struct osd_obj_id *);
+
+/*
+ * Attributes appended to most commands
+ */
+
+/* Attributes List mode (or V2 CDB) */
+  /*
+   * TODO: In ver2 if at finalize time only one attr was set and no gets,
+   * then the Attributes CDB mode is used automatically to save IO.
+   */
+
+/* set a list of attributes. */
+int osd_req_add_set_attr_list(struct osd_request *or,
+	const struct osd_attr *, unsigned nelem);
+
+/* get a list of attributes */
+int osd_req_add_get_attr_list(struct osd_request *or,
+	const struct osd_attr *, unsigned nelem);
+
+/*
+ * Attributes list decoding
+ * Must be called after osd_request.request was executed
+ * It is called in a loop to decode the returned get_attr
+ * (see osd_add_get_attr)
+ */
+int osd_req_decode_get_attr_list(struct osd_request *or,
+	struct osd_attr *, int *nelem, void **iterator);
+
+/* Attributes Page mode */
+
+/*
+ * Read an attribute page and optionally set one attribute
+ *
+ * Retrieves the attribute page directly to a user buffer.
+ * @attr_page_data shall stay valid until end of execution.
+ * See osd_attributes.h for common page structures
+ */
+int osd_req_add_get_attr_page(struct osd_request *or,
+	u32 page_id, void *attr_page_data, unsigned max_page_len,
+	const struct osd_attr *set_one);
+
+#endif /* __OSD_LIB_H__ */
diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h
new file mode 100644
index 0000000..ce1a877
--- /dev/null
+++ b/include/scsi/osd_protocol.h
@@ -0,0 +1,497 @@
+/*
+ * osd_protocol.h - OSD T10 standard C definitions.
+ *
+ * Copyright (C) 2008 Panasas Inc.  All rights reserved.
+ *
+ * Authors:
+ *   Boaz Harrosh <bharrosh@panasas.com>
+ *   Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ * This file contains types and constants that are defined by the protocol
+ * Note: All names and symbols are taken from the OSD standard's text.
+ */
+#ifndef __OSD_PROTOCOL_H__
+#define __OSD_PROTOCOL_H__
+
+#include <linux/types.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+
+enum {
+	OSDv1_ADDITIONAL_CDB_LENGTH = 192,
+	OSDv1_TOTAL_CDB_LEN = OSDv1_ADDITIONAL_CDB_LENGTH + 8,
+	OSDv1_CAP_LEN = 80,
+	/* Latest supported version */
+	OSD_ADDITIONAL_CDB_LENGTH = OSDv1_ADDITIONAL_CDB_LENGTH,
+	OSD_TOTAL_CDB_LEN = OSDv1_TOTAL_CDB_LEN,
+	OSD_CAP_LEN = OSDv1_CAP_LEN,
+
+	OSD_SYSTEMID_LEN = 20,
+	OSD_CRYPTO_KEYID_SIZE = 20,
+	OSD_CRYPTO_SEED_SIZE = 4,
+	OSD_CRYPTO_NONCE_SIZE = 12,
+	OSD_MAX_SENSE_LEN = 252, /* from SPC-3 */
+
+	OSD_PARTITION_FIRST_ID = 0x10000,
+	OSD_OBJECT_FIRST_ID = 0x10000,
+};
+
+/* (osd-r10 5.2.4)
+ * osd2r03: 5.2.3 Caching control bits
+ */
+enum osd_options_byte {
+	OSD_CDB_FUA = 0x08,	/* Force Unit Access */
+	OSD_CDB_DPO = 0x10,	/* Disable Page Out */
+};
+
+/*
+ * osd2r03: 5.2.5 Isolation.
+ * First 3 bits, V2-only.
+ * Also for attr 110h "default isolation method" at Root Information page
+ */
+enum osd_options_byte_isolation {
+	OSD_ISOLATION_DEFAULT = 0,
+	OSD_ISOLATION_NONE = 1,
+	OSD_ISOLATION_STRICT = 2,
+	OSD_ISOLATION_RANGE = 4,
+	OSD_ISOLATION_FUNCTIONAL = 5,
+	OSD_ISOLATION_VENDOR = 7,
+};
+
+/* (osd-r10: 6.7)
+ * osd2r03: 6.8 FLUSH, FLUSH COLLECTION, FLUSH OSD, FLUSH PARTITION
+ */
+enum osd_options_flush_scope_values {
+	OSD_CDB_FLUSH_ALL = 0,
+	OSD_CDB_FLUSH_ATTR_ONLY = 1,
+
+	OSD_CDB_FLUSH_ALL_RECURSIVE = 2,
+	/* V2-only */
+	OSD_CDB_FLUSH_ALL_RANGE = 2,
+};
+
+/* osd2r03: 5.2.10 Timestamps control */
+enum {
+	OSD_CDB_NORMAL_TIMESTAMPS = 0,
+	OSD_CDB_BYPASS_TIMESTAMPS = 0x7f,
+};
+
+/* (osd-r10: 5.2.2.1)
+ * osd2r03: 5.2.4.1 Get and set attributes CDB format selection
+ *	2 bits at second nibble of command_specific_options byte
+ */
+enum osd_attributes_mode {
+	/* V2-only */
+	OSD_CDB_SET_ONE_ATTR = 0x10,
+
+	OSD_CDB_GET_ATTR_PAGE_SET_ONE = 0x20,
+	OSD_CDB_GET_SET_ATTR_LISTS = 0x30,
+
+	OSD_CDB_GET_SET_ATTR_MASK = 0x30,
+};
+
+/* (osd-r10: 4.12.5)
+ * osd2r03: 4.14.5 Data-In and Data-Out buffer offsets
+ *	byte offset = mantissa * (2^(exponent+8))
+ *	struct {
+ *		unsigned mantissa: 28;
+ *		int exponent: 04;
+ *	}
+ */
+typedef __be32 __bitwise osd_cdb_offset;
+
+enum {
+	OSD_OFFSET_UNUSED = 0xFFFFFFFF,
+	OSD_OFFSET_MAX_BITS = 28,
+
+	OSDv1_OFFSET_MIN_SHIFT = 8,
+	OSD_OFFSET_MAX_SHIFT = 16,
+};
+
+/* Return the smallest allowed encoded offset that contains @offset.
+ *
+ * The actual encoded offset returned is @offset + *padding.
+ * (up to max_shift, non-inclusive)
+ */
+osd_cdb_offset __osd_encode_offset(u64 offset, unsigned *padding,
+	int min_shift, int max_shift);
+
+/* Minimum alignment is 256 bytes
+ * Note: Seems from std v1 that exponent can be from 0+8 to 0xE+8 (inclusive)
+ * which is 8 to 23 but IBM code restricts it to 16, so be it.
+ */
+static inline osd_cdb_offset osd_encode_offset_v1(u64 offset, unsigned *padding)
+{
+	return __osd_encode_offset(offset, padding,
+				OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
+}
+
+/* osd2r03: 5.2.1 Overview */
+struct osd_cdb_head {
+	struct scsi_varlen_cdb_hdr varlen_cdb;
+/*10*/	u8		options;
+	u8		command_specific_options;
+	u8		timestamp_control;
+/*13*/	u8		reserved1[3];
+/*16*/	__be64		partition;
+/*24*/	__be64		object;
+/*32*/	union { /* V1 vs V2 alignment differences */
+		struct __osdv1_cdb_addr_len {
+/*32*/			__be32 		list_identifier;/* Rarely used */
+/*36*/			__be64		length;
+/*44*/			__be64		start_address;
+		} __packed v1;
+	};
+/*52*/	union { /* selected attributes mode Page/List/Single */
+		struct osd_attributes_page_mode {
+/*52*/			__be32		get_attr_page;
+/*56*/			__be32		get_attr_alloc_length;
+/*60*/			osd_cdb_offset	get_attr_offset;
+
+/*64*/			__be32		set_attr_page;
+/*68*/			__be32		set_attr_id;
+/*72*/			__be32		set_attr_length;
+/*76*/			osd_cdb_offset	set_attr_offset;
+/*80*/		} __packed attrs_page;
+
+		struct osd_attributes_list_mode {
+/*52*/			__be32		get_attr_desc_bytes;
+/*56*/			osd_cdb_offset	get_attr_desc_offset;
+
+/*60*/			__be32		get_attr_alloc_length;
+/*64*/			osd_cdb_offset	get_attr_offset;
+
+/*68*/			__be32		set_attr_bytes;
+/*72*/			osd_cdb_offset	set_attr_offset;
+			__be32 not_used;
+/*80*/		} __packed attrs_list;
+
+		/* osd2r03:5.2.4.2 Set one attribute value using CDB fields */
+		struct osd_attributes_cdb_mode {
+/*52*/			__be32		set_attr_page;
+/*56*/			__be32		set_attr_id;
+/*60*/			__be16		set_attr_len;
+/*62*/			u8		set_attr_val[18];
+/*80*/		} __packed attrs_cdb;
+/*52*/		u8 get_set_attributes_parameters[28];
+	};
+} __packed;
+/*80*/
+
+/*160 v1*/
+struct osd_security_parameters {
+/*160*/u8	integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
+/*180*/u8	request_nonce[OSD_CRYPTO_NONCE_SIZE];
+/*192*/osd_cdb_offset	data_in_integrity_check_offset;
+/*196*/osd_cdb_offset	data_out_integrity_check_offset;
+} __packed;
+/*200 v1*/
+
+struct osdv1_cdb {
+	struct osd_cdb_head h;
+	u8 caps[OSDv1_CAP_LEN];
+	struct osd_security_parameters sec_params;
+} __packed;
+
+struct osd_cdb {
+	union {
+		struct osdv1_cdb v1;
+		u8 buff[OSD_TOTAL_CDB_LEN];
+	};
+} __packed;
+
+static inline struct osd_cdb_head *osd_cdb_head(struct osd_cdb *ocdb)
+{
+	return (struct osd_cdb_head *)ocdb->buff;
+}
+
+/* define both version actions
+ * Ex name = FORMAT_OSD we have OSD_ACT_FORMAT_OSD && OSDv1_ACT_FORMAT_OSD
+ */
+#define OSD_ACT___(Name, Num) \
+	OSD_ACT_##Name = __constant_cpu_to_be16(0x8880 + Num), \
+	OSDv1_ACT_##Name = __constant_cpu_to_be16(0x8800 + Num),
+
+/* V2 only actions */
+#define OSD_ACT_V2(Name, Num) \
+	OSD_ACT_##Name = __constant_cpu_to_be16(0x8880 + Num),
+
+#define OSD_ACT_V1_V2(Name, Num1, Num2) \
+	OSD_ACT_##Name = __constant_cpu_to_be16(Num2), \
+	OSDv1_ACT_##Name = __constant_cpu_to_be16(Num1),
+
+enum osd_service_actions {
+	OSD_ACT_V2(OBJECT_STRUCTURE_CHECK,	0x00)
+	OSD_ACT___(FORMAT_OSD,			0x01)
+	OSD_ACT___(CREATE,			0x02)
+	OSD_ACT___(LIST,			0x03)
+	OSD_ACT_V2(PUNCH,			0x04)
+	OSD_ACT___(READ,			0x05)
+	OSD_ACT___(WRITE,			0x06)
+	OSD_ACT___(APPEND,			0x07)
+	OSD_ACT___(FLUSH,			0x08)
+	OSD_ACT_V2(CLEAR,			0x09)
+	OSD_ACT___(REMOVE,			0x0A)
+	OSD_ACT___(CREATE_PARTITION,		0x0B)
+	OSD_ACT___(REMOVE_PARTITION,		0x0C)
+	OSD_ACT___(GET_ATTRIBUTES,		0x0E)
+	OSD_ACT___(SET_ATTRIBUTES,		0x0F)
+	OSD_ACT___(CREATE_AND_WRITE,		0x12)
+	OSD_ACT___(CREATE_COLLECTION,		0x15)
+	OSD_ACT___(REMOVE_COLLECTION,		0x16)
+	OSD_ACT___(LIST_COLLECTION,		0x17)
+	OSD_ACT___(SET_KEY,			0x18)
+	OSD_ACT___(SET_MASTER_KEY,		0x19)
+	OSD_ACT___(FLUSH_COLLECTION,		0x1A)
+	OSD_ACT___(FLUSH_PARTITION,		0x1B)
+	OSD_ACT___(FLUSH_OSD,			0x1C)
+
+	OSD_ACT_V2(QUERY,			0x20)
+	OSD_ACT_V2(REMOVE_MEMBER_OBJECTS,	0x21)
+	OSD_ACT_V2(GET_MEMBER_ATTRIBUTES,	0x22)
+	OSD_ACT_V2(SET_MEMBER_ATTRIBUTES,	0x23)
+	OSD_ACT_V2(READ_MAP,			0x31)
+
+	OSD_ACT_V1_V2(PERFORM_SCSI_COMMAND,	0x8F7E, 0x8F7C)
+	OSD_ACT_V1_V2(SCSI_TASK_MANAGEMENT,	0x8F7F, 0x8F7D)
+	/* 0x8F80 to 0x8FFF are Vendor specific */
+};
+
+/* osd2r03: 7.1.3.2 List entry format for retrieving attributes */
+struct osd_attributes_list_attrid {
+	__be32 attr_page;
+	__be32 attr_id;
+} __packed;
+
+/*
+ * osd2r03: 7.1.3.3 List entry format for retrieved attributes and
+ *                  for setting attributes
+ */
+struct osd_attributes_list_element {
+	__be32 attr_page;
+	__be32 attr_id;
+	__be16 attr_bytes;
+	u8 attr_val[0];
+} __packed;
+
+enum {
+	OSDv1_ATTRIBUTES_ELEM_ALIGN = 1,
+};
+
+enum {
+	OSD_ATTR_LIST_ALL_PAGES = 0xFFFFFFFF,
+	OSD_ATTR_LIST_ALL_IN_PAGE = 0xFFFFFFFF,
+};
+
+static inline unsigned osdv1_attr_list_elem_size(unsigned len)
+{
+	return ALIGN(len + sizeof(struct osd_attributes_list_element),
+		     OSDv1_ATTRIBUTES_ELEM_ALIGN);
+}
+
+/*
+ * osd2r03: 7.1.3 OSD attributes lists (Table 184) — List type values
+ */
+enum osd_attr_list_types {
+	OSD_ATTR_LIST_GET = 0x1, 	/* descriptors only */
+	OSD_ATTR_LIST_SET_RETRIEVE = 0x9, /*descriptors/values variable-length*/
+	OSD_V2_ATTR_LIST_MULTIPLE = 0xE,  /* ver2, Multiple Objects lists*/
+	OSD_V1_ATTR_LIST_CREATE_MULTIPLE = 0xF,/*ver1, used by create_multple*/
+};
+
+/* osd2r03: 7.1.3.4 Multi-object retrieved attributes format */
+struct osd_attributes_list_multi_header {
+	__be64 object_id;
+	u8 object_type; /* object_type enum below */
+	u8 reserved[5];
+	__be16 list_bytes;
+	/* followed by struct osd_attributes_list_element's */
+};
+
+struct osdv1_attributes_list_header {
+	u8 type;	/* low 4-bit only */
+	u8 pad;
+	__be16 list_bytes; /* Initiator shall set to Zero. Only set by target */
+	/*
+	 * type=9 followed by struct osd_attributes_list_element's
+	 * type=E followed by struct osd_attributes_list_multi_header's
+	 */
+} __packed;
+
+static inline unsigned osdv1_list_size(struct osdv1_attributes_list_header *h)
+{
+	return be16_to_cpu(h->list_bytes);
+}
+
+/* (osd-r10 6.13)
+ * osd2r03: 6.15 LIST (Table 79) LIST command parameter data.
+ *	for root_lstchg below
+ */
+enum {
+	OSD_OBJ_ID_LIST_PAR = 0x1, /* V1-only. Not used in V2 */
+	OSD_OBJ_ID_LIST_LSTCHG = 0x2,
+};
+
+/*
+ * osd2r03: 6.15.2 LIST command parameter data
+ * (Also for LIST COLLECTION)
+ */
+struct osd_obj_id_list {
+	__be64 list_bytes; /* bytes in list excluding list_bytes (-8) */
+	__be64 continuation_id;
+	__be32 list_identifier;
+	u8 pad[3];
+	u8 root_lstchg;
+	__be64 object_ids[0];
+} __packed;
+
+static inline bool osd_is_obj_list_done(struct osd_obj_id_list *list,
+	bool *is_changed)
+{
+	*is_changed = (0 != (list->root_lstchg & OSD_OBJ_ID_LIST_LSTCHG));
+	return 0 != list->continuation_id;
+}
+
+/*
+ * osd2r03: 4.12.4.5 The ALLDATA security method
+ */
+struct osd_data_out_integrity_info {
+	__be64 data_bytes;
+	__be64 set_attributes_bytes;
+	__be64 get_attributes_bytes;
+	__be64 integrity_check_value;
+} __packed;
+
+struct osd_data_in_integrity_info {
+	__be64 data_bytes;
+	__be64 retrieved_attributes_bytes;
+	__be64 integrity_check_value;
+} __packed;
+
+struct osd_timestamp {
+	u8 time[6]; /* number of milliseconds since 1/1/1970 UT (big endian) */
+} __packed;
+/* FIXME: define helper functions to convert to/from osd time format */
+
+/*
+ * Capability & Security definitions
+ * osd2r03: 4.11.2.2 Capability format
+ * osd2r03: 5.2.8 Security parameters
+ */
+
+struct osd_key_identifier {
+	u8 id[7]; /* if you know why 7 please email bharrosh@panasas.com */
+} __packed;
+
+/* for osd_capability.format */
+enum {
+	OSD_SEC_CAP_FORMAT_NO_CAPS = 0,
+	OSD_SEC_CAP_FORMAT_VER1 = 1,
+	OSD_SEC_CAP_FORMAT_VER2 = 2,
+};
+
+/* security_method */
+enum {
+	OSD_SEC_NOSEC = 0,
+	OSD_SEC_CAPKEY = 1,
+	OSD_SEC_CMDRSP = 2,
+	OSD_SEC_ALLDATA = 3,
+};
+
+enum object_type {
+	OSD_SEC_OBJ_ROOT = 0x1,
+	OSD_SEC_OBJ_PARTITION = 0x2,
+	OSD_SEC_OBJ_COLLECTION = 0x40,
+	OSD_SEC_OBJ_USER = 0x80,
+};
+
+enum osd_capability_bit_masks {
+	OSD_SEC_CAP_APPEND	= BIT(0),
+	OSD_SEC_CAP_OBJ_MGMT	= BIT(1),
+	OSD_SEC_CAP_REMOVE	= BIT(2),
+	OSD_SEC_CAP_CREATE	= BIT(3),
+	OSD_SEC_CAP_SET_ATTR	= BIT(4),
+	OSD_SEC_CAP_GET_ATTR	= BIT(5),
+	OSD_SEC_CAP_WRITE	= BIT(6),
+	OSD_SEC_CAP_READ	= BIT(7),
+
+	OSD_SEC_CAP_NONE1	= BIT(8),
+	OSD_SEC_CAP_NONE2	= BIT(9),
+	OSD_SEC_CAP_NONE3	= BIT(10),
+	OSD_SEC_CAP_QUERY	= BIT(11), /*v2 only*/
+	OSD_SEC_CAP_M_OBJECT	= BIT(12), /*v2 only*/
+	OSD_SEC_CAP_POL_SEC	= BIT(13),
+	OSD_SEC_CAP_GLOBAL	= BIT(14),
+	OSD_SEC_CAP_DEV_MGMT	= BIT(15),
+};
+
+/* for object_descriptor_type (hi nibble used) */
+enum {
+	OSD_SEC_OBJ_DESC_NONE = 0,     /* Not allowed */
+	OSD_SEC_OBJ_DESC_OBJ = 1 << 4, /* v1: also collection */
+	OSD_SEC_OBJ_DESC_PAR = 2 << 4, /* also root */
+	OSD_SEC_OBJ_DESC_COL = 3 << 4, /* v2 only */
+};
+
+/* (osd-r10:4.9.2.2)
+ * osd2r03:4.11.2.2 Capability format
+ */
+struct osd_capability_head {
+	u8 format; /* low nibble */
+	u8 integrity_algorithm__key_version; /* MAKE_BYTE(integ_alg, key_ver) */
+	u8 security_method;
+	u8 reserved1;
+/*04*/	struct osd_timestamp expiration_time;
+/*10*/	u8 audit[20];
+/*30*/	u8 discriminator[12];
+/*42*/	struct osd_timestamp object_created_time;
+/*48*/	u8 object_type;
+/*49*/	u8 permissions_bit_mask[5];
+/*54*/	u8 reserved2;
+/*55*/	u8 object_descriptor_type; /* high nibble */
+} __packed;
+
+/*56 v1*/
+struct osdv1_cap_object_descriptor {
+	union {
+		struct {
+/*56*/			__be32 policy_access_tag;
+/*60*/			__be64 allowed_partition_id;
+/*68*/			__be64 allowed_object_id;
+/*76*/			__be32 reserved;
+		} __packed obj_desc;
+
+/*56*/		u8 object_descriptor[24];
+	};
+} __packed;
+/*80 v1*/
+
+struct osd_capability {
+	struct osd_capability_head h;
+	struct osdv1_cap_object_descriptor od;
+} __packed;
+
+/**
+ * osd_sec_set_caps - set cap-bits into the capabilities header
+ *
+ * @cap:	The osd_capability_head to set cap bits to.
+ * @bit_mask: 	Use an ORed list of enum osd_capability_bit_masks values
+ *
+ * permissions_bit_mask is unaligned use below to set into caps
+ * in a version independent way
+ */
+static inline void osd_sec_set_caps(struct osd_capability_head *cap,
+	u16 bit_mask)
+{
+	/*
+	 *Note: The bits above are defined LE order this is because this way
+	 *      they can grow in the future to more then 16, and still retain
+	 *      there constant values.
+	 */
+	put_unaligned_le16(bit_mask, &cap->permissions_bit_mask);
+}
+
+#endif /* ndef __OSD_PROTOCOL_H__ */
diff --git a/include/scsi/osd_sec.h b/include/scsi/osd_sec.h
new file mode 100644
index 0000000..4c09fee
--- /dev/null
+++ b/include/scsi/osd_sec.h
@@ -0,0 +1,45 @@
+/*
+ * osd_sec.h - OSD security manager API
+ *
+ * Copyright (C) 2008 Panasas Inc.  All rights reserved.
+ *
+ * Authors:
+ *   Boaz Harrosh <bharrosh@panasas.com>
+ *   Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ */
+#ifndef __OSD_SEC_H__
+#define __OSD_SEC_H__
+
+#include "osd_protocol.h"
+#include "osd_types.h"
+
+/*
+ * Contains types and constants of osd capabilities and security
+ * encoding/decoding.
+ * API is trying to keep security abstract so initiator of an object
+ * based pNFS client knows as little as possible about security and
+ * capabilities. It is the Server's osd-initiator place to know more.
+ * Also can be used by osd-target.
+ */
+void osd_sec_encode_caps(void *caps, ...);/* NI */
+void osd_sec_init_nosec_doall_caps(void *caps,
+	const struct osd_obj_id *obj, bool is_collection, const bool is_v1);
+
+bool osd_is_sec_alldata(struct osd_security_parameters *sec_params);
+
+/* Conditionally sign the CDB according to security setting in ocdb
+ * with cap_key */
+void osd_sec_sign_cdb(struct osd_cdb *ocdb, const u8 *cap_key);
+
+/* Unconditionally sign the BIO data with cap_key.
+ * Check for osd_is_sec_alldata() was done prior to calling this. */
+void osd_sec_sign_data(void *data_integ, struct bio *bio, const u8 *cap_key);
+
+/* Version independent copy of caps into the cdb */
+void osd_set_caps(struct osd_cdb *cdb, const void *caps);
+
+#endif /* ndef __OSD_SEC_H__ */
diff --git a/include/scsi/osd_types.h b/include/scsi/osd_types.h
new file mode 100644
index 0000000..3f5e88c
--- /dev/null
+++ b/include/scsi/osd_types.h
@@ -0,0 +1,40 @@
+/*
+ * osd_types.h - Types and constants which are not part of the protocol.
+ *
+ * Copyright (C) 2008 Panasas Inc.  All rights reserved.
+ *
+ * Authors:
+ *   Boaz Harrosh <bharrosh@panasas.com>
+ *   Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ * Contains types and constants that are implementation specific and are
+ * used by more than one part of the osd library.
+ *     (Eg initiator/target/security_manager/...)
+ */
+#ifndef __OSD_TYPES_H__
+#define __OSD_TYPES_H__
+
+struct osd_systemid {
+	u8 data[OSD_SYSTEMID_LEN];
+};
+
+typedef u64 __bitwise osd_id;
+
+struct osd_obj_id {
+	osd_id partition;
+	osd_id id;
+};
+
+static const struct __weak osd_obj_id osd_root_object = {0, 0};
+
+struct osd_attr {
+	u32 attr_page;
+	u32 attr_id;
+	u16 len;		/* byte count of operand */
+	void *val_ptr;		/* in network order */
+};
+
+#endif /* ndef __OSD_TYPES_H__ */
-- 
1.6.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 04/16] libosd: OSDv1 preliminary implementation
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (2 preceding siblings ...)
  2009-01-25 14:54 ` [PATCH 03/16] libosd: OSDv1 Headers Boaz Harrosh
@ 2009-01-25 14:55 ` Boaz Harrosh
  2009-01-25 14:56 ` [PATCH 05/16] osd_uld: OSD scsi ULD Boaz Harrosh
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 14:55 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Implementation of the most basic OSD functionality and
infrastructure. Mainly Format, Create/Remove Partition,
Create/Remove Object, and read/write.

- Add Makefile and Kbuild to compile libosd.ko
- osd_initiator.c Implementation file for osd_initiator.h
  and osd_sec.h APIs
- osd_debug.h - Some kprintf macro definitions

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 drivers/scsi/osd/Kbuild          |   32 +++
 drivers/scsi/osd/Makefile        |   37 +++
 drivers/scsi/osd/osd_debug.h     |   30 +++
 drivers/scsi/osd/osd_initiator.c |  448 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 547 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/osd/Kbuild
 create mode 100755 drivers/scsi/osd/Makefile
 create mode 100644 drivers/scsi/osd/osd_debug.h
 create mode 100644 drivers/scsi/osd/osd_initiator.c

diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild
new file mode 100644
index 0000000..a95e025
--- /dev/null
+++ b/drivers/scsi/osd/Kbuild
@@ -0,0 +1,32 @@
+#
+# Kbuild for the OSD modules
+#
+# Copyright (C) 2008 Panasas Inc.  All rights reserved.
+#
+# Authors:
+#   Boaz Harrosh <bharrosh@panasas.com>
+#   Benny Halevy <bhalevy@panasas.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2
+#
+
+ifneq ($(OSD_INC),)
+# we are built out-of-tree Kconfigure everything as on
+
+CONFIG_SCSI_OSD_INITIATOR=m
+ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
+
+# Uncomment to turn debug on
+# ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
+
+# if we are built out-of-tree and the hosting kernel has OSD headers
+# then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing
+# this it will work. This might break in future kernels
+LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE)
+
+endif
+
+# libosd.ko - osd-initiator library
+libosd-y := osd_initiator.o
+obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
diff --git a/drivers/scsi/osd/Makefile b/drivers/scsi/osd/Makefile
new file mode 100755
index 0000000..d905344
--- /dev/null
+++ b/drivers/scsi/osd/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for the OSD modules (out of tree)
+#
+# Copyright (C) 2008 Panasas Inc.  All rights reserved.
+#
+# Authors:
+#   Boaz Harrosh <bharrosh@panasas.com>
+#   Benny Halevy <bhalevy@panasas.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2
+#
+# This Makefile is used to call the kernel Makefile in case of an out-of-tree
+# build.
+# $KSRC should point to a Kernel source tree otherwise host's default is
+# used. (eg. /lib/modules/`uname -r`/build)
+
+# include path for out-of-tree Headers
+OSD_INC ?= `pwd`/../../../include
+
+# allow users to override these
+# e.g. to compile for a kernel that you aren't currently running
+KSRC ?= /lib/modules/$(shell uname -r)/build
+KBUILD_OUTPUT ?=
+ARCH ?=
+V ?= 0
+
+# this is the basic Kbuild out-of-tree invocation, with the M= option
+KBUILD_BASE = +$(MAKE) -C $(KSRC) M=`pwd` KBUILD_OUTPUT=$(KBUILD_OUTPUT) ARCH=$(ARCH) V=$(V)
+
+all: libosd
+
+libosd: ;
+	$(KBUILD_BASE) OSD_INC=$(OSD_INC) modules
+
+clean:
+	$(KBUILD_BASE) clean
diff --git a/drivers/scsi/osd/osd_debug.h b/drivers/scsi/osd/osd_debug.h
new file mode 100644
index 0000000..579e491
--- /dev/null
+++ b/drivers/scsi/osd/osd_debug.h
@@ -0,0 +1,30 @@
+/*
+ * osd_debug.h - Some kprintf macros
+ *
+ * Copyright (C) 2008 Panasas Inc.  All rights reserved.
+ *
+ * Authors:
+ *   Boaz Harrosh <bharrosh@panasas.com>
+ *   Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ */
+#ifndef __OSD_DEBUG_H__
+#define __OSD_DEBUG_H__
+
+#define OSD_ERR(fmt, a...) printk(KERN_ERR "osd: " fmt, ##a)
+#define OSD_INFO(fmt, a...) printk(KERN_NOTICE "osd: " fmt, ##a)
+
+#ifdef CONFIG_SCSI_OSD_DEBUG
+#define OSD_DEBUG(fmt, a...) \
+	printk(KERN_NOTICE "osd @%s:%d: " fmt, __func__, __LINE__, ##a)
+#else
+#define OSD_DEBUG(fmt, a...) do {} while (0)
+#endif
+
+/* u64 has problems with printk this will cast it to unsigned long long */
+#define _LLU(x) (unsigned long long)(x)
+
+#endif /* ndef __OSD_DEBUG_H__ */
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
new file mode 100644
index 0000000..0e6d906
--- /dev/null
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -0,0 +1,448 @@
+/*
+ * osd_initiator - Main body of the osd initiator library.
+ *
+ * Note: The file does not contain the advanced security functionality which
+ * is only needed by the security_manager's initiators.
+ *
+ * Copyright (C) 2008 Panasas Inc.  All rights reserved.
+ *
+ * Authors:
+ *   Boaz Harrosh <bharrosh@panasas.com>
+ *   Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the Panasas company nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <scsi/osd_initiator.h>
+#include <scsi/osd_sec.h>
+#include <scsi/scsi_device.h>
+
+#include "osd_debug.h"
+
+enum { OSD_REQ_RETRIES = 1 };
+
+MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
+MODULE_DESCRIPTION("open-osd initiator library libosd.ko");
+MODULE_LICENSE("GPL");
+
+static inline void build_test(void)
+{
+	/* structures were not packed */
+	BUILD_BUG_ON(sizeof(struct osd_capability) != OSD_CAP_LEN);
+	BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN);
+}
+
+static unsigned _osd_req_cdb_len(struct osd_request *or)
+{
+	return OSDv1_TOTAL_CDB_LEN;
+}
+
+void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)
+{
+	memset(osdd, 0, sizeof(*osdd));
+	osdd->scsi_device = scsi_device;
+	osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT;
+	/* TODO: Allocate pools for osd_request attributes ... */
+}
+EXPORT_SYMBOL(osd_dev_init);
+
+void osd_dev_fini(struct osd_dev *osdd)
+{
+	/* TODO: De-allocate pools */
+
+	osdd->scsi_device = NULL;
+}
+EXPORT_SYMBOL(osd_dev_fini);
+
+static struct osd_request *_osd_request_alloc(gfp_t gfp)
+{
+	struct osd_request *or;
+
+	/* TODO: Use mempool with one saved request */
+	or = kzalloc(sizeof(*or), gfp);
+	return or;
+}
+
+static void _osd_request_free(struct osd_request *or)
+{
+	kfree(or);
+}
+
+struct osd_request *osd_start_request(struct osd_dev *dev, gfp_t gfp)
+{
+	struct osd_request *or;
+
+	or = _osd_request_alloc(gfp);
+	if (!or)
+		return NULL;
+
+	or->osd_dev = dev;
+	or->alloc_flags = gfp;
+	or->timeout = dev->def_timeout;
+	or->retries = OSD_REQ_RETRIES;
+
+	return or;
+}
+EXPORT_SYMBOL(osd_start_request);
+
+/*
+ * If osd_finalize_request() was called but the request was not executed through
+ * the block layer, then we must release BIOs.
+ */
+static void _abort_unexecuted_bios(struct request *rq)
+{
+	struct bio *bio;
+
+	while ((bio = rq->bio) != NULL) {
+		rq->bio = bio->bi_next;
+		bio_endio(bio, 0);
+	}
+}
+
+void osd_end_request(struct osd_request *or)
+{
+	struct request *rq = or->request;
+
+	if (rq) {
+		if (rq->next_rq) {
+			_abort_unexecuted_bios(rq->next_rq);
+			blk_put_request(rq->next_rq);
+		}
+
+		_abort_unexecuted_bios(rq);
+		blk_put_request(rq);
+	}
+	_osd_request_free(or);
+}
+EXPORT_SYMBOL(osd_end_request);
+
+int osd_execute_request(struct osd_request *or)
+{
+	return blk_execute_rq(or->request->q, NULL, or->request, 0);
+}
+EXPORT_SYMBOL(osd_execute_request);
+
+static void osd_request_async_done(struct request *req, int error)
+{
+	struct osd_request *or = req->end_io_data;
+
+	or->async_error = error;
+
+	if (error)
+		OSD_DEBUG("osd_request_async_done error recieved %d\n", error);
+
+	if (or->async_done)
+		or->async_done(or, or->async_private);
+	else
+		osd_end_request(or);
+}
+
+int osd_execute_request_async(struct osd_request *or,
+	osd_req_done_fn *done, void *private)
+{
+	or->request->end_io_data = or;
+	or->async_private = private;
+	or->async_done = done;
+
+	blk_execute_rq_nowait(or->request->q, NULL, or->request, 0,
+			      osd_request_async_done);
+	return 0;
+}
+EXPORT_SYMBOL(osd_execute_request_async);
+
+/*
+ * Common to all OSD commands
+ */
+
+static void _osdv1_req_encode_common(struct osd_request *or,
+	__be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
+{
+	struct osdv1_cdb *ocdb = &or->cdb.v1;
+
+	/*
+	 * For speed, the commands
+	 *	OSD_ACT_PERFORM_SCSI_COMMAND	, V1 0x8F7E, V2 0x8F7C
+	 *	OSD_ACT_SCSI_TASK_MANAGEMENT	, V1 0x8F7F, V2 0x8F7D
+	 * are not supported here. Should pass zero and set after the call
+	 */
+	act &= cpu_to_be16(~0x0080); /* V1 action code */
+
+	OSD_DEBUG("OSDv1 execute opcode 0x%x\n", be16_to_cpu(act));
+
+	ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD;
+	ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH;
+	ocdb->h.varlen_cdb.service_action = act;
+
+	ocdb->h.partition = cpu_to_be64(obj->partition);
+	ocdb->h.object = cpu_to_be64(obj->id);
+	ocdb->h.v1.length = cpu_to_be64(len);
+	ocdb->h.v1.start_address = cpu_to_be64(offset);
+}
+
+static void _osd_req_encode_common(struct osd_request *or,
+	__be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
+{
+	_osdv1_req_encode_common(or, act, obj, offset, len);
+}
+
+/*
+ * Device commands
+ */
+void osd_req_format(struct osd_request *or, u64 tot_capacity)
+{
+	_osd_req_encode_common(or, OSD_ACT_FORMAT_OSD, &osd_root_object, 0,
+				tot_capacity);
+}
+EXPORT_SYMBOL(osd_req_format);
+
+/*
+ * Partition commands
+ */
+static void _osd_req_encode_partition(struct osd_request *or,
+	__be16 act, osd_id partition)
+{
+	struct osd_obj_id par = {
+		.partition = partition,
+		.id = 0,
+	};
+
+	_osd_req_encode_common(or, act, &par, 0, 0);
+}
+
+void osd_req_create_partition(struct osd_request *or, osd_id partition)
+{
+	_osd_req_encode_partition(or, OSD_ACT_CREATE_PARTITION, partition);
+}
+EXPORT_SYMBOL(osd_req_create_partition);
+
+void osd_req_remove_partition(struct osd_request *or, osd_id partition)
+{
+	_osd_req_encode_partition(or, OSD_ACT_REMOVE_PARTITION, partition);
+}
+EXPORT_SYMBOL(osd_req_remove_partition);
+
+/*
+ * Object commands
+ */
+void osd_req_create_object(struct osd_request *or, struct osd_obj_id *obj)
+{
+	_osd_req_encode_common(or, OSD_ACT_CREATE, obj, 0, 0);
+}
+EXPORT_SYMBOL(osd_req_create_object);
+
+void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *obj)
+{
+	_osd_req_encode_common(or, OSD_ACT_REMOVE, obj, 0, 0);
+}
+EXPORT_SYMBOL(osd_req_remove_object);
+
+void osd_req_write(struct osd_request *or,
+	const struct osd_obj_id *obj, struct bio *bio, u64 offset)
+{
+	_osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, bio->bi_size);
+	WARN_ON(or->out.bio || or->out.total_bytes);
+	bio->bi_rw |= (1 << BIO_RW);
+	or->out.bio = bio;
+	or->out.total_bytes = bio->bi_size;
+}
+EXPORT_SYMBOL(osd_req_write);
+
+void osd_req_read(struct osd_request *or,
+	const struct osd_obj_id *obj, struct bio *bio, u64 offset)
+{
+	_osd_req_encode_common(or, OSD_ACT_READ, obj, offset, bio->bi_size);
+	WARN_ON(or->in.bio || or->in.total_bytes);
+	bio->bi_rw &= ~(1 << BIO_RW);
+	or->in.bio = bio;
+	or->in.total_bytes = bio->bi_size;
+}
+EXPORT_SYMBOL(osd_req_read);
+
+/*
+ * osd_finalize_request and helpers
+ */
+
+static int _init_blk_request(struct osd_request *or,
+	bool has_in, bool has_out)
+{
+	gfp_t flags = or->alloc_flags;
+	struct scsi_device *scsi_device = or->osd_dev->scsi_device;
+	struct request_queue *q = scsi_device->request_queue;
+	struct request *req;
+	int ret = -ENOMEM;
+
+	req = blk_get_request(q, has_out, flags);
+	if (!req)
+		goto out;
+
+	or->request = req;
+	req->cmd_type = REQ_TYPE_BLOCK_PC;
+	req->timeout = or->timeout;
+	req->retries = or->retries;
+	req->sense = or->sense;
+	req->sense_len = 0;
+
+	if (has_out) {
+		or->out.req = req;
+		if (has_in) {
+			/* allocate bidi request */
+			req = blk_get_request(q, READ, flags);
+			if (!req) {
+				OSD_DEBUG("blk_get_request for bidi failed\n");
+				goto out;
+			}
+			req->cmd_type = REQ_TYPE_BLOCK_PC;
+			or->in.req = or->request->next_rq = req;
+		}
+	} else if (has_in)
+		or->in.req = req;
+
+	ret = 0;
+out:
+	OSD_DEBUG("or=%p has_in=%d has_out=%d => %d, %p\n",
+			or, has_in, has_out, ret, or->request);
+	return ret;
+}
+
+int osd_finalize_request(struct osd_request *or,
+	u8 options, const void *cap, const u8 *cap_key)
+{
+	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
+	bool has_in, has_out;
+	int ret;
+
+	if (options & OSD_REQ_FUA)
+		cdbh->options |= OSD_CDB_FUA;
+
+	if (options & OSD_REQ_DPO)
+		cdbh->options |= OSD_CDB_DPO;
+
+	if (options & OSD_REQ_BYPASS_TIMESTAMPS)
+		cdbh->timestamp_control = OSD_CDB_BYPASS_TIMESTAMPS;
+
+	osd_set_caps(&or->cdb, cap);
+
+	has_in = or->in.bio || or->get_attr.total_bytes;
+	has_out = or->out.bio || or->set_attr.total_bytes ||
+		or->enc_get_attr.total_bytes;
+
+	ret = _init_blk_request(or, has_in, has_out);
+	if (ret) {
+		OSD_DEBUG("_init_blk_request failed\n");
+		return ret;
+	}
+
+	if (or->out.bio) {
+		ret = blk_rq_append_bio(or->request->q, or->out.req,
+					or->out.bio);
+		if (ret) {
+			OSD_DEBUG("blk_rq_append_bio out failed\n");
+			return ret;
+		}
+		OSD_DEBUG("out bytes=%llu (bytes_req=%u)\n",
+			_LLU(or->out.total_bytes), or->out.req->data_len);
+	}
+	if (or->in.bio) {
+		ret = blk_rq_append_bio(or->request->q, or->in.req, or->in.bio);
+		if (ret) {
+			OSD_DEBUG("blk_rq_append_bio in failed\n");
+			return ret;
+		}
+		OSD_DEBUG("in bytes=%llu (bytes_req=%u)\n",
+			_LLU(or->in.total_bytes), or->in.req->data_len);
+	}
+
+	if (!or->attributes_mode)
+		or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
+	cdbh->command_specific_options |= or->attributes_mode;
+
+	or->request->cmd = or->cdb.buff;
+	or->request->cmd_len = _osd_req_cdb_len(or);
+
+	return 0;
+}
+EXPORT_SYMBOL(osd_finalize_request);
+
+/*
+ * Implementation of osd_sec.h API
+ * TODO: Move to a separate osd_sec.c file at a later stage.
+ */
+
+enum { OSD_SEC_CAP_V1_ALL_CAPS =
+	OSD_SEC_CAP_APPEND | OSD_SEC_CAP_OBJ_MGMT | OSD_SEC_CAP_REMOVE   |
+	OSD_SEC_CAP_CREATE | OSD_SEC_CAP_SET_ATTR | OSD_SEC_CAP_GET_ATTR |
+	OSD_SEC_CAP_WRITE  | OSD_SEC_CAP_READ     | OSD_SEC_CAP_POL_SEC  |
+	OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT
+};
+
+void osd_sec_init_nosec_doall_caps(void *caps,
+	const struct osd_obj_id *obj, bool is_collection, const bool is_v1)
+{
+	struct osd_capability *cap = caps;
+	u8 type;
+	u8 descriptor_type;
+
+	if (likely(obj->id)) {
+		if (unlikely(is_collection)) {
+			type = OSD_SEC_OBJ_COLLECTION;
+			descriptor_type = is_v1 ? OSD_SEC_OBJ_DESC_OBJ :
+						  OSD_SEC_OBJ_DESC_COL;
+		} else {
+			type = OSD_SEC_OBJ_USER;
+			descriptor_type = OSD_SEC_OBJ_DESC_OBJ;
+		}
+		WARN_ON(!obj->partition);
+	} else {
+		type = obj->partition ? OSD_SEC_OBJ_PARTITION :
+					OSD_SEC_OBJ_ROOT;
+		descriptor_type = OSD_SEC_OBJ_DESC_PAR;
+	}
+
+	memset(cap, 0, sizeof(*cap));
+
+	cap->h.format = OSD_SEC_CAP_FORMAT_VER1;
+	cap->h.integrity_algorithm__key_version = 0; /* MAKE_BYTE(0, 0); */
+	cap->h.security_method = OSD_SEC_NOSEC;
+/*	cap->expiration_time;
+	cap->AUDIT[30-10];
+	cap->discriminator[42-30];
+	cap->object_created_time; */
+	cap->h.object_type = type;
+	osd_sec_set_caps(&cap->h, OSD_SEC_CAP_V1_ALL_CAPS);
+	cap->h.object_descriptor_type = descriptor_type;
+	cap->od.obj_desc.policy_access_tag = 0;
+	cap->od.obj_desc.allowed_partition_id = cpu_to_be64(obj->partition);
+	cap->od.obj_desc.allowed_object_id = cpu_to_be64(obj->id);
+}
+EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps);
+
+void osd_set_caps(struct osd_cdb *cdb, const void *caps)
+{
+	memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN);
+}
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 05/16] osd_uld: OSD scsi ULD
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (3 preceding siblings ...)
  2009-01-25 14:55 ` [PATCH 04/16] libosd: OSDv1 preliminary implementation Boaz Harrosh
@ 2009-01-25 14:56 ` Boaz Harrosh
  2009-01-25 14:58 ` [PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel Boaz Harrosh
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 14:56 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Add a Linux driver module that registers as a SCSI ULD and probes
for OSD type SCSI devices.

When an OSD-type SCSI device is found a character device is created
in the form of /dev/osdX - where X goes from 0 up to hard coded 64.
The Major character device number used is *260*, which is free
(as of Linux v2.6.28).

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 drivers/scsi/osd/Kbuild      |    7 +
 drivers/scsi/osd/osd_uld.c   |  419 ++++++++++++++++++++++++++++++++++++++++++
 include/scsi/osd_initiator.h |    6 +
 3 files changed, 432 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/osd/osd_uld.c

diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild
index a95e025..9d38248 100644
--- a/drivers/scsi/osd/Kbuild
+++ b/drivers/scsi/osd/Kbuild
@@ -17,6 +17,9 @@ ifneq ($(OSD_INC),)
 CONFIG_SCSI_OSD_INITIATOR=m
 ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
 
+CONFIG_SCSI_OSD_ULD=m
+ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE
+
 # Uncomment to turn debug on
 # ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
 
@@ -30,3 +33,7 @@ endif
 # libosd.ko - osd-initiator library
 libosd-y := osd_initiator.o
 obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
+
+# osd.ko - SCSI ULD and char-device
+osd-y := osd_uld.o
+obj-$(CONFIG_SCSI_OSD_ULD) += osd.o
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
new file mode 100644
index 0000000..f6f9a99
--- /dev/null
+++ b/drivers/scsi/osd/osd_uld.c
@@ -0,0 +1,419 @@
+/*
+ * osd_uld.c - OSD Upper Layer Driver
+ *
+ * A Linux driver module that registers as a SCSI ULD and probes
+ * for OSD type SCSI devices.
+ * It's main function is to export osd devices to in-kernel users like
+ * osdfs and pNFS-objects-LD. It also provides one ioctl for running
+ * in Kernel tests.
+ *
+ * Copyright (C) 2008 Panasas Inc.  All rights reserved.
+ *
+ * Authors:
+ *   Boaz Harrosh <bharrosh@panasas.com>
+ *   Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the Panasas company nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/namei.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/idr.h>
+#include <linux/major.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_ioctl.h>
+
+#include <scsi/osd_initiator.h>
+#include <scsi/osd_sec.h>
+
+#include "osd_debug.h"
+
+#ifndef TYPE_OSD
+#  define TYPE_OSD 0x11
+#endif
+
+#ifndef SCSI_OSD_MAJOR
+#  define SCSI_OSD_MAJOR 260
+#endif
+#define SCSI_OSD_MAX_MINOR 64
+
+static const char osd_name[] = "osd";
+static const char *osd_version_string = "open-osd 0.1.0";
+const char osd_symlink[] = "scsi_osd";
+
+MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
+MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(SCSI_OSD_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_OSD);
+
+struct osd_uld_device {
+	int minor;
+	struct kref kref;
+	struct cdev cdev;
+	struct osd_dev od;
+	struct gendisk *disk;
+	struct device *class_member;
+};
+
+static void __uld_get(struct osd_uld_device *oud);
+static void __uld_put(struct osd_uld_device *oud);
+
+/*
+ * Char Device operations
+ */
+
+static int osd_uld_open(struct inode *inode, struct file *file)
+{
+	struct osd_uld_device *oud = container_of(inode->i_cdev,
+					struct osd_uld_device, cdev);
+
+	__uld_get(oud);
+	/* cache osd_uld_device on file handle */
+	file->private_data = oud;
+	OSD_DEBUG("osd_uld_open %p\n", oud);
+	return 0;
+}
+
+static int osd_uld_release(struct inode *inode, struct file *file)
+{
+	struct osd_uld_device *oud = file->private_data;
+
+	OSD_DEBUG("osd_uld_release %p\n", file->private_data);
+	file->private_data = NULL;
+	__uld_put(oud);
+	return 0;
+}
+
+/* FIXME: Only one vector for now */
+unsigned g_test_ioctl;
+do_test_fn *g_do_test;
+
+int osduld_register_test(unsigned ioctl, do_test_fn *do_test)
+{
+	if (g_test_ioctl)
+		return -EINVAL;
+
+	g_test_ioctl = ioctl;
+	g_do_test = do_test;
+	return 0;
+}
+EXPORT_SYMBOL(osduld_register_test);
+
+void osduld_unregister_test(unsigned ioctl)
+{
+	if (ioctl == g_test_ioctl) {
+		g_test_ioctl = 0;
+		g_do_test = NULL;
+	}
+}
+EXPORT_SYMBOL(osduld_unregister_test);
+
+static do_test_fn *_find_ioctl(unsigned cmd)
+{
+	if (g_test_ioctl == cmd)
+		return g_do_test;
+	else
+		return NULL;
+}
+
+static long osd_uld_ioctl(struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	struct osd_uld_device *oud = file->private_data;
+	int ret;
+	do_test_fn *do_test;
+
+	do_test = _find_ioctl(cmd);
+	if (do_test)
+		ret = do_test(&oud->od, cmd, arg);
+	else {
+		OSD_ERR("Unknown ioctl %d: osd_uld_device=%p\n", cmd, oud);
+		ret = -ENOIOCTLCMD;
+	}
+	return ret;
+}
+
+static const struct file_operations osd_fops = {
+	.owner          = THIS_MODULE,
+	.open           = osd_uld_open,
+	.release        = osd_uld_release,
+	.unlocked_ioctl = osd_uld_ioctl,
+};
+
+/*
+ * Scsi Device operations
+ */
+
+static int __detect_osd(struct osd_uld_device *oud)
+{
+	struct scsi_device *scsi_device = oud->od.scsi_device;
+	int error;
+
+	/* sending a test_unit_ready as first command seems to be needed
+	 * by some targets
+	 */
+	OSD_DEBUG("start scsi_test_unit_ready %p %p %p\n",
+			oud, scsi_device, scsi_device->request_queue);
+	error = scsi_test_unit_ready(scsi_device, 10*HZ, 5, NULL);
+	if (error)
+		OSD_ERR("warning: scsi_test_unit_ready failed\n");
+
+	return 0;
+}
+
+static struct class *osd_sysfs_class;
+static DEFINE_IDA(osd_minor_ida);
+
+static int osd_probe(struct device *dev)
+{
+	struct scsi_device *scsi_device = to_scsi_device(dev);
+	struct gendisk *disk;
+	struct osd_uld_device *oud;
+	int minor;
+	int error;
+
+	if (scsi_device->type != TYPE_OSD)
+		return -ENODEV;
+
+	do {
+		if (!ida_pre_get(&osd_minor_ida, GFP_KERNEL))
+			return -ENODEV;
+
+		error = ida_get_new(&osd_minor_ida, &minor);
+	} while (error == -EAGAIN);
+
+	if (error)
+		return error;
+	if (minor >= SCSI_OSD_MAX_MINOR) {
+		error = -EBUSY;
+		goto err_retract_minor;
+	}
+
+	error = -ENOMEM;
+	oud = kzalloc(sizeof(*oud), GFP_KERNEL);
+	if (NULL == oud)
+		goto err_retract_minor;
+
+	kref_init(&oud->kref);
+	dev_set_drvdata(dev, oud);
+	oud->minor = minor;
+
+	/* allocate a disk and set it up */
+	/* FIXME: do we need this since sg has already done that */
+	disk = alloc_disk(1);
+	if (!disk) {
+		OSD_ERR("alloc_disk failed\n");
+		goto err_free_osd;
+	}
+	disk->major = SCSI_OSD_MAJOR;
+	disk->first_minor = oud->minor;
+	sprintf(disk->disk_name, "osd%d", oud->minor);
+	oud->disk = disk;
+
+	/* hold one more reference to the scsi_device that will get released
+	 * in __release, in case a logout is happening while fs is mounted
+	 */
+	scsi_device_get(scsi_device);
+	osd_dev_init(&oud->od, scsi_device);
+
+	/* Detect the OSD Version */
+	error = __detect_osd(oud);
+	if (error) {
+		OSD_ERR("osd detection failed, non-compatible OSD device\n");
+		goto err_put_disk;
+	}
+
+	/* init the char-device for communication with user-mode */
+	cdev_init(&oud->cdev, &osd_fops);
+	oud->cdev.owner = THIS_MODULE;
+	error = cdev_add(&oud->cdev,
+			 MKDEV(SCSI_OSD_MAJOR, oud->minor), 1);
+	if (error) {
+		OSD_ERR("cdev_add failed\n");
+		goto err_put_disk;
+	}
+	kobject_get(&oud->cdev.kobj); /* 2nd ref see osd_remove() */
+
+	/* class_member */
+	oud->class_member = device_create(osd_sysfs_class, dev,
+		MKDEV(SCSI_OSD_MAJOR, oud->minor), "%s", disk->disk_name);
+	if (IS_ERR(oud->class_member)) {
+		OSD_ERR("class_device_create failed\n");
+		error = PTR_ERR(oud->class_member);
+		goto err_put_cdev;
+	}
+
+	dev_set_drvdata(oud->class_member, oud);
+	error = sysfs_create_link(&scsi_device->sdev_gendev.kobj,
+				  &oud->class_member->kobj, osd_symlink);
+	if (error)
+		OSD_ERR("warning: unable to make symlink\n");
+
+	OSD_INFO("osd_probe %s\n", disk->disk_name);
+	return 0;
+
+err_put_cdev:
+	cdev_del(&oud->cdev);
+err_put_disk:
+	scsi_device_put(scsi_device);
+	put_disk(disk);
+err_free_osd:
+	dev_set_drvdata(dev, NULL);
+	kfree(oud);
+err_retract_minor:
+	ida_remove(&osd_minor_ida, minor);
+	return error;
+}
+
+static int osd_remove(struct device *dev)
+{
+	struct scsi_device *scsi_device = to_scsi_device(dev);
+	struct osd_uld_device *oud = dev_get_drvdata(dev);
+
+	if (!oud || (oud->od.scsi_device != scsi_device)) {
+		OSD_ERR("Half cooked osd-device %p,%p || %p!=%p",
+			dev, oud, oud ? oud->od.scsi_device : NULL,
+			scsi_device);
+	}
+
+	sysfs_remove_link(&oud->od.scsi_device->sdev_gendev.kobj, osd_symlink);
+
+	if (oud->class_member)
+		device_destroy(osd_sysfs_class,
+			       MKDEV(SCSI_OSD_MAJOR, oud->minor));
+
+	/* We have 2 references to the cdev. One is released here
+	 * and also takes down the /dev/osdX mapping. The second
+	 * Will be released in __remove() after all users have released
+	 * the osd_uld_device.
+	 */
+	if (oud->cdev.owner)
+		cdev_del(&oud->cdev);
+
+	__uld_put(oud);
+	return 0;
+}
+
+static void __remove(struct kref *kref)
+{
+	struct osd_uld_device *oud = container_of(kref,
+					struct osd_uld_device, kref);
+	struct scsi_device *scsi_device = oud->od.scsi_device;
+
+	/* now let delete the char_dev */
+	kobject_put(&oud->cdev.kobj);
+
+	osd_dev_fini(&oud->od);
+	scsi_device_put(scsi_device);
+
+	OSD_INFO("osd_remove %s\n",
+		 oud->disk ? oud->disk->disk_name : NULL);
+
+	if (oud->disk)
+		put_disk(oud->disk);
+
+	ida_remove(&osd_minor_ida, oud->minor);
+	kfree(oud);
+}
+
+static void __uld_get(struct osd_uld_device *oud)
+{
+	kref_get(&oud->kref);
+}
+
+static void __uld_put(struct osd_uld_device *oud)
+{
+	kref_put(&oud->kref, __remove);
+}
+
+/*
+ * Global driver and scsi registration
+ */
+
+static struct scsi_driver osd_driver = {
+	.owner			= THIS_MODULE,
+	.gendrv = {
+		.name		= osd_name,
+		.probe		= osd_probe,
+		.remove		= osd_remove,
+	}
+};
+
+static int __init osd_uld_init(void)
+{
+	int err;
+
+	osd_sysfs_class = class_create(THIS_MODULE, osd_symlink);
+	if (IS_ERR(osd_sysfs_class)) {
+		OSD_ERR("Unable to register sysfs class => %ld\n",
+			PTR_ERR(osd_sysfs_class));
+		return PTR_ERR(osd_sysfs_class);
+	}
+
+	err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0),
+				     SCSI_OSD_MAX_MINOR, osd_name);
+	if (err) {
+		OSD_ERR("Unable to register major %d for osd ULD => %d\n",
+			SCSI_OSD_MAJOR, err);
+		goto err_out;
+	}
+
+	err = scsi_register_driver(&osd_driver.gendrv);
+	if (err) {
+		OSD_ERR("scsi_register_driver failed => %d\n", err);
+		goto err_out_chrdev;
+	}
+
+	OSD_INFO("LOADED %s\n", osd_version_string);
+	return 0;
+
+err_out_chrdev:
+	unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
+err_out:
+	class_destroy(osd_sysfs_class);
+	return err;
+}
+
+static void __exit osd_uld_exit(void)
+{
+	scsi_unregister_driver(&osd_driver.gendrv);
+	unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR);
+	class_destroy(osd_sysfs_class);
+	OSD_INFO("UNLOADED %s\n", osd_version_string);
+}
+
+module_init(osd_uld_init);
+module_exit(osd_uld_exit);
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index 1d92247..a5dbbdd 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -33,6 +33,12 @@ struct osd_dev {
 	unsigned def_timeout;
 };
 
+/* Add/remove test ioctls from external modules */
+typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
+int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
+void osduld_unregister_test(unsigned ioctl);
+
+/* These are called by uld at probe time */
 void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
 void osd_dev_fini(struct osd_dev *od);
 
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (4 preceding siblings ...)
  2009-01-25 14:56 ` [PATCH 05/16] osd_uld: OSD scsi ULD Boaz Harrosh
@ 2009-01-25 14:58 ` Boaz Harrosh
  2009-01-28 16:32   ` James Bottomley
  2009-01-25 14:59 ` [PATCH 07/16] libosd: attributes Support Boaz Harrosh
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 14:58 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Kernel clients like exofs can retrieve struct osd_dev(s)
by means of below API.

+ osduld_path_lookup() - given a path (e.g "/dev/osd0") locks and
returns the corresponding struct osd_dev, which is then needed
for subsequent libosd use.

+ osduld_put_device() - free up use of an osd_dev.

Devices can be shared by multiple clients. The osd_uld_device's
life time is governed by an embedded kref structure.

The osd_uld_device holds an extra reference to both it's
char-device and it's scsi_device, and will release these just
before the final deallocation.

There are three possible lock sources of the osd_uld_device
1. First and for most is the probe() function called by
  scsi-ml upon a successful login into a target. Released in release()
  when logout.
2. Second by user-mode file handles opened on the char-dev.
3. Third is here by Kernel users.
All three locks must be removed before the osd_uld_device is freed.

The MODULE has three lock sources as well:
1. scsi-ml at probe() time, removed after release(). (login/logout)
2. The user-mode file handles open/close.
3. Import symbols by client modules like exofs.

TODO:
  This API is not enough for the pNFS-objects LD. A more versatile
  API will be needed. Proposed API could be:
  struct osd_dev *osduld_sysid_lookup(const char id[OSD_SYSTEMID_LEN]);

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
---
 drivers/scsi/osd/osd_uld.c   |   63 ++++++++++++++++++++++++++++++++++++++++++
 include/scsi/osd_initiator.h |    4 ++
 2 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index f6f9a99..cd4ca7c 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -173,6 +173,69 @@ static const struct file_operations osd_fops = {
 	.unlocked_ioctl = osd_uld_ioctl,
 };
 
+struct osd_dev *osduld_path_lookup(const char *path)
+{
+	struct nameidata nd;
+	struct inode *inode;
+	struct cdev *cdev;
+	struct osd_uld_device *uninitialized_var(oud);
+	int error;
+
+	if (!path || !*path) {
+		OSD_ERR("Mount with !path || !*path\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	error = path_lookup(path, LOOKUP_FOLLOW, &nd);
+	if (error) {
+		OSD_ERR("path_lookup of %s faild=>%d\n", path, error);
+		return ERR_PTR(error);
+	}
+
+	inode = nd.path.dentry->d_inode;
+	error = -EINVAL; /* Not the right device e.g osd_uld_device */
+	if (!S_ISCHR(inode->i_mode)) {
+		OSD_DEBUG("!S_ISCHR()\n");
+		goto out;
+	}
+
+	cdev = inode->i_cdev;
+	if (!cdev) {
+		OSD_ERR("Before mounting an OSD Based filesystem\n");
+		OSD_ERR("  user-mode must open+close the %s device\n", path);
+		OSD_ERR("  Example: bash: echo < %s\n", path);
+		goto out;
+	}
+
+	/* The Magic wand. Is it our char-dev */
+	/* TODO: Support sg devices */
+	if (cdev->owner != THIS_MODULE) {
+		OSD_ERR("Error mounting %s - is not an OSD device\n", path);
+		goto out;
+	}
+
+	oud = container_of(cdev, struct osd_uld_device, cdev);
+
+	__uld_get(oud);
+	error = 0;
+
+out:
+	path_put(&nd.path);
+	return error ? ERR_PTR(error) : &oud->od;
+}
+EXPORT_SYMBOL(osduld_path_lookup);
+
+void osduld_put_device(struct osd_dev *od)
+{
+	if (od) {
+		struct osd_uld_device *oud = container_of(od,
+						struct osd_uld_device, od);
+
+		__uld_put(oud);
+	}
+}
+EXPORT_SYMBOL(osduld_put_device);
+
 /*
  * Scsi Device operations
  */
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index a5dbbdd..e84dc7a 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -33,6 +33,10 @@ struct osd_dev {
 	unsigned def_timeout;
 };
 
+/* Retrieve/return osd_dev(s) for use by Kernel clients */
+struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/
+void osduld_put_device(struct osd_dev *od);
+
 /* Add/remove test ioctls from external modules */
 typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
 int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 07/16] libosd: attributes Support
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (5 preceding siblings ...)
  2009-01-25 14:58 ` [PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel Boaz Harrosh
@ 2009-01-25 14:59 ` Boaz Harrosh
  2009-01-25 15:03 ` [PATCH 08/16] libosd: OSD Security processing stubs Boaz Harrosh
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 14:59 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Support for both List-Mode and Page-Mode osd attributes. One of
these operations may be added to most other operations.

Define the OSD standard's attribute pages constants and structures
(osd_attributes.h)

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 drivers/scsi/osd/osd_initiator.c |  579 ++++++++++++++++++++++++++++++++++++++
 include/scsi/osd_attributes.h    |  327 +++++++++++++++++++++
 2 files changed, 906 insertions(+), 0 deletions(-)
 create mode 100644 include/scsi/osd_attributes.h

diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 0e6d906..b982d76 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -45,6 +45,10 @@
 
 #include "osd_debug.h"
 
+#ifndef __unused
+#    define __unused			__attribute__((unused))
+#endif
+
 enum { OSD_REQ_RETRIES = 1 };
 
 MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
@@ -63,6 +67,50 @@ static unsigned _osd_req_cdb_len(struct osd_request *or)
 	return OSDv1_TOTAL_CDB_LEN;
 }
 
+static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len)
+{
+	return osdv1_attr_list_elem_size(len);
+}
+
+static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head)
+{
+	return osdv1_list_size(list_head);
+}
+
+static unsigned _osd_req_sizeof_alist_header(struct osd_request *or)
+{
+	return sizeof(struct osdv1_attributes_list_header);
+}
+
+static void _osd_req_set_alist_type(struct osd_request *or,
+	void *list, int list_type)
+{
+	struct osdv1_attributes_list_header *attr_list = list;
+
+	memset(attr_list, 0, sizeof(*attr_list));
+	attr_list->type = list_type;
+}
+
+static bool _osd_req_is_alist_type(struct osd_request *or,
+	void *list, int list_type)
+{
+	if (!list)
+		return false;
+
+	if (1) {
+		struct osdv1_attributes_list_header *attr_list = list;
+
+		return attr_list->type == list_type;
+	}
+}
+
+static osd_cdb_offset osd_req_encode_offset(struct osd_request *or,
+	u64 offset, unsigned *padding)
+{
+	return __osd_encode_offset(offset, padding,
+				  OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
+}
+
 void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)
 {
 	memset(osdd, 0, sizeof(*osdd));
@@ -125,10 +173,25 @@ static void _abort_unexecuted_bios(struct request *rq)
 	}
 }
 
+static void _osd_free_seg(struct osd_request *or __unused,
+	struct _osd_req_data_segment *seg)
+{
+	if (!seg->buff || !seg->alloc_size)
+		return;
+
+	kfree(seg->buff);
+	seg->buff = NULL;
+	seg->alloc_size = 0;
+}
+
 void osd_end_request(struct osd_request *or)
 {
 	struct request *rq = or->request;
 
+	_osd_free_seg(or, &or->set_attr);
+	_osd_free_seg(or, &or->enc_get_attr);
+	_osd_free_seg(or, &or->get_attr);
+
 	if (rq) {
 		if (rq->next_rq) {
 			_abort_unexecuted_bios(rq->next_rq);
@@ -176,6 +239,54 @@ int osd_execute_request_async(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_execute_request_async);
 
+u8 sg_out_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
+u8 sg_in_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
+
+static int _osd_realloc_seg(struct osd_request *or,
+	struct _osd_req_data_segment *seg, unsigned max_bytes)
+{
+	void *buff;
+
+	if (seg->alloc_size >= max_bytes)
+		return 0;
+
+	buff = krealloc(seg->buff, max_bytes, or->alloc_flags);
+	if (!buff) {
+		OSD_ERR("Failed to Realloc %d-bytes was-%d\n", max_bytes,
+			seg->alloc_size);
+		return -ENOMEM;
+	}
+
+	memset(buff + seg->alloc_size, 0, max_bytes - seg->alloc_size);
+	seg->buff = buff;
+	seg->alloc_size = max_bytes;
+	return 0;
+}
+
+static int _alloc_set_attr_list(struct osd_request *or,
+	const struct osd_attr *oa, unsigned nelem, unsigned add_bytes)
+{
+	unsigned total_bytes = add_bytes;
+
+	for (; nelem; --nelem, ++oa)
+		total_bytes += _osd_req_alist_elem_size(or, oa->len);
+
+	OSD_DEBUG("total_bytes=%d\n", total_bytes);
+	return _osd_realloc_seg(or, &or->set_attr, total_bytes);
+}
+
+static int _alloc_get_attr_desc(struct osd_request *or, unsigned max_bytes)
+{
+	OSD_DEBUG("total_bytes=%d\n", max_bytes);
+	return _osd_realloc_seg(or, &or->enc_get_attr, max_bytes);
+}
+
+static int _alloc_get_attr_list(struct osd_request *or)
+{
+	OSD_DEBUG("total_bytes=%d\n", or->get_attr.total_bytes);
+	return _osd_realloc_seg(or, &or->get_attr, or->get_attr.total_bytes);
+}
+
 /*
  * Common to all OSD commands
  */
@@ -284,6 +395,410 @@ void osd_req_read(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_req_read);
 
+void osd_req_get_attributes(struct osd_request *or,
+	const struct osd_obj_id *obj)
+{
+	_osd_req_encode_common(or, OSD_ACT_GET_ATTRIBUTES, obj, 0, 0);
+}
+EXPORT_SYMBOL(osd_req_get_attributes);
+
+void osd_req_set_attributes(struct osd_request *or,
+	const struct osd_obj_id *obj)
+{
+	_osd_req_encode_common(or, OSD_ACT_SET_ATTRIBUTES, obj, 0, 0);
+}
+EXPORT_SYMBOL(osd_req_set_attributes);
+
+/*
+ * Attributes List-mode
+ */
+
+int osd_req_add_set_attr_list(struct osd_request *or,
+	const struct osd_attr *oa, unsigned nelem)
+{
+	unsigned total_bytes = or->set_attr.total_bytes;
+	void *attr_last;
+	int ret;
+
+	if (or->attributes_mode &&
+	    or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
+
+	if (!total_bytes) { /* first-time: allocate and put list header */
+		total_bytes = _osd_req_sizeof_alist_header(or);
+		ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
+		if (ret)
+			return ret;
+		_osd_req_set_alist_type(or, or->set_attr.buff,
+					OSD_ATTR_LIST_SET_RETRIEVE);
+	}
+	attr_last = or->set_attr.buff + total_bytes;
+
+	for (; nelem; --nelem) {
+		struct osd_attributes_list_element *attr;
+		unsigned elem_size = _osd_req_alist_elem_size(or, oa->len);
+
+		total_bytes += elem_size;
+		if (unlikely(or->set_attr.alloc_size < total_bytes)) {
+			or->set_attr.total_bytes = total_bytes - elem_size;
+			ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
+			if (ret)
+				return ret;
+			attr_last =
+				or->set_attr.buff + or->set_attr.total_bytes;
+		}
+
+		attr = attr_last;
+		attr->attr_page = cpu_to_be32(oa->attr_page);
+		attr->attr_id = cpu_to_be32(oa->attr_id);
+		attr->attr_bytes = cpu_to_be16(oa->len);
+		memcpy(attr->attr_val, oa->val_ptr, oa->len);
+
+		attr_last += elem_size;
+		++oa;
+	}
+
+	or->set_attr.total_bytes = total_bytes;
+	return 0;
+}
+EXPORT_SYMBOL(osd_req_add_set_attr_list);
+
+static int _append_map_kern(struct request *req,
+	void *buff, unsigned len, gfp_t flags)
+{
+	struct bio *bio;
+	int ret;
+
+	bio = bio_map_kern(req->q, buff, len, flags);
+	if (IS_ERR(bio)) {
+		OSD_ERR("Failed bio_map_kern(%p, %d) => %ld\n", buff, len,
+			PTR_ERR(bio));
+		return PTR_ERR(bio);
+	}
+	ret = blk_rq_append_bio(req->q, req, bio);
+	if (ret) {
+		OSD_ERR("Failed blk_rq_append_bio(%p) => %d\n", bio, ret);
+		bio_put(bio);
+	}
+	return ret;
+}
+
+static int _req_append_segment(struct osd_request *or,
+	unsigned padding, struct _osd_req_data_segment *seg,
+	struct _osd_req_data_segment *last_seg, struct _osd_io_info *io)
+{
+	void *pad_buff;
+	int ret;
+
+	if (padding) {
+		/* check if we can just add it to last buffer */
+		if (last_seg &&
+		    (padding <= last_seg->alloc_size - last_seg->total_bytes))
+			pad_buff = last_seg->buff + last_seg->total_bytes;
+		else
+			pad_buff = io->pad_buff;
+
+		ret = _append_map_kern(io->req, pad_buff, padding,
+				       or->alloc_flags);
+		if (ret)
+			return ret;
+		io->total_bytes += padding;
+	}
+
+	ret = _append_map_kern(io->req, seg->buff, seg->total_bytes,
+			       or->alloc_flags);
+	if (ret)
+		return ret;
+
+	io->total_bytes += seg->total_bytes;
+	OSD_DEBUG("padding=%d buff=%p total_bytes=%d\n", padding, seg->buff,
+		  seg->total_bytes);
+	return 0;
+}
+
+static int _osd_req_finalize_set_attr_list(struct osd_request *or)
+{
+	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
+	unsigned padding;
+	int ret;
+
+	if (!or->set_attr.total_bytes) {
+		cdbh->attrs_list.set_attr_offset = OSD_OFFSET_UNUSED;
+		return 0;
+	}
+
+	cdbh->attrs_list.set_attr_bytes = cpu_to_be32(or->set_attr.total_bytes);
+	cdbh->attrs_list.set_attr_offset =
+		osd_req_encode_offset(or, or->out.total_bytes, &padding);
+
+	ret = _req_append_segment(or, padding, &or->set_attr,
+				  or->out.last_seg, &or->out);
+	if (ret)
+		return ret;
+
+	or->out.last_seg = &or->set_attr;
+	return 0;
+}
+
+int osd_req_add_get_attr_list(struct osd_request *or,
+	const struct osd_attr *oa, unsigned nelem)
+{
+	unsigned total_bytes = or->enc_get_attr.total_bytes;
+	void *attr_last;
+	int ret;
+
+	if (or->attributes_mode &&
+	    or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
+
+	/* first time calc data-in list header size */
+	if (!or->get_attr.total_bytes)
+		or->get_attr.total_bytes = _osd_req_sizeof_alist_header(or);
+
+	/* calc data-out info */
+	if (!total_bytes) { /* first-time: allocate and put list header */
+		unsigned max_bytes;
+
+		total_bytes = _osd_req_sizeof_alist_header(or);
+		max_bytes = total_bytes +
+			nelem * sizeof(struct osd_attributes_list_attrid);
+		ret = _alloc_get_attr_desc(or, max_bytes);
+		if (ret)
+			return ret;
+
+		_osd_req_set_alist_type(or, or->enc_get_attr.buff,
+					OSD_ATTR_LIST_GET);
+	}
+	attr_last = or->enc_get_attr.buff + total_bytes;
+
+	for (; nelem; --nelem) {
+		struct osd_attributes_list_attrid *attrid;
+		const unsigned cur_size = sizeof(*attrid);
+
+		total_bytes += cur_size;
+		if (unlikely(or->enc_get_attr.alloc_size < total_bytes)) {
+			or->enc_get_attr.total_bytes = total_bytes - cur_size;
+			ret = _alloc_get_attr_desc(or,
+					total_bytes + nelem * sizeof(*attrid));
+			if (ret)
+				return ret;
+			attr_last = or->enc_get_attr.buff +
+				or->enc_get_attr.total_bytes;
+		}
+
+		attrid = attr_last;
+		attrid->attr_page = cpu_to_be32(oa->attr_page);
+		attrid->attr_id = cpu_to_be32(oa->attr_id);
+
+		attr_last += cur_size;
+
+		/* calc data-in size */
+		or->get_attr.total_bytes +=
+			_osd_req_alist_elem_size(or, oa->len);
+		++oa;
+	}
+
+	or->enc_get_attr.total_bytes = total_bytes;
+
+	OSD_DEBUG(
+	       "get_attr.total_bytes=%u(%u) enc_get_attr.total_bytes=%u(%Zu)\n",
+	       or->get_attr.total_bytes,
+	       or->get_attr.total_bytes - _osd_req_sizeof_alist_header(or),
+	       or->enc_get_attr.total_bytes,
+	       (or->enc_get_attr.total_bytes - _osd_req_sizeof_alist_header(or))
+			/ sizeof(struct osd_attributes_list_attrid));
+
+	return 0;
+}
+EXPORT_SYMBOL(osd_req_add_get_attr_list);
+
+static int _osd_req_finalize_get_attr_list(struct osd_request *or)
+{
+	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
+	unsigned out_padding;
+	unsigned in_padding;
+	int ret;
+
+	if (!or->enc_get_attr.total_bytes) {
+		cdbh->attrs_list.get_attr_desc_offset = OSD_OFFSET_UNUSED;
+		cdbh->attrs_list.get_attr_offset = OSD_OFFSET_UNUSED;
+		return 0;
+	}
+
+	ret = _alloc_get_attr_list(or);
+	if (ret)
+		return ret;
+
+	/* The out-going buffer info update */
+	OSD_DEBUG("out-going\n");
+	cdbh->attrs_list.get_attr_desc_bytes =
+		cpu_to_be32(or->enc_get_attr.total_bytes);
+
+	cdbh->attrs_list.get_attr_desc_offset =
+		osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
+
+	ret = _req_append_segment(or, out_padding, &or->enc_get_attr,
+				  or->out.last_seg, &or->out);
+	if (ret)
+		return ret;
+	or->out.last_seg = &or->enc_get_attr;
+
+	/* The incoming buffer info update */
+	OSD_DEBUG("in-coming\n");
+	cdbh->attrs_list.get_attr_alloc_length =
+		cpu_to_be32(or->get_attr.total_bytes);
+
+	cdbh->attrs_list.get_attr_offset =
+		osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
+
+	ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
+				  &or->in);
+	if (ret)
+		return ret;
+	or->in.last_seg = &or->get_attr;
+
+	return 0;
+}
+
+int osd_req_decode_get_attr_list(struct osd_request *or,
+	struct osd_attr *oa, int *nelem, void **iterator)
+{
+	unsigned cur_bytes, returned_bytes;
+	int n;
+	const unsigned sizeof_attr_list = _osd_req_sizeof_alist_header(or);
+	void *cur_p;
+
+	if (!_osd_req_is_alist_type(or, or->get_attr.buff,
+				    OSD_ATTR_LIST_SET_RETRIEVE)) {
+		oa->attr_page = 0;
+		oa->attr_id = 0;
+		oa->val_ptr = NULL;
+		oa->len = 0;
+		*iterator = NULL;
+		return 0;
+	}
+
+	if (*iterator) {
+		BUG_ON((*iterator < or->get_attr.buff) ||
+		     (or->get_attr.buff + or->get_attr.alloc_size < *iterator));
+		cur_p = *iterator;
+		cur_bytes = (*iterator - or->get_attr.buff) - sizeof_attr_list;
+		returned_bytes = or->get_attr.total_bytes;
+	} else { /* first time decode the list header */
+		cur_bytes = sizeof_attr_list;
+		returned_bytes = _osd_req_alist_size(or, or->get_attr.buff) +
+					sizeof_attr_list;
+
+		cur_p = or->get_attr.buff + sizeof_attr_list;
+
+		if (returned_bytes > or->get_attr.alloc_size) {
+			OSD_DEBUG("target report: space was not big enough! "
+				  "Allocate=%u Needed=%u\n",
+				  or->get_attr.alloc_size,
+				  returned_bytes + sizeof_attr_list);
+
+			returned_bytes =
+				or->get_attr.alloc_size - sizeof_attr_list;
+		}
+		or->get_attr.total_bytes = returned_bytes;
+	}
+
+	for (n = 0; (n < *nelem) && (cur_bytes < returned_bytes); ++n) {
+		struct osd_attributes_list_element *attr = cur_p;
+		unsigned inc;
+
+		oa->len = be16_to_cpu(attr->attr_bytes);
+		inc = _osd_req_alist_elem_size(or, oa->len);
+		OSD_DEBUG("oa->len=%d inc=%d cur_bytes=%d\n",
+			  oa->len, inc, cur_bytes);
+		cur_bytes += inc;
+		if (cur_bytes > returned_bytes) {
+			OSD_ERR("BAD FOOD from target. list not valid!"
+				"c=%d r=%d n=%d\n",
+				cur_bytes, returned_bytes, n);
+			oa->val_ptr = NULL;
+			break;
+		}
+
+		oa->attr_page = be32_to_cpu(attr->attr_page);
+		oa->attr_id = be32_to_cpu(attr->attr_id);
+		oa->val_ptr = attr->attr_val;
+
+		cur_p += inc;
+		++oa;
+	}
+
+	*iterator = (returned_bytes - cur_bytes) ? cur_p : NULL;
+	*nelem = n;
+	return returned_bytes - cur_bytes;
+}
+EXPORT_SYMBOL(osd_req_decode_get_attr_list);
+
+/*
+ * Attributes Page-mode
+ */
+
+int osd_req_add_get_attr_page(struct osd_request *or,
+	u32 page_id, void *attar_page, unsigned max_page_len,
+	const struct osd_attr *set_one_attr)
+{
+	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
+
+	if (or->attributes_mode &&
+	    or->attributes_mode != OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	or->attributes_mode = OSD_CDB_GET_ATTR_PAGE_SET_ONE;
+
+	or->get_attr.buff = attar_page;
+	or->get_attr.total_bytes = max_page_len;
+
+	or->set_attr.buff = set_one_attr->val_ptr;
+	or->set_attr.total_bytes = set_one_attr->len;
+
+	cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id);
+	cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len);
+	/* ocdb->attrs_page.get_attr_offset; */
+
+	cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page);
+	cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id);
+	cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len);
+	/* ocdb->attrs_page.set_attr_offset; */
+	return 0;
+}
+EXPORT_SYMBOL(osd_req_add_get_attr_page);
+
+static int _osd_req_finalize_attr_page(struct osd_request *or)
+{
+	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
+	unsigned in_padding, out_padding;
+	int ret;
+
+	/* returned page */
+	cdbh->attrs_page.get_attr_offset =
+		osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
+
+	ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
+				  &or->in);
+	if (ret)
+		return ret;
+
+	/* set one value */
+	cdbh->attrs_page.set_attr_offset =
+		osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
+
+	ret = _req_append_segment(or, out_padding, &or->enc_get_attr, NULL,
+				  &or->out);
+	return ret;
+}
+
 /*
  * osd_finalize_request and helpers
  */
@@ -378,9 +893,31 @@ int osd_finalize_request(struct osd_request *or,
 			_LLU(or->in.total_bytes), or->in.req->data_len);
 	}
 
+	or->out.pad_buff = sg_out_pad_buffer;
+	or->in.pad_buff = sg_in_pad_buffer;
+
 	if (!or->attributes_mode)
 		or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
 	cdbh->command_specific_options |= or->attributes_mode;
+	if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
+		ret = _osd_req_finalize_attr_page(or);
+	} else {
+		/* TODO: I think that for the GET_ATTR command these 2 should
+		 * be reversed to keep them in execution order (for embeded
+		 * targets with low memory footprint)
+		 */
+		ret = _osd_req_finalize_set_attr_list(or);
+		if (ret) {
+			OSD_DEBUG("_osd_req_finalize_set_attr_list failed\n");
+			return ret;
+		}
+
+		ret = _osd_req_finalize_get_attr_list(or);
+		if (ret) {
+			OSD_DEBUG("_osd_req_finalize_get_attr_list failed\n");
+			return ret;
+		}
+	}
 
 	or->request->cmd = or->cdb.buff;
 	or->request->cmd_len = _osd_req_cdb_len(or);
@@ -446,3 +983,45 @@ void osd_set_caps(struct osd_cdb *cdb, const void *caps)
 {
 	memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN);
 }
+
+/*
+ * Declared in osd_protocol.h
+ * 4.12.5 Data-In and Data-Out buffer offsets
+ * byte offset = mantissa * (2^(exponent+8))
+ * Returns the smallest allowed encoded offset that contains given @offset
+ * The actual encoded offset returned is @offset + *@padding.
+ */
+osd_cdb_offset __osd_encode_offset(
+	u64 offset, unsigned *padding, int min_shift, int max_shift)
+{
+	u64 try_offset = -1, mod, align;
+	osd_cdb_offset be32_offset;
+	int shift;
+
+	*padding = 0;
+	if (!offset)
+		return 0;
+
+	for (shift = min_shift; shift < max_shift; ++shift) {
+		try_offset = offset >> shift;
+		if (try_offset < (1 << OSD_OFFSET_MAX_BITS))
+			break;
+	}
+
+	BUG_ON(shift == max_shift);
+
+	align = 1 << shift;
+	mod = offset & (align - 1);
+	if (mod) {
+		*padding = align - mod;
+		try_offset += 1;
+	}
+
+	try_offset |= ((shift - 8) & 0xf) << 28;
+	be32_offset = cpu_to_be32((u32)try_offset);
+
+	OSD_DEBUG("offset=%llu mantissa=%llu exp=%d encoded=%x pad=%d\n",
+		 _LLU(offset), _LLU(try_offset & 0x0FFFFFFF), shift,
+		 be32_offset, *padding);
+	return be32_offset;
+}
diff --git a/include/scsi/osd_attributes.h b/include/scsi/osd_attributes.h
new file mode 100644
index 0000000..f888a6f
--- /dev/null
+++ b/include/scsi/osd_attributes.h
@@ -0,0 +1,327 @@
+#ifndef __OSD_ATTRIBUTES_H__
+#define __OSD_ATTRIBUTES_H__
+
+#include "osd_protocol.h"
+
+/*
+ * Contains types and constants that define attribute pages and attribute
+ * numbers and their data types.
+ */
+
+#define ATTR_SET(pg, id, l, ptr) \
+	{ .attr_page = pg, .attr_id = id, .len = l, .val_ptr = ptr }
+
+#define ATTR_DEF(pg, id, l) ATTR_SET(pg, id, l, NULL)
+
+/* osd-r10 4.7.3 Attributes pages */
+enum {
+	OSD_APAGE_OBJECT_FIRST		= 0x0,
+	OSD_APAGE_OBJECT_DIRECTORY	= 0,
+	OSD_APAGE_OBJECT_INFORMATION	= 1,
+	OSD_APAGE_OBJECT_QUOTAS		= 2,
+	OSD_APAGE_OBJECT_TIMESTAMP	= 3,
+	OSD_APAGE_OBJECT_COLLECTIONS	= 4,
+	OSD_APAGE_OBJECT_SECURITY	= 5,
+	OSD_APAGE_OBJECT_LAST		= 0x2fffffff,
+
+	OSD_APAGE_PARTITION_FIRST	= 0x30000000,
+	OSD_APAGE_PARTITION_DIRECTORY	= OSD_APAGE_PARTITION_FIRST + 0,
+	OSD_APAGE_PARTITION_INFORMATION = OSD_APAGE_PARTITION_FIRST + 1,
+	OSD_APAGE_PARTITION_QUOTAS	= OSD_APAGE_PARTITION_FIRST + 2,
+	OSD_APAGE_PARTITION_TIMESTAMP	= OSD_APAGE_PARTITION_FIRST + 3,
+	OSD_APAGE_PARTITION_SECURITY	= OSD_APAGE_PARTITION_FIRST + 5,
+	OSD_APAGE_PARTITION_LAST	= 0x5FFFFFFF,
+
+	OSD_APAGE_COLLECTION_FIRST	= 0x60000000,
+	OSD_APAGE_COLLECTION_DIRECTORY	= OSD_APAGE_COLLECTION_FIRST + 0,
+	OSD_APAGE_COLLECTION_INFORMATION = OSD_APAGE_COLLECTION_FIRST + 1,
+	OSD_APAGE_COLLECTION_TIMESTAMP	= OSD_APAGE_COLLECTION_FIRST + 3,
+	OSD_APAGE_COLLECTION_SECURITY	= OSD_APAGE_COLLECTION_FIRST + 5,
+	OSD_APAGE_COLLECTION_LAST	= 0x8FFFFFFF,
+
+	OSD_APAGE_ROOT_FIRST		= 0x90000000,
+	OSD_APAGE_ROOT_DIRECTORY	= OSD_APAGE_ROOT_FIRST + 0,
+	OSD_APAGE_ROOT_INFORMATION	= OSD_APAGE_ROOT_FIRST + 1,
+	OSD_APAGE_ROOT_QUOTAS		= OSD_APAGE_ROOT_FIRST + 2,
+	OSD_APAGE_ROOT_TIMESTAMP	= OSD_APAGE_ROOT_FIRST + 3,
+	OSD_APAGE_ROOT_SECURITY		= OSD_APAGE_ROOT_FIRST + 5,
+	OSD_APAGE_ROOT_LAST		= 0xBFFFFFFF,
+
+	OSD_APAGE_RESERVED_TYPE_FIRST	= 0xC0000000,
+	OSD_APAGE_RESERVED_TYPE_LAST	= 0xEFFFFFFF,
+
+	OSD_APAGE_COMMON_FIRST		= 0xF0000000,
+	OSD_APAGE_COMMON_LAST		= 0xFFFFFFFE,
+
+	OSD_APAGE_REQUEST_ALL		= 0xFFFFFFFF,
+};
+
+/* subcategories of attr pages within each range above */
+enum {
+	OSD_APAGE_STD_FIRST		= 0x0,
+	OSD_APAGE_STD_DIRECTORY		= 0,
+	OSD_APAGE_STD_INFORMATION	= 1,
+	OSD_APAGE_STD_QUOTAS		= 2,
+	OSD_APAGE_STD_TIMESTAMP		= 3,
+	OSD_APAGE_STD_COLLECTIONS	= 4,
+	OSD_APAGE_STD_POLICY_SECURITY	= 5,
+	OSD_APAGE_STD_LAST		= 0x0000007F,
+
+	OSD_APAGE_RESERVED_FIRST	= 0x00000080,
+	OSD_APAGE_RESERVED_LAST		= 0x00007FFF,
+
+	OSD_APAGE_OTHER_STD_FIRST	= 0x00008000,
+	OSD_APAGE_OTHER_STD_LAST	= 0x0000EFFF,
+
+	OSD_APAGE_PUBLIC_FIRST		= 0x0000F000,
+	OSD_APAGE_PUBLIC_LAST		= 0x0000FFFF,
+
+	OSD_APAGE_APP_DEFINED_FIRST	= 0x00010000,
+	OSD_APAGE_APP_DEFINED_LAST	= 0x1FFFFFFF,
+
+	OSD_APAGE_VENDOR_SPECIFIC_FIRST	= 0x20000000,
+	OSD_APAGE_VENDOR_SPECIFIC_LAST	= 0x2FFFFFFF,
+};
+
+enum {
+	OSD_ATTR_PAGE_IDENTIFICATION = 0, /* in all pages 40 bytes */
+};
+
+struct page_identification {
+	u8 vendor_identification[8];
+	u8 page_identification[32];
+}  __packed;
+
+struct osd_attr_page_header {
+	__be32 page_number;
+	__be32 page_length;
+} __packed;
+
+/* 7.1.2.8 Root Information attributes page (OSD_APAGE_ROOT_INFORMATION) */
+enum {
+	OSD_ATTR_RI_OSD_SYSTEM_ID            = 0x3,   /* 20       */
+	OSD_ATTR_RI_VENDOR_IDENTIFICATION    = 0x4,   /* 8        */
+	OSD_ATTR_RI_PRODUCT_IDENTIFICATION   = 0x5,   /* 16       */
+	OSD_ATTR_RI_PRODUCT_MODEL            = 0x6,   /* 32       */
+	OSD_ATTR_RI_PRODUCT_REVISION_LEVEL   = 0x7,   /* 4        */
+	OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER    = 0x8,   /* variable */
+	OSD_ATTR_RI_OSD_NAME                 = 0x9,   /* variable */
+	OSD_ATTR_RI_TOTAL_CAPACITY           = 0x80,  /* 8        */
+	OSD_ATTR_RI_USED_CAPACITY            = 0x81,  /* 8        */
+	OSD_ATTR_RI_NUMBER_OF_PARTITIONS     = 0xC0,  /* 8        */
+	OSD_ATTR_RI_CLOCK                    = 0x100, /* 6        */
+};
+/* Root_Information_attributes_page does not have a get_page structure */
+
+/* 7.1.2.9 Partition Information attributes page
+ * (OSD_APAGE_PARTITION_INFORMATION)
+ */
+enum {
+	OSD_ATTR_PI_PARTITION_ID            = 0x1,     /* 8        */
+	OSD_ATTR_PI_USERNAME                = 0x9,     /* variable */
+	OSD_ATTR_PI_USED_CAPACITY           = 0x81,    /* 8        */
+	OSD_ATTR_PI_NUMBER_OF_OBJECTS       = 0xC1,    /* 8        */
+};
+/* Partition Information attributes page does not have a get_page structure */
+
+/* 7.1.2.10 Collection Information attributes page
+ * (OSD_APAGE_COLLECTION_INFORMATION)
+ */
+enum {
+	OSD_ATTR_CI_PARTITION_ID           = 0x1,       /* 8        */
+	OSD_ATTR_CI_COLLECTION_OBJECT_ID   = 0x2,       /* 8        */
+	OSD_ATTR_CI_USERNAME               = 0x9,       /* variable */
+	OSD_ATTR_CI_USED_CAPACITY          = 0x81,      /* 8        */
+};
+/* Collection Information attributes page does not have a get_page structure */
+
+/* 7.1.2.11 User Object Information attributes page
+ * (OSD_APAGE_OBJECT_INFORMATION)
+ */
+enum {
+	OSD_ATTR_OI_PARTITION_ID         = 0x1,       /* 8        */
+	OSD_ATTR_OI_OBJECT_ID            = 0x2,       /* 8        */
+	OSD_ATTR_OI_USERNAME             = 0x9,       /* variable */
+	OSD_ATTR_OI_USED_CAPACITY        = 0x81,      /* 8        */
+	OSD_ATTR_OI_LOGICAL_LENGTH       = 0x82,      /* 8        */
+};
+/* Object Information attributes page does not have a get_page structure */
+
+/* 7.1.2.12 Root Quotas attributes page (OSD_APAGE_ROOT_QUOTAS) */
+enum {
+	OSD_ATTR_RQ_DEFAULT_MAXIMUM_USER_OBJECT_LENGTH     = 0x1,      /* 8  */
+	OSD_ATTR_RQ_PARTITION_CAPACITY_QUOTA               = 0x10001,  /* 8  */
+	OSD_ATTR_RQ_PARTITION_OBJECT_COUNT                 = 0x10002,  /* 8  */
+	OSD_ATTR_RQ_PARTITION_COLLECTIONS_PER_USER_OBJECT  = 0x10081,  /* 4  */
+	OSD_ATTR_RQ_PARTITION_COUNT                        = 0x20002,  /* 8  */
+};
+
+struct Root_Quotas_attributes_page {
+	struct osd_attr_page_header hdr; /* id=R+2, size=0x24 */
+	__be64 default_maximum_user_object_length;
+	__be64 partition_capacity_quota;
+	__be64 partition_object_count;
+	__be64 partition_collections_per_user_object;
+	__be64 partition_count;
+}  __packed;
+
+/* 7.1.2.13 Partition Quotas attributes page (OSD_APAGE_PARTITION_QUOTAS)*/
+enum {
+	OSD_ATTR_PQ_DEFAULT_MAXIMUM_USER_OBJECT_LENGTH  = 0x1,        /* 8 */
+	OSD_ATTR_PQ_CAPACITY_QUOTA                      = 0x10001,    /* 8 */
+	OSD_ATTR_PQ_OBJECT_COUNT                        = 0x10002,    /* 8 */
+	OSD_ATTR_PQ_COLLECTIONS_PER_USER_OBJECT         = 0x10081,    /* 4 */
+};
+
+struct Partition_Quotas_attributes_page {
+	struct osd_attr_page_header hdr; /* id=P+2, size=0x1C */
+	__be64 default_maximum_user_object_length;
+	__be64 capacity_quota;
+	__be64 object_count;
+	__be64 collections_per_user_object;
+}  __packed;
+
+/* 7.1.2.14 User Object Quotas attributes page (OSD_APAGE_OBJECT_QUOTAS) */
+enum {
+	OSD_ATTR_OQ_MAXIMUM_LENGTH  = 0x1,        /* 8 */
+};
+
+struct Object_Quotas_attributes_page {
+	struct osd_attr_page_header hdr; /* id=U+2, size=0x8 */
+	__be64 maximum_length;
+}  __packed;
+
+/* 7.1.2.15 Root Timestamps attributes page (OSD_APAGE_ROOT_TIMESTAMP) */
+enum {
+	OSD_ATTR_RT_ATTRIBUTES_ACCESSED_TIME  = 0x2,        /* 6 */
+	OSD_ATTR_RT_ATTRIBUTES_MODIFIED_TIME  = 0x3,        /* 6 */
+	OSD_ATTR_RT_TIMESTAMP_BYPASS          = 0xFFFFFFFE, /* 1 */
+};
+
+struct root_timestamps_attributes_page {
+	struct osd_attr_page_header hdr; /* id=R+3, size=0xD */
+	struct osd_timestamp attributes_accessed_time;
+	struct osd_timestamp attributes_modified_time;
+	u8 timestamp_bypass;
+}  __packed;
+
+/* 7.1.2.16 Partition Timestamps attributes page
+ * (OSD_APAGE_PARTITION_TIMESTAMP)
+ */
+enum {
+	OSD_ATTR_PT_CREATED_TIME              = 0x1,        /* 6 */
+	OSD_ATTR_PT_ATTRIBUTES_ACCESSED_TIME  = 0x2,        /* 6 */
+	OSD_ATTR_PT_ATTRIBUTES_MODIFIED_TIME  = 0x3,        /* 6 */
+	OSD_ATTR_PT_DATA_ACCESSED_TIME        = 0x4,        /* 6 */
+	OSD_ATTR_PT_DATA_MODIFIED_TIME        = 0x5,        /* 6 */
+	OSD_ATTR_PT_TIMESTAMP_BYPASS          = 0xFFFFFFFE, /* 1 */
+};
+
+struct partition_timestamps_attributes_page {
+	struct osd_attr_page_header hdr; /* id=P+3, size=0x1F */
+	struct osd_timestamp created_time;
+	struct osd_timestamp attributes_accessed_time;
+	struct osd_timestamp attributes_modified_time;
+	struct osd_timestamp data_accessed_time;
+	struct osd_timestamp data_modified_time;
+	u8 timestamp_bypass;
+}  __packed;
+
+/* 7.1.2.17/18 Collection/Object Timestamps attributes page
+ * (OSD_APAGE_COLLECTION_TIMESTAMP/OSD_APAGE_OBJECT_TIMESTAMP)
+ */
+enum {
+	OSD_ATTR_OT_CREATED_TIME              = 0x1,        /* 6 */
+	OSD_ATTR_OT_ATTRIBUTES_ACCESSED_TIME  = 0x2,        /* 6 */
+	OSD_ATTR_OT_ATTRIBUTES_MODIFIED_TIME  = 0x3,        /* 6 */
+	OSD_ATTR_OT_DATA_ACCESSED_TIME        = 0x4,        /* 6 */
+	OSD_ATTR_OT_DATA_MODIFIED_TIME        = 0x5,        /* 6 */
+};
+
+/* same for collection */
+struct object_timestamps_attributes_page {
+	struct osd_attr_page_header hdr; /* id=C+3/3, size=0x1E */
+	struct osd_timestamp created_time;
+	struct osd_timestamp attributes_accessed_time;
+	struct osd_timestamp attributes_modified_time;
+	struct osd_timestamp data_accessed_time;
+	struct osd_timestamp data_modified_time;
+}  __packed;
+
+/* 7.1.2.19 Collections attributes page */
+/* TBD */
+
+/* 7.1.2.20 Root Policy/Security attributes page (OSD_APAGE_ROOT_SECURITY) */
+enum {
+	OSD_ATTR_RS_DEFAULT_SECURITY_METHOD           = 0x1,       /* 1      */
+	OSD_ATTR_RS_OLDEST_VALID_NONCE_LIMIT          = 0x2,       /* 6      */
+	OSD_ATTR_RS_NEWEST_VALID_NONCE_LIMIT          = 0x3,       /* 6      */
+	OSD_ATTR_RS_PARTITION_DEFAULT_SECURITY_METHOD = 0x6,       /* 1      */
+	OSD_ATTR_RS_SUPPORTED_SECURITY_METHODS        = 0x7,       /* 2      */
+	OSD_ATTR_RS_ADJUSTABLE_CLOCK                  = 0x9,       /* 6      */
+	OSD_ATTR_RS_MASTER_KEY_IDENTIFIER             = 0x7FFD,    /* 0 or 7 */
+	OSD_ATTR_RS_ROOT_KEY_IDENTIFIER               = 0x7FFE,    /* 0 or 7 */
+	OSD_ATTR_RS_SUPPORTED_INTEGRITY_ALGORITHM_0   = 0x80000000,/* 1,(x16)*/
+	OSD_ATTR_RS_SUPPORTED_DH_GROUP_0              = 0x80000010,/* 1,(x16)*/
+};
+
+struct root_security_attributes_page {
+	struct osd_attr_page_header hdr; /* id=R+5, size=0x3F */
+	u8 default_security_method;
+	u8 partition_default_security_method;
+	__be16 supported_security_methods;
+	u8 mki_valid_rki_valid;
+	struct osd_timestamp oldest_valid_nonce_limit;
+	struct osd_timestamp newest_valid_nonce_limit;
+	struct osd_timestamp adjustable_clock;
+	u8 master_key_identifier[32-25];
+	u8 root_key_identifier[39-32];
+	u8 supported_integrity_algorithm[16];
+	u8 supported_dh_group[16];
+}  __packed;
+
+/* 7.1.2.21 Partition Policy/Security attributes page
+ * (OSD_APAGE_PARTITION_SECURITY)
+ */
+enum {
+	OSD_ATTR_PS_DEFAULT_SECURITY_METHOD        = 0x1,        /* 1      */
+	OSD_ATTR_PS_OLDEST_VALID_NONCE             = 0x2,        /* 6      */
+	OSD_ATTR_PS_NEWEST_VALID_NONCE             = 0x3,        /* 6      */
+	OSD_ATTR_PS_REQUEST_NONCE_LIST_DEPTH       = 0x4,        /* 2      */
+	OSD_ATTR_PS_FROZEN_WORKING_KEY_BIT_MASK    = 0x5,        /* 2      */
+	OSD_ATTR_PS_PARTITION_KEY_IDENTIFIER       = 0x7FFF,     /* 0 or 7 */
+	OSD_ATTR_PS_WORKING_KEY_IDENTIFIER_FIRST   = 0x8000,     /* 0 or 7 */
+	OSD_ATTR_PS_WORKING_KEY_IDENTIFIER_LAST    = 0x800F,     /* 0 or 7 */
+	OSD_ATTR_PS_POLICY_ACCESS_TAG              = 0x40000001, /* 4      */
+	OSD_ATTR_PS_USER_OBJECT_POLICY_ACCESS_TAG  = 0x40000002, /* 4      */
+};
+
+struct partition_security_attributes_page {
+	struct osd_attr_page_header hdr; /* id=p+5, size=0x8f */
+	u8 reserved[3];
+	u8 default_security_method;
+	struct osd_timestamp oldest_valid_nonce;
+	struct osd_timestamp newest_valid_nonce;
+	__be16 request_nonce_list_depth;
+	__be16 frozen_working_key_bit_mask;
+	__be32 policy_access_tag;
+	__be32 user_object_policy_access_tag;
+	u8 pki_valid;
+	__be16 wki_00_0f_vld;
+	struct osd_key_identifier partition_key_identifier;
+	struct osd_key_identifier working_key_identifiers[16];
+}  __packed;
+
+/* 7.1.2.22/23 Collection/Object Policy-Security attributes page
+ * (OSD_APAGE_COLLECTION_SECURITY/OSD_APAGE_OBJECT_SECURITY)
+ */
+enum {
+	OSD_ATTR_OS_POLICY_ACCESS_TAG              = 0x40000001, /* 4      */
+};
+
+struct object_security_attributes_page {
+	struct osd_attr_page_header hdr; /* id=C+5/5, size=4 */
+	__be32 policy_access_tag;
+}  __packed;
+
+#endif /*ndef __OSD_ATTRIBUTES_H__*/
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 08/16] libosd: OSD Security processing stubs
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (6 preceding siblings ...)
  2009-01-25 14:59 ` [PATCH 07/16] libosd: attributes Support Boaz Harrosh
@ 2009-01-25 15:03 ` Boaz Harrosh
  2009-01-25 15:05 ` [PATCH 09/16] libosd: Add Flush and List-objects support Boaz Harrosh
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 15:03 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Layout the signing of OSD's CDB and all-data security modes. The actual
code for signing the data and CDB is missing, but the code flow and the extra
buffer segments are all in place.

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 drivers/scsi/osd/osd_initiator.c |   86 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 86 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index b982d76..6849f26 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -111,6 +111,14 @@ static osd_cdb_offset osd_req_encode_offset(struct osd_request *or,
 				  OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
 }
 
+static struct osd_security_parameters *
+_osd_req_sec_params(struct osd_request *or)
+{
+	struct osd_cdb *ocdb = &or->cdb;
+
+	return &ocdb->v1.sec_params;
+}
+
 void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)
 {
 	memset(osdd, 0, sizeof(*osdd));
@@ -799,6 +807,64 @@ static int _osd_req_finalize_attr_page(struct osd_request *or)
 	return ret;
 }
 
+static int _osd_req_finalize_data_integrity(struct osd_request *or,
+	bool has_in, bool has_out, const u8 *cap_key)
+{
+	struct osd_security_parameters *sec_parms = _osd_req_sec_params(or);
+	int ret;
+
+	if (!osd_is_sec_alldata(sec_parms))
+		return 0;
+
+	if (has_out) {
+		struct _osd_req_data_segment seg = {
+			.buff = &or->out_data_integ,
+			.total_bytes = sizeof(or->out_data_integ),
+		};
+		unsigned pad;
+
+		or->out_data_integ.data_bytes = cpu_to_be64(
+			or->out.bio ? or->out.bio->bi_size : 0);
+		or->out_data_integ.set_attributes_bytes = cpu_to_be64(
+			or->set_attr.total_bytes);
+		or->out_data_integ.get_attributes_bytes = cpu_to_be64(
+			or->enc_get_attr.total_bytes);
+
+		sec_parms->data_out_integrity_check_offset =
+			osd_req_encode_offset(or, or->out.total_bytes, &pad);
+
+		ret = _req_append_segment(or, pad, &seg, or->out.last_seg,
+					  &or->out);
+		if (ret)
+			return ret;
+		or->out.last_seg = NULL;
+
+		/* they are now all chained to request sign them all together */
+		osd_sec_sign_data(&or->out_data_integ, or->out.req->bio,
+				  cap_key);
+	}
+
+	if (has_in) {
+		struct _osd_req_data_segment seg = {
+			.buff = &or->in_data_integ,
+			.total_bytes = sizeof(or->in_data_integ),
+		};
+		unsigned pad;
+
+		sec_parms->data_in_integrity_check_offset =
+			osd_req_encode_offset(or, or->in.total_bytes, &pad);
+
+		ret = _req_append_segment(or, pad, &seg, or->in.last_seg,
+					  &or->in);
+		if (ret)
+			return ret;
+
+		or->in.last_seg = NULL;
+	}
+
+	return 0;
+}
+
 /*
  * osd_finalize_request and helpers
  */
@@ -919,6 +985,12 @@ int osd_finalize_request(struct osd_request *or,
 		}
 	}
 
+	ret = _osd_req_finalize_data_integrity(or, has_in, has_out, cap_key);
+	if (ret)
+		return ret;
+
+	osd_sec_sign_cdb(&or->cdb, cap_key);
+
 	or->request->cmd = or->cdb.buff;
 	or->request->cmd_len = _osd_req_cdb_len(or);
 
@@ -984,6 +1056,20 @@ void osd_set_caps(struct osd_cdb *cdb, const void *caps)
 	memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN);
 }
 
+bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused)
+{
+	return false;
+}
+
+void osd_sec_sign_cdb(struct osd_cdb *ocdb __unused, const u8 *cap_key __unused)
+{
+}
+
+void osd_sec_sign_data(void *data_integ __unused,
+		       struct bio *bio __unused, const u8 *cap_key __unused)
+{
+}
+
 /*
  * Declared in osd_protocol.h
  * 4.12.5 Data-In and Data-Out buffer offsets
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 09/16] libosd: Add Flush and List-objects support
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (7 preceding siblings ...)
  2009-01-25 15:03 ` [PATCH 08/16] libosd: OSD Security processing stubs Boaz Harrosh
@ 2009-01-25 15:05 ` Boaz Harrosh
  2009-01-25 15:07 ` [PATCH 10/16] libosd: Not implemented commands Boaz Harrosh
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 15:05 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Add support for the various List-objects commands. List-partitions-in-device,
List-collections-in-partition, List-objects-in-partition,
List-objects-in-collection. All these support partial listing and continuation.

Add support for the different Flush commands and options.

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 drivers/scsi/osd/osd_initiator.c |  124 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 124 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 6849f26..5d9457b 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -104,6 +104,16 @@ static bool _osd_req_is_alist_type(struct osd_request *or,
 	}
 }
 
+/* This is for List-objects not Attributes-Lists */
+static void _osd_req_encode_olist(struct osd_request *or,
+	struct osd_obj_id_list *list)
+{
+	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
+
+	cdbh->v1.list_identifier = list->list_identifier;
+	cdbh->v1.start_address = list->continuation_id;
+}
+
 static osd_cdb_offset osd_req_encode_offset(struct osd_request *or,
 	u64 offset, unsigned *padding)
 {
@@ -340,6 +350,29 @@ void osd_req_format(struct osd_request *or, u64 tot_capacity)
 }
 EXPORT_SYMBOL(osd_req_format);
 
+int osd_req_list_dev_partitions(struct osd_request *or,
+	osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem)
+{
+	return osd_req_list_partition_objects(or, 0, initial_id, list, nelem);
+}
+EXPORT_SYMBOL(osd_req_list_dev_partitions);
+
+static void _osd_req_encode_flush(struct osd_request *or,
+	enum osd_options_flush_scope_values op)
+{
+	struct osd_cdb_head *ocdb = osd_cdb_head(&or->cdb);
+
+	ocdb->command_specific_options = op;
+}
+
+void osd_req_flush_obsd(struct osd_request *or,
+	enum osd_options_flush_scope_values op)
+{
+	_osd_req_encode_common(or, OSD_ACT_FLUSH_OSD, &osd_root_object, 0, 0);
+	_osd_req_encode_flush(or, op);
+}
+EXPORT_SYMBOL(osd_req_flush_obsd);
+
 /*
  * Partition commands
  */
@@ -366,6 +399,88 @@ void osd_req_remove_partition(struct osd_request *or, osd_id partition)
 }
 EXPORT_SYMBOL(osd_req_remove_partition);
 
+static int _osd_req_list_objects(struct osd_request *or,
+	__be16 action, const struct osd_obj_id *obj, osd_id initial_id,
+	struct osd_obj_id_list *list, unsigned nelem)
+{
+	struct request_queue *q = or->osd_dev->scsi_device->request_queue;
+	u64 len = nelem * sizeof(osd_id) + sizeof(*list);
+	struct bio *bio;
+
+	_osd_req_encode_common(or, action, obj, (u64)initial_id, len);
+
+	if (list->list_identifier)
+		_osd_req_encode_olist(or, list);
+
+	WARN_ON(or->in.bio);
+	bio = bio_map_kern(q, list, len, or->alloc_flags);
+	if (!bio) {
+		OSD_ERR("!!! Failed to allocate list_objects BIO\n");
+		return -ENOMEM;
+	}
+
+	bio->bi_rw &= ~(1 << BIO_RW);
+	or->in.bio = bio;
+	or->in.total_bytes = bio->bi_size;
+	return 0;
+}
+
+int osd_req_list_partition_collections(struct osd_request *or,
+	osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
+	unsigned nelem)
+{
+	struct osd_obj_id par = {
+		.partition = partition,
+		.id = 0,
+	};
+
+	return osd_req_list_collection_objects(or, &par, initial_id, list,
+					       nelem);
+}
+EXPORT_SYMBOL(osd_req_list_partition_collections);
+
+int osd_req_list_partition_objects(struct osd_request *or,
+	osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
+	unsigned nelem)
+{
+	struct osd_obj_id par = {
+		.partition = partition,
+		.id = 0,
+	};
+
+	return _osd_req_list_objects(or, OSD_ACT_LIST, &par, initial_id, list,
+				     nelem);
+}
+EXPORT_SYMBOL(osd_req_list_partition_objects);
+
+void osd_req_flush_partition(struct osd_request *or,
+	osd_id partition, enum osd_options_flush_scope_values op)
+{
+	_osd_req_encode_partition(or, OSD_ACT_FLUSH_PARTITION, partition);
+	_osd_req_encode_flush(or, op);
+}
+EXPORT_SYMBOL(osd_req_flush_partition);
+
+/*
+ * Collection commands
+ */
+int osd_req_list_collection_objects(struct osd_request *or,
+	const struct osd_obj_id *obj, osd_id initial_id,
+	struct osd_obj_id_list *list, unsigned nelem)
+{
+	return _osd_req_list_objects(or, OSD_ACT_LIST_COLLECTION, obj,
+				     initial_id, list, nelem);
+}
+EXPORT_SYMBOL(osd_req_list_collection_objects);
+
+void osd_req_flush_collection(struct osd_request *or,
+	const struct osd_obj_id *obj, enum osd_options_flush_scope_values op)
+{
+	_osd_req_encode_common(or, OSD_ACT_FLUSH_PARTITION, obj, 0, 0);
+	_osd_req_encode_flush(or, op);
+}
+EXPORT_SYMBOL(osd_req_flush_collection);
+
 /*
  * Object commands
  */
@@ -392,6 +507,15 @@ void osd_req_write(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_req_write);
 
+void osd_req_flush_object(struct osd_request *or,
+	const struct osd_obj_id *obj, enum osd_options_flush_scope_values op,
+	/*V2*/ u64 offset, /*V2*/ u64 len)
+{
+	_osd_req_encode_common(or, OSD_ACT_FLUSH, obj, offset, len);
+	_osd_req_encode_flush(or, op);
+}
+EXPORT_SYMBOL(osd_req_flush_object);
+
 void osd_req_read(struct osd_request *or,
 	const struct osd_obj_id *obj, struct bio *bio, u64 offset)
 {
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 10/16] libosd: Not implemented commands
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (8 preceding siblings ...)
  2009-01-25 15:05 ` [PATCH 09/16] libosd: Add Flush and List-objects support Boaz Harrosh
@ 2009-01-25 15:07 ` Boaz Harrosh
  2009-01-25 15:09 ` [PATCH 11/16] libosd: OSD version 2 Support Boaz Harrosh
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 15:07 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Some commands declared in header are not yet implemented. Put them
as stubs in .c file, just so they take their place in the file

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 drivers/scsi/osd/osd_initiator.c |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 5d9457b..3fd021a 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -343,6 +343,9 @@ static void _osd_req_encode_common(struct osd_request *or,
 /*
  * Device commands
  */
+/*TODO: void osd_req_set_master_seed_xchg(struct osd_request *, ...); */
+/*TODO: void osd_req_set_master_key(struct osd_request *, ...); */
+
 void osd_req_format(struct osd_request *or, u64 tot_capacity)
 {
 	_osd_req_encode_common(or, OSD_ACT_FORMAT_OSD, &osd_root_object, 0,
@@ -373,6 +376,10 @@ void osd_req_flush_obsd(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_req_flush_obsd);
 
+/*TODO: void osd_req_perform_scsi_command(struct osd_request *,
+	const u8 *cdb, ...); */
+/*TODO: void osd_req_task_management(struct osd_request *, ...); */
+
 /*
  * Partition commands
  */
@@ -399,6 +406,10 @@ void osd_req_remove_partition(struct osd_request *or, osd_id partition)
 }
 EXPORT_SYMBOL(osd_req_remove_partition);
 
+/*TODO: void osd_req_set_partition_key(struct osd_request *,
+	osd_id partition, u8 new_key_id[OSD_CRYPTO_KEYID_SIZE],
+	u8 seed[OSD_CRYPTO_SEED_SIZE]); */
+
 static int _osd_req_list_objects(struct osd_request *or,
 	__be16 action, const struct osd_obj_id *obj, osd_id initial_id,
 	struct osd_obj_id_list *list, unsigned nelem)
@@ -464,6 +475,11 @@ EXPORT_SYMBOL(osd_req_flush_partition);
 /*
  * Collection commands
  */
+/*TODO: void osd_req_create_collection(struct osd_request *,
+	const struct osd_obj_id *); */
+/*TODO: void osd_req_remove_collection(struct osd_request *,
+	const struct osd_obj_id *); */
+
 int osd_req_list_collection_objects(struct osd_request *or,
 	const struct osd_obj_id *obj, osd_id initial_id,
 	struct osd_obj_id_list *list, unsigned nelem)
@@ -473,6 +489,8 @@ int osd_req_list_collection_objects(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_req_list_collection_objects);
 
+/*TODO: void query(struct osd_request *, ...); V2 */
+
 void osd_req_flush_collection(struct osd_request *or,
 	const struct osd_obj_id *obj, enum osd_options_flush_scope_values op)
 {
@@ -481,6 +499,9 @@ void osd_req_flush_collection(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_req_flush_collection);
 
+/*TODO: void get_member_attrs(struct osd_request *, ...); V2 */
+/*TODO: void set_member_attrs(struct osd_request *, ...); V2 */
+
 /*
  * Object commands
  */
@@ -496,6 +517,11 @@ void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *obj)
 }
 EXPORT_SYMBOL(osd_req_remove_object);
 
+
+/*TODO: void osd_req_create_multi(struct osd_request *or,
+	struct osd_obj_id *first, struct osd_obj_id_list *list, unsigned nelem);
+*/
+
 void osd_req_write(struct osd_request *or,
 	const struct osd_obj_id *obj, struct bio *bio, u64 offset)
 {
@@ -507,6 +533,15 @@ void osd_req_write(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_req_write);
 
+/*TODO: void osd_req_append(struct osd_request *,
+	const struct osd_obj_id *, struct bio *data_out); */
+/*TODO: void osd_req_create_write(struct osd_request *,
+	const struct osd_obj_id *, struct bio *data_out, u64 offset); */
+/*TODO: void osd_req_clear(struct osd_request *,
+	const struct osd_obj_id *, u64 offset, u64 len); */
+/*TODO: void osd_req_punch(struct osd_request *,
+	const struct osd_obj_id *, u64 offset, u64 len); V2 */
+
 void osd_req_flush_object(struct osd_request *or,
 	const struct osd_obj_id *obj, enum osd_options_flush_scope_values op,
 	/*V2*/ u64 offset, /*V2*/ u64 len)
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 11/16] libosd: OSD version 2 Support
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (9 preceding siblings ...)
  2009-01-25 15:07 ` [PATCH 10/16] libosd: Not implemented commands Boaz Harrosh
@ 2009-01-25 15:09 ` Boaz Harrosh
  2009-01-25 15:13 ` [PATCH 12/16] libosd: OSDv2 auto detection Boaz Harrosh
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 15:09 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Add support for OSD2 at run time. It is now possible to run with
both OSDv1 and OSDv2 targets at the same time. The actual detection
should be preformed by the security manager, as the version is encoded
in the capability structure.

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 drivers/scsi/osd/osd_initiator.c |   94 ++++++++++++++++++++++++++++++++------
 include/scsi/osd_initiator.h     |   39 ++++++++++++++++
 include/scsi/osd_protocol.h      |   90 ++++++++++++++++++++++++++++++++++--
 3 files changed, 205 insertions(+), 18 deletions(-)

diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 3fd021a..86a76cc 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -59,36 +59,50 @@ static inline void build_test(void)
 {
 	/* structures were not packed */
 	BUILD_BUG_ON(sizeof(struct osd_capability) != OSD_CAP_LEN);
+	BUILD_BUG_ON(sizeof(struct osdv2_cdb) != OSD_TOTAL_CDB_LEN);
 	BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN);
 }
 
 static unsigned _osd_req_cdb_len(struct osd_request *or)
 {
-	return OSDv1_TOTAL_CDB_LEN;
+	return osd_req_is_ver1(or) ? OSDv1_TOTAL_CDB_LEN : OSD_TOTAL_CDB_LEN;
 }
 
 static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len)
 {
-	return osdv1_attr_list_elem_size(len);
+	return osd_req_is_ver1(or) ?
+		osdv1_attr_list_elem_size(len) :
+		osdv2_attr_list_elem_size(len);
 }
 
 static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head)
 {
-	return osdv1_list_size(list_head);
+	return osd_req_is_ver1(or) ?
+		osdv1_list_size(list_head) :
+		osdv2_list_size(list_head);
 }
 
 static unsigned _osd_req_sizeof_alist_header(struct osd_request *or)
 {
-	return sizeof(struct osdv1_attributes_list_header);
+	return osd_req_is_ver1(or) ?
+		sizeof(struct osdv1_attributes_list_header) :
+		sizeof(struct osdv2_attributes_list_header);
 }
 
 static void _osd_req_set_alist_type(struct osd_request *or,
 	void *list, int list_type)
 {
-	struct osdv1_attributes_list_header *attr_list = list;
+	if (osd_req_is_ver1(or)) {
+		struct osdv1_attributes_list_header *attr_list = list;
+
+		memset(attr_list, 0, sizeof(*attr_list));
+		attr_list->type = list_type;
+	} else {
+		struct osdv2_attributes_list_header *attr_list = list;
 
-	memset(attr_list, 0, sizeof(*attr_list));
-	attr_list->type = list_type;
+		memset(attr_list, 0, sizeof(*attr_list));
+		attr_list->type = list_type;
+	}
 }
 
 static bool _osd_req_is_alist_type(struct osd_request *or,
@@ -97,10 +111,14 @@ static bool _osd_req_is_alist_type(struct osd_request *or,
 	if (!list)
 		return false;
 
-	if (1) {
+	if (osd_req_is_ver1(or)) {
 		struct osdv1_attributes_list_header *attr_list = list;
 
 		return attr_list->type == list_type;
+	} else {
+		struct osdv2_attributes_list_header *attr_list = list;
+
+		return attr_list->type == list_type;
 	}
 }
 
@@ -110,15 +128,22 @@ static void _osd_req_encode_olist(struct osd_request *or,
 {
 	struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
 
-	cdbh->v1.list_identifier = list->list_identifier;
-	cdbh->v1.start_address = list->continuation_id;
+	if (osd_req_is_ver1(or)) {
+		cdbh->v1.list_identifier = list->list_identifier;
+		cdbh->v1.start_address = list->continuation_id;
+	} else {
+		cdbh->v2.list_identifier = list->list_identifier;
+		cdbh->v2.start_address = list->continuation_id;
+	}
 }
 
 static osd_cdb_offset osd_req_encode_offset(struct osd_request *or,
 	u64 offset, unsigned *padding)
 {
 	return __osd_encode_offset(offset, padding,
-				  OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
+			osd_req_is_ver1(or) ?
+				OSDv1_OFFSET_MIN_SHIFT : OSD_OFFSET_MIN_SHIFT,
+			OSD_OFFSET_MAX_SHIFT);
 }
 
 static struct osd_security_parameters *
@@ -126,7 +151,10 @@ _osd_req_sec_params(struct osd_request *or)
 {
 	struct osd_cdb *ocdb = &or->cdb;
 
-	return &ocdb->v1.sec_params;
+	if (osd_req_is_ver1(or))
+		return &ocdb->v1.sec_params;
+	else
+		return &ocdb->v2.sec_params;
 }
 
 void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)
@@ -134,6 +162,9 @@ void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)
 	memset(osdd, 0, sizeof(*osdd));
 	osdd->scsi_device = scsi_device;
 	osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT;
+#ifdef OSD_VER1_SUPPORT
+	osdd->version = OSD_VER2;
+#endif
 	/* TODO: Allocate pools for osd_request attributes ... */
 }
 EXPORT_SYMBOL(osd_dev_init);
@@ -334,10 +365,30 @@ static void _osdv1_req_encode_common(struct osd_request *or,
 	ocdb->h.v1.start_address = cpu_to_be64(offset);
 }
 
+static void _osdv2_req_encode_common(struct osd_request *or,
+	 __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
+{
+	struct osdv2_cdb *ocdb = &or->cdb.v2;
+
+	OSD_DEBUG("OSDv2 execute opcode 0x%x\n", be16_to_cpu(act));
+
+	ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD;
+	ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH;
+	ocdb->h.varlen_cdb.service_action = act;
+
+	ocdb->h.partition = cpu_to_be64(obj->partition);
+	ocdb->h.object = cpu_to_be64(obj->id);
+	ocdb->h.v2.length = cpu_to_be64(len);
+	ocdb->h.v2.start_address = cpu_to_be64(offset);
+}
+
 static void _osd_req_encode_common(struct osd_request *or,
 	__be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
 {
-	_osdv1_req_encode_common(or, act, obj, offset, len);
+	if (osd_req_is_ver1(or))
+		_osdv1_req_encode_common(or, act, obj, offset, len);
+	else
+		_osdv2_req_encode_common(or, act, obj, offset, len);
 }
 
 /*
@@ -546,6 +597,12 @@ void osd_req_flush_object(struct osd_request *or,
 	const struct osd_obj_id *obj, enum osd_options_flush_scope_values op,
 	/*V2*/ u64 offset, /*V2*/ u64 len)
 {
+	if (unlikely(osd_req_is_ver1(or) && (offset || len))) {
+		OSD_DEBUG("OSD Ver1 flush on specific range ignored\n");
+		offset = 0;
+		len = 0;
+	}
+
 	_osd_req_encode_common(or, OSD_ACT_FLUSH, obj, offset, len);
 	_osd_req_encode_flush(or, op);
 }
@@ -1169,6 +1226,10 @@ enum { OSD_SEC_CAP_V1_ALL_CAPS =
 	OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT
 };
 
+enum { OSD_SEC_CAP_V2_ALL_CAPS =
+	OSD_SEC_CAP_V1_ALL_CAPS | OSD_SEC_CAP_QUERY | OSD_SEC_CAP_M_OBJECT
+};
+
 void osd_sec_init_nosec_doall_caps(void *caps,
 	const struct osd_obj_id *obj, bool is_collection, const bool is_v1)
 {
@@ -1210,9 +1271,14 @@ void osd_sec_init_nosec_doall_caps(void *caps,
 }
 EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps);
 
+/* FIXME: Extract version from caps pointer.
+ *        Also Pete's target only supports caps from OSDv1 for now
+ */
 void osd_set_caps(struct osd_cdb *cdb, const void *caps)
 {
-	memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN);
+	bool is_ver1 = true;
+	/* NOTE: They start at same address */
+	memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN);
 }
 
 bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused)
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index e84dc7a..8482777 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -21,6 +21,23 @@
 
 /* Note: "NI" in comments below means "Not Implemented yet" */
 
+/* Configure of code:
+ * #undef if you *don't* want OSD v1 support in runtime.
+ * If #defined the initiator will dynamically configure to encode OSD v1
+ * CDB's if the target is detected to be OSD v1 only.
+ * OSD v2 only commands, options, and attributes will be ignored if target
+ * is v1 only.
+ * If #defined will result in bigger/slower code (OK Slower maybe not)
+ * Q: Should this be CONFIG_SCSI_OSD_VER1_SUPPORT and set from Kconfig?
+ */
+#define OSD_VER1_SUPPORT y
+
+enum osd_std_version {
+	OSD_VER_NONE = 0,
+	OSD_VER1 = 1,
+	OSD_VER2 = 2,
+};
+
 /*
  * Object-based Storage Device.
  * This object represents an OSD device.
@@ -31,6 +48,10 @@
 struct osd_dev {
 	struct scsi_device *scsi_device;
 	unsigned def_timeout;
+
+#ifdef OSD_VER1_SUPPORT
+	enum osd_std_version version;
+#endif
 };
 
 /* Retrieve/return osd_dev(s) for use by Kernel clients */
@@ -46,6 +67,14 @@ void osduld_unregister_test(unsigned ioctl);
 void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
 void osd_dev_fini(struct osd_dev *od);
 
+/* we might want to use function vector in the future */
+static inline void osd_dev_set_ver(struct osd_dev *od, enum osd_std_version v)
+{
+#ifdef OSD_VER1_SUPPORT
+	od->version = v;
+#endif
+}
+
 struct osd_request;
 typedef void (osd_req_done_fn)(struct osd_request *or, void *private);
 
@@ -82,6 +111,16 @@ struct osd_request {
 	int async_error;
 };
 
+/* OSD Version control */
+static inline bool osd_req_is_ver1(struct osd_request *or)
+{
+#ifdef OSD_VER1_SUPPORT
+	return or->osd_dev->version == OSD_VER1;
+#else
+	return false;
+#endif
+}
+
 /*
  * How to use the osd library:
  *
diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h
index ce1a877..cd3cbf7 100644
--- a/include/scsi/osd_protocol.h
+++ b/include/scsi/osd_protocol.h
@@ -25,12 +25,16 @@ enum {
 	OSDv1_TOTAL_CDB_LEN = OSDv1_ADDITIONAL_CDB_LENGTH + 8,
 	OSDv1_CAP_LEN = 80,
 	/* Latest supported version */
-	OSD_ADDITIONAL_CDB_LENGTH = OSDv1_ADDITIONAL_CDB_LENGTH,
-	OSD_TOTAL_CDB_LEN = OSDv1_TOTAL_CDB_LEN,
-	OSD_CAP_LEN = OSDv1_CAP_LEN,
+/* 	OSD_ADDITIONAL_CDB_LENGTH = 216,*/
+	OSD_ADDITIONAL_CDB_LENGTH =
+		OSDv1_ADDITIONAL_CDB_LENGTH, /* FIXME: Pete rev-001 sup */
+	OSD_TOTAL_CDB_LEN = OSD_ADDITIONAL_CDB_LENGTH + 8,
+/* 	OSD_CAP_LEN = 104,*/
+	OSD_CAP_LEN = OSDv1_CAP_LEN,/* FIXME: Pete rev-001 sup */
 
 	OSD_SYSTEMID_LEN = 20,
 	OSD_CRYPTO_KEYID_SIZE = 20,
+	/*FIXME: OSDv2_CRYPTO_KEYID_SIZE = 32,*/
 	OSD_CRYPTO_SEED_SIZE = 4,
 	OSD_CRYPTO_NONCE_SIZE = 12,
 	OSD_MAX_SENSE_LEN = 252, /* from SPC-3 */
@@ -108,6 +112,7 @@ enum {
 	OSD_OFFSET_MAX_BITS = 28,
 
 	OSDv1_OFFSET_MIN_SHIFT = 8,
+	OSD_OFFSET_MIN_SHIFT = 3,
 	OSD_OFFSET_MAX_SHIFT = 16,
 };
 
@@ -129,6 +134,16 @@ static inline osd_cdb_offset osd_encode_offset_v1(u64 offset, unsigned *padding)
 				OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
 }
 
+/* Minimum 8 bytes alignment
+ * Same as v1 but since exponent can be signed than a less than
+ * 256 alignment can be reached with small offsets (<2GB)
+ */
+static inline osd_cdb_offset osd_encode_offset_v2(u64 offset, unsigned *padding)
+{
+	return __osd_encode_offset(offset, padding,
+				   OSD_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
+}
+
 /* osd2r03: 5.2.1 Overview */
 struct osd_cdb_head {
 	struct scsi_varlen_cdb_hdr varlen_cdb;
@@ -144,6 +159,13 @@ struct osd_cdb_head {
 /*36*/			__be64		length;
 /*44*/			__be64		start_address;
 		} __packed v1;
+
+		struct __osdv2_cdb_addr_len {
+			/* called allocation_length in some commands */
+/*32*/			__be64	length;
+/*40*/			__be64	start_address;
+/*48*/			__be32 list_identifier;/* Rarely used */
+		} __packed v2;
 	};
 /*52*/	union { /* selected attributes mode Page/List/Single */
 		struct osd_attributes_page_mode {
@@ -182,6 +204,7 @@ struct osd_cdb_head {
 /*80*/
 
 /*160 v1*/
+/*184 v2*/
 struct osd_security_parameters {
 /*160*/u8	integrity_check_value[OSD_CRYPTO_KEYID_SIZE];
 /*180*/u8	request_nonce[OSD_CRYPTO_NONCE_SIZE];
@@ -189,6 +212,9 @@ struct osd_security_parameters {
 /*196*/osd_cdb_offset	data_out_integrity_check_offset;
 } __packed;
 /*200 v1*/
+/*224 v2*/
+
+/* FIXME: osdv2_security_parameters */
 
 struct osdv1_cdb {
 	struct osd_cdb_head h;
@@ -196,9 +222,17 @@ struct osdv1_cdb {
 	struct osd_security_parameters sec_params;
 } __packed;
 
+struct osdv2_cdb {
+	struct osd_cdb_head h;
+	u8 caps[OSD_CAP_LEN];
+	struct osd_security_parameters sec_params;
+	/* FIXME: osdv2_security_parameters */
+} __packed;
+
 struct osd_cdb {
 	union {
 		struct osdv1_cdb v1;
+		struct osdv2_cdb v2;
 		u8 buff[OSD_TOTAL_CDB_LEN];
 	};
 } __packed;
@@ -269,6 +303,7 @@ struct osd_attributes_list_attrid {
 /*
  * osd2r03: 7.1.3.3 List entry format for retrieved attributes and
  *                  for setting attributes
+ * NOTE: v2 is 8-bytes aligned, v1 is not aligned.
  */
 struct osd_attributes_list_element {
 	__be32 attr_page;
@@ -279,6 +314,7 @@ struct osd_attributes_list_element {
 
 enum {
 	OSDv1_ATTRIBUTES_ELEM_ALIGN = 1,
+	OSD_ATTRIBUTES_ELEM_ALIGN = 8,
 };
 
 enum {
@@ -292,6 +328,12 @@ static inline unsigned osdv1_attr_list_elem_size(unsigned len)
 		     OSDv1_ATTRIBUTES_ELEM_ALIGN);
 }
 
+static inline unsigned osdv2_attr_list_elem_size(unsigned len)
+{
+	return ALIGN(len + sizeof(struct osd_attributes_list_element),
+		     OSD_ATTRIBUTES_ELEM_ALIGN);
+}
+
 /*
  * osd2r03: 7.1.3 OSD attributes lists (Table 184) — List type values
  */
@@ -326,6 +368,21 @@ static inline unsigned osdv1_list_size(struct osdv1_attributes_list_header *h)
 	return be16_to_cpu(h->list_bytes);
 }
 
+struct osdv2_attributes_list_header {
+	u8 type;	/* lower 4-bits only */
+	u8 pad[3];
+/*4*/	__be32 list_bytes; /* Initiator shall set to zero. Only set by target */
+	/*
+	 * type=9 followed by struct osd_attributes_list_element's
+	 * type=E followed by struct osd_attributes_list_multi_header's
+	 */
+} __packed;
+
+static inline unsigned osdv2_list_size(struct osdv2_attributes_list_header *h)
+{
+	return be32_to_cpu(h->list_bytes);
+}
+
 /* (osd-r10 6.13)
  * osd2r03: 6.15 LIST (Table 79) LIST command parameter data.
  *	for root_lstchg below
@@ -469,11 +526,36 @@ struct osdv1_cap_object_descriptor {
 } __packed;
 /*80 v1*/
 
-struct osd_capability {
+/*56 v2*/
+struct osd_cap_object_descriptor {
+	union {
+		struct {
+/*56*/			__be32 allowed_attributes_access;
+/*60*/			__be32 policy_access_tag;
+/*64*/			__be16 boot_epoch;
+/*66*/			u8 reserved[6];
+/*72*/			__be64 allowed_partition_id;
+/*80*/			__be64 allowed_object_id;
+/*88*/			__be64 allowed_range_length;
+/*96*/			__be64 allowed_range_start;
+		} __packed obj_desc;
+
+/*56*/		u8 object_descriptor[48];
+	};
+} __packed;
+/*104 v2*/
+
+struct osdv1_capability {
 	struct osd_capability_head h;
 	struct osdv1_cap_object_descriptor od;
 } __packed;
 
+struct osd_capability {
+	struct osd_capability_head h;
+/* 	struct osd_cap_object_descriptor od;*/
+	struct osdv1_cap_object_descriptor od; /* FIXME: Pete rev-001 sup */
+} __packed;
+
 /**
  * osd_sec_set_caps - set cap-bits into the capabilities header
  *
-- 
1.6.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 12/16] libosd: OSDv2 auto detection
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (10 preceding siblings ...)
  2009-01-25 15:09 ` [PATCH 11/16] libosd: OSD version 2 Support Boaz Harrosh
@ 2009-01-25 15:13 ` Boaz Harrosh
  2009-01-25 15:15 ` [PATCH 13/16] libosd: SCSI/OSD Sense decoding support Boaz Harrosh
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 15:13 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Auto detect an OSDv2 or OSDv1 target at run time. Note how none
of the OSD API calls change. The tests do not know what device
version it is.

This test now passes against both the IBM-OSD-SIM OSD1 target
as well as OSC's OSD2 target.

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 drivers/scsi/osd/osd_initiator.c |  125 ++++++++++++++++++++++++++++++++++++++
 drivers/scsi/osd/osd_uld.c       |    5 ++
 include/scsi/osd_initiator.h     |    3 +
 3 files changed, 133 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 86a76cc..f6340c2 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -41,6 +41,7 @@
 
 #include <scsi/osd_initiator.h>
 #include <scsi/osd_sec.h>
+#include <scsi/osd_attributes.h>
 #include <scsi/scsi_device.h>
 
 #include "osd_debug.h"
@@ -63,6 +64,130 @@ static inline void build_test(void)
 	BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN);
 }
 
+static const char *_osd_ver_desc(struct osd_request *or)
+{
+	return osd_req_is_ver1(or) ? "OSD1" : "OSD2";
+}
+
+#define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len)
+
+static int _osd_print_system_info(struct osd_dev *od, void *caps)
+{
+	struct osd_request *or;
+	struct osd_attr get_attrs[] = {
+		ATTR_DEF_RI(OSD_ATTR_RI_VENDOR_IDENTIFICATION, 8),
+		ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_IDENTIFICATION, 16),
+		ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_MODEL, 32),
+		ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_REVISION_LEVEL, 4),
+		ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER, 64 /*variable*/),
+		ATTR_DEF_RI(OSD_ATTR_RI_OSD_NAME, 64 /*variable*/),
+		ATTR_DEF_RI(OSD_ATTR_RI_TOTAL_CAPACITY, 8),
+		ATTR_DEF_RI(OSD_ATTR_RI_USED_CAPACITY, 8),
+		ATTR_DEF_RI(OSD_ATTR_RI_NUMBER_OF_PARTITIONS, 8),
+		ATTR_DEF_RI(OSD_ATTR_RI_CLOCK, 6),
+		/* IBM-OSD-SIM Has a bug with this one put it last */
+		ATTR_DEF_RI(OSD_ATTR_RI_OSD_SYSTEM_ID, 20),
+	};
+	void *iter = NULL, *pFirst;
+	int nelem = ARRAY_SIZE(get_attrs), a = 0;
+	int ret;
+
+	or = osd_start_request(od, GFP_KERNEL);
+	if (!or)
+		return -ENOMEM;
+
+	/* get attrs */
+	osd_req_get_attributes(or, &osd_root_object);
+	osd_req_add_get_attr_list(or, get_attrs, ARRAY_SIZE(get_attrs));
+
+	ret = osd_finalize_request(or, 0, caps, NULL);
+	if (ret)
+		goto out;
+
+	ret = osd_execute_request(or);
+	if (ret) {
+		OSD_ERR("Failed to detect %s => %d\n", _osd_ver_desc(or), ret);
+		goto out;
+	}
+
+	osd_req_decode_get_attr_list(or, get_attrs, &nelem, &iter);
+
+	OSD_INFO("Detected %s device\n",
+		_osd_ver_desc(or));
+
+	pFirst = get_attrs[a++].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_VENDOR_IDENTIFICATION [%s]\n",
+		(char *)pFirst);
+
+	pFirst = get_attrs[a++].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_PRODUCT_IDENTIFICATION [%s]\n",
+		(char *)pFirst);
+
+	pFirst = get_attrs[a++].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_PRODUCT_MODEL [%s]\n",
+		(char *)pFirst);
+
+	pFirst = get_attrs[a++].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_PRODUCT_REVISION_LEVEL [%u]\n",
+		get_unaligned_be32(pFirst));
+
+	pFirst = get_attrs[a++].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER [%s]\n",
+		(char *)pFirst);
+
+	pFirst = get_attrs[a].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_OSD_NAME [%s]\n", (char *)pFirst);
+	a++;
+
+	pFirst = get_attrs[a++].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_TOTAL_CAPACITY [0x%llx]\n",
+		_LLU(get_unaligned_be64(pFirst)));
+
+	pFirst = get_attrs[a++].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_USED_CAPACITY [0x%llx]\n",
+		_LLU(get_unaligned_be64(pFirst)));
+
+	pFirst = get_attrs[a++].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_NUMBER_OF_PARTITIONS [%llu]\n",
+		_LLU(get_unaligned_be64(pFirst)));
+
+	/* FIXME: Where are the time utilities */
+	pFirst = get_attrs[a++].val_ptr;
+	OSD_INFO("OSD_ATTR_RI_CLOCK [0x%02x%02x%02x%02x%02x%02x]\n",
+		((char *)pFirst)[0], ((char *)pFirst)[1],
+		((char *)pFirst)[2], ((char *)pFirst)[3],
+		((char *)pFirst)[4], ((char *)pFirst)[5]);
+
+	if (a < nelem) { /* IBM-OSD-SIM bug, Might not have it */
+		unsigned len = get_attrs[a].len;
+		char sid_dump[32*4 + 2]; /* 2nibbles+space+ASCII */
+
+		hex_dump_to_buffer(get_attrs[a].val_ptr, len, 32, 1,
+				   sid_dump, sizeof(sid_dump), true);
+		OSD_INFO("OSD_ATTR_RI_OSD_SYSTEM_ID(%d) [%s]\n", len, sid_dump);
+		a++;
+	}
+out:
+	osd_end_request(or);
+	return ret;
+}
+
+int osd_auto_detect_ver(struct osd_dev *od, void *caps)
+{
+	int ret;
+
+	/* Auto-detect the osd version */
+	ret = _osd_print_system_info(od, caps);
+	if (ret) {
+		osd_dev_set_ver(od, OSD_VER1);
+		OSD_DEBUG("converting to OSD1\n");
+		ret = _osd_print_system_info(od, caps);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(osd_auto_detect_ver);
+
 static unsigned _osd_req_cdb_len(struct osd_request *or)
 {
 	return osd_req_is_ver1(or) ? OSDv1_TOTAL_CDB_LEN : OSD_TOTAL_CDB_LEN;
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index cd4ca7c..f8b1a74 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -243,6 +243,7 @@ EXPORT_SYMBOL(osduld_put_device);
 static int __detect_osd(struct osd_uld_device *oud)
 {
 	struct scsi_device *scsi_device = oud->od.scsi_device;
+	char caps[OSD_CAP_LEN];
 	int error;
 
 	/* sending a test_unit_ready as first command seems to be needed
@@ -254,6 +255,10 @@ static int __detect_osd(struct osd_uld_device *oud)
 	if (error)
 		OSD_ERR("warning: scsi_test_unit_ready failed\n");
 
+	osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true);
+	if (osd_auto_detect_ver(&oud->od, caps))
+		return -ENODEV;
+
 	return 0;
 }
 
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index 8482777..24edeae 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -67,6 +67,9 @@ void osduld_unregister_test(unsigned ioctl);
 void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
 void osd_dev_fini(struct osd_dev *od);
 
+/* some hi level device operations */
+int osd_auto_detect_ver(struct osd_dev *od, void *caps);    /* GFP_KERNEL */
+
 /* we might want to use function vector in the future */
 static inline void osd_dev_set_ver(struct osd_dev *od, enum osd_std_version v)
 {
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 13/16] libosd: SCSI/OSD Sense decoding support
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (11 preceding siblings ...)
  2009-01-25 15:13 ` [PATCH 12/16] libosd: OSDv2 auto detection Boaz Harrosh
@ 2009-01-25 15:15 ` Boaz Harrosh
  2009-01-28 16:32   ` James Bottomley
  2009-01-25 15:21 ` [PATCH 14/16] osd: Documentation for OSD library Boaz Harrosh
                   ` (2 subsequent siblings)
  15 siblings, 1 reply; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 15:15 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Implementation of the osd_req_decode_sense() API. Can be called by
library users to decode what failed in command executions.

Add SCSI_OSD_DPRINT_SENSE Kconfig variable. Possible values are:
0 - Do not print any errors to messages file <KERN_ERR>
1 - (Default) Print only decoded errors that are not recoverable.
    Recoverable errors are those that the target has complied with
    the request but with a warning. For example read passed end of
    object will return zeros after the last valid byte.
2- Print all errors.

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
---
 drivers/scsi/osd/Kbuild          |    6 +
 drivers/scsi/osd/osd_initiator.c |  191 ++++++++++++++++++++++++++++
 include/scsi/osd_initiator.h     |   49 +++++++
 include/scsi/osd_sense.h         |  260 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 506 insertions(+), 0 deletions(-)
 create mode 100644 include/scsi/osd_sense.h

diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild
index 9d38248..0e207aa 100644
--- a/drivers/scsi/osd/Kbuild
+++ b/drivers/scsi/osd/Kbuild
@@ -20,6 +20,12 @@ ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
 CONFIG_SCSI_OSD_ULD=m
 ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE
 
+# CONFIG_SCSI_OSD_DPRINT_SENSE =
+#	0 - no print of errors
+#	1 - print errors
+#	2 - errors + warrnings
+ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1
+
 # Uncomment to turn debug on
 # ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
 
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index f6340c2..0bbbf27 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -42,6 +42,8 @@
 #include <scsi/osd_initiator.h>
 #include <scsi/osd_sec.h>
 #include <scsi/osd_attributes.h>
+#include <scsi/osd_sense.h>
+
 #include <scsi/scsi_device.h>
 
 #include "osd_debug.h"
@@ -1339,6 +1341,195 @@ int osd_finalize_request(struct osd_request *or,
 }
 EXPORT_SYMBOL(osd_finalize_request);
 
+#define OSD_SENSE_PRINT1(fmt, a...) \
+	do { \
+		if (__cur_sense_need_output) \
+			OSD_ERR(fmt, ##a); \
+	} while (0)
+
+#define OSD_SENSE_PRINT2(fmt, a...) OSD_SENSE_PRINT1("    " fmt, ##a)
+
+int osd_req_decode_sense_full(struct osd_request *or,
+	struct osd_sense_info *osi, bool silent,
+	struct osd_obj_id *bad_obj_list __unused, int max_obj __unused,
+	struct osd_attr *bad_attr_list, int max_attr)
+{
+	int sense_len, original_sense_len;
+	struct osd_sense_info local_osi;
+	struct scsi_sense_descriptor_based *ssdb;
+	void *cur_descriptor;
+#if (CONFIG_SCSI_OSD_DPRINT_SENSE == 0)
+	const bool __cur_sense_need_output = false;
+#else
+	bool __cur_sense_need_output = !silent;
+#endif
+
+	if (!or->request->errors)
+		return 0;
+
+	ssdb = or->request->sense;
+	sense_len = or->request->sense_len;
+	if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) {
+		OSD_ERR("Block-layer returned error(0x%x) but "
+			"sense_len(%u) || key(%d) is empty\n",
+			or->request->errors, sense_len, ssdb->sense_key);
+		return -EIO;
+	}
+
+	if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) {
+		OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n",
+			ssdb->response_code, sense_len);
+		return -EIO;
+	}
+
+	osi = osi ? : &local_osi;
+	memset(osi, 0, sizeof(*osi));
+	osi->key = ssdb->sense_key;
+	osi->additional_code = be16_to_cpu(ssdb->additional_sense_code);
+	original_sense_len = ssdb->additional_sense_length + 8;
+
+#if (CONFIG_SCSI_OSD_DPRINT_SENSE == 1)
+	if (__cur_sense_need_output)
+		__cur_sense_need_output = (osi->key > scsi_sk_recovered_error);
+#endif
+	OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) "
+			"additional_code=0x%x\n",
+			osi->key, original_sense_len, sense_len,
+			osi->additional_code);
+
+	if (original_sense_len < sense_len)
+		sense_len = original_sense_len;
+
+	cur_descriptor = ssdb->ssd;
+	sense_len -= sizeof(*ssdb);
+	while (sense_len > 0) {
+		struct scsi_sense_descriptor *ssd = cur_descriptor;
+		int cur_len = ssd->additional_length + 2;
+
+		sense_len -= cur_len;
+
+		if (sense_len < 0)
+			break; /* sense was truncated */
+
+		switch (ssd->descriptor_type) {
+		case scsi_sense_information:
+		case scsi_sense_command_specific_information:
+		{
+			struct scsi_sense_command_specific_data_descriptor
+				*sscd = cur_descriptor;
+
+			osi->command_info =
+				get_unaligned_be64(&sscd->information) ;
+			OSD_SENSE_PRINT2(
+				"command_specific_information 0x%llx \n",
+				_LLU(osi->command_info));
+			break;
+		}
+		case scsi_sense_key_specific:
+		{
+			struct scsi_sense_key_specific_data_descriptor
+				*ssks = cur_descriptor;
+
+			osi->sense_info = get_unaligned_be16(&ssks->value);
+			OSD_SENSE_PRINT2(
+				"sense_key_specific_information %u"
+				"sksv_cd_bpv_bp (0x%x)\n",
+				osi->sense_info, ssks->sksv_cd_bpv_bp);
+			break;
+		}
+		case osd_sense_object_identification:
+		{ /*FIXME: Keep first not last, Store in array*/
+			struct osd_sense_identification_data_descriptor
+				*osidd = cur_descriptor;
+
+			osi->not_initiated_command_functions =
+				le32_to_cpu(osidd->not_initiated_functions);
+			osi->completed_command_functions =
+				le32_to_cpu(osidd->completed_functions);
+			osi->obj.partition = be64_to_cpu(osidd->partition_id);
+			osi->obj.id = be64_to_cpu(osidd->object_id);
+			OSD_SENSE_PRINT2(
+				"object_identification pid=0x%llx oid=0x%llx\n",
+				_LLU(osi->obj.partition), _LLU(osi->obj.id));
+			OSD_SENSE_PRINT2(
+				"not_initiated_bits(%x) "
+				"completed_command_bits(%x)\n",
+				osi->not_initiated_command_functions,
+				osi->completed_command_functions);
+			break;
+		}
+		case osd_sense_response_integrity_check:
+		{
+			struct osd_sense_response_integrity_check_descriptor
+				*osricd = cur_descriptor;
+			const unsigned len =
+					  sizeof(osricd->integrity_check_value);
+			char key_dump[len*4 + 2]; /* 2nibbles+space+ASCII */
+
+			hex_dump_to_buffer(osricd->integrity_check_value, len,
+				       32, 1, key_dump, sizeof(key_dump), true);
+			OSD_SENSE_PRINT2("response_integrity [%s]\n", key_dump);
+		}
+		case osd_sense_attribute_identification:
+		{
+			struct osd_sense_attributes_data_descriptor
+				*osadd = cur_descriptor;
+			int len = min(cur_len, sense_len);
+			int i = 0;
+			struct osd_sense_attr *pattr = osadd->sense_attrs;
+
+			while (len < 0) {
+				u32 attr_page = be32_to_cpu(pattr->attr_page);
+				u32 attr_id = be32_to_cpu(pattr->attr_id);
+
+				if (i++ == 0) {
+					osi->attr.attr_page = attr_page;
+					osi->attr.attr_id = attr_id;
+				}
+
+				if (bad_attr_list && max_attr) {
+					bad_attr_list->attr_page = attr_page;
+					bad_attr_list->attr_id = attr_id;
+					bad_attr_list++;
+					max_attr--;
+				}
+				OSD_SENSE_PRINT2(
+					"osd_sense_attribute_identification"
+					"attr_page=0x%x attr_id=0x%x\n",
+					attr_page, attr_id);
+			}
+		}
+		/*These are not legal for OSD*/
+		case scsi_sense_field_replaceable_unit:
+			OSD_SENSE_PRINT2("scsi_sense_field_replaceable_unit\n");
+			break;
+		case scsi_sense_stream_commands:
+			OSD_SENSE_PRINT2("scsi_sense_stream_commands\n");
+			break;
+		case scsi_sense_block_commands:
+			OSD_SENSE_PRINT2("scsi_sense_block_commands\n");
+			break;
+		case scsi_sense_ata_return:
+			OSD_SENSE_PRINT2("scsi_sense_ata_return\n");
+			break;
+		default:
+			if (ssd->descriptor_type <= scsi_sense_Reserved_last)
+				OSD_SENSE_PRINT2(
+					"scsi_sense Reserved descriptor (0x%x)",
+					ssd->descriptor_type);
+			else
+				OSD_SENSE_PRINT2(
+					"scsi_sense Vendor descriptor (0x%x)",
+					ssd->descriptor_type);
+		}
+
+		cur_descriptor += cur_len;
+	}
+
+	return (osi->key > scsi_sk_recovered_error) ? -EIO : 0;
+}
+EXPORT_SYMBOL(osd_req_decode_sense_full);
+
 /*
  * Implementation of osd_sec.h API
  * TODO: Move to a separate osd_sec.c file at a later stage.
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index 24edeae..b24d961 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -217,6 +217,55 @@ int osd_execute_request_async(struct osd_request *or,
 	osd_req_done_fn *done, void *private);
 
 /**
+ * osd_req_decode_sense_full - Decode sense information after execution.
+ *
+ * @or:           - osd_request to examine
+ * @osi           - Recievs a more detailed error report information (optional).
+ * @silent        - Do not print to dmsg (Even if enabled)
+ * @bad_obj_list  - Some commands act on multiple objects. Failed objects will
+ *                  be recieved here (optional)
+ * @max_obj       - Size of @bad_obj_list.
+ * @bad_attr_list - List of failing attributes (optional)
+ * @max_attr      - Size of @bad_attr_list.
+ *
+ * After execution, sense + return code can be analyzed using this function. The
+ * return code is the final disposition on the error. So it is possible that a
+ * CHECK_CONDITION was returned from target but this will return NO_ERROR, for
+ * example on recovered errors. All parameters are optional if caller does
+ * not need any returned information.
+ * Note: This function will also dump the error to dmsg according to settings
+ * of the SCSI_OSD_DPRINT_SENSE Kconfig value. Set @silent if you know the
+ * command would routinely fail, to not spam the dmsg file.
+ */
+struct osd_sense_info {
+	int key;		/* one of enum scsi_sense_keys */
+	int additional_code ;	/* enum osd_additional_sense_codes */
+	union { /* Sense specific information */
+		u16 sense_info;
+		u16 cdb_field_offset; 	/* scsi_invalid_field_in_cdb */
+	};
+	union { /* Command specific information */
+		u64 command_info;
+	};
+
+	u32 not_initiated_command_functions; /* osd_command_functions_bits */
+	u32 completed_command_functions; /* osd_command_functions_bits */
+	struct osd_obj_id obj;
+	struct osd_attr attr;
+};
+
+int osd_req_decode_sense_full(struct osd_request *or,
+	struct osd_sense_info *osi, bool silent,
+	struct osd_obj_id *bad_obj_list, int max_obj,
+	struct osd_attr *bad_attr_list, int max_attr);
+
+static inline int osd_req_decode_sense(struct osd_request *or,
+	struct osd_sense_info *osi)
+{
+	return osd_req_decode_sense_full(or, osi, false, NULL, 0, NULL, 0);
+}
+
+/**
  * osd_end_request - return osd_request to free store
  *
  * @or:		osd_request to free
diff --git a/include/scsi/osd_sense.h b/include/scsi/osd_sense.h
new file mode 100644
index 0000000..ff9b33c
--- /dev/null
+++ b/include/scsi/osd_sense.h
@@ -0,0 +1,260 @@
+/*
+ * osd_sense.h - OSD Related sense handling definitions.
+ *
+ * Copyright (C) 2008 Panasas Inc.  All rights reserved.
+ *
+ * Authors:
+ *   Boaz Harrosh <bharrosh@panasas.com>
+ *   Benny Halevy <bhalevy@panasas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ *
+ * This file contains types and constants that are defined by the protocol
+ * Note: All names and symbols are taken from the OSD standard's text.
+ */
+#ifndef __OSD_SENSE_H__
+#define __OSD_SENSE_H__
+
+#include <scsi/osd_protocol.h>
+
+/* SPC3r23 4.5.6 Sense key and sense code definitions table 27 */
+enum scsi_sense_keys {
+	scsi_sk_no_sense        = 0x0,
+	scsi_sk_recovered_error = 0x1,
+	scsi_sk_not_ready       = 0x2,
+	scsi_sk_medium_error    = 0x3,
+	scsi_sk_hardware_error  = 0x4,
+	scsi_sk_illegal_request = 0x5,
+	scsi_sk_unit_attention  = 0x6,
+	scsi_sk_data_protect    = 0x7,
+	scsi_sk_blank_check     = 0x8,
+	scsi_sk_vendor_specific = 0x9,
+	scsi_sk_copy_aborted    = 0xa,
+	scsi_sk_aborted_command = 0xb,
+	scsi_sk_volume_overflow = 0xd,
+	scsi_sk_miscompare      = 0xe,
+	scsi_sk_reserved        = 0xf,
+};
+
+/* SPC3r23 4.5.6 Sense key and sense code definitions table 28 */
+/* Note: only those which can be returned by an OSD target. Most of
+ *       these errors are taken care of by the generic scsi layer.
+ */
+enum osd_additional_sense_codes {
+	scsi_no_additional_sense_information			= 0x0000,
+	scsi_operation_in_progress				= 0x0016,
+	scsi_cleaning_requested					= 0x0017,
+	scsi_lunr_cause_not_reportable				= 0x0400,
+	scsi_logical_unit_is_in_process_of_becoming_ready	= 0x0401,
+	scsi_lunr_initializing_command_required			= 0x0402,
+	scsi_lunr_manual_intervention_required			= 0x0403,
+	scsi_lunr_operation_in_progress				= 0x0407,
+	scsi_lunr_selftest_in_progress				= 0x0409,
+	scsi_luna_asymmetric_access_state_transition		= 0x040a,
+	scsi_luna_target_port_in_standby_state			= 0x040b,
+	scsi_luna_target_port_in_unavailable_state		= 0x040c,
+	scsi_lunr_notify_enable_spinup_required			= 0x0411,
+	scsi_logical_unit_does_not_respond_to_selection		= 0x0500,
+	scsi_logical_unit_communication_failure			= 0x0800,
+	scsi_logical_unit_communication_timeout			= 0x0801,
+	scsi_logical_unit_communication_parity_error		= 0x0802,
+	scsi_error_log_overflow					= 0x0a00,
+	scsi_warning						= 0x0b00,
+	scsi_warning_specified_temperature_exceeded		= 0x0b01,
+	scsi_warning_enclosure_degraded				= 0x0b02,
+	scsi_write_error_unexpected_unsolicited_data		= 0x0c0c,
+	scsi_write_error_not_enough_unsolicited_data		= 0x0c0d,
+	scsi_invalid_information_unit				= 0x0e00,
+	scsi_invalid_field_in_command_information_unit		= 0x0e03,
+	scsi_read_error_failed_retransmission_request		= 0x1113,
+	scsi_parameter_list_length_error			= 0x1a00,
+	scsi_invalid_command_operation_code			= 0x2000,
+	scsi_invalid_field_in_cdb				= 0x2400,
+	osd_security_audit_value_frozen				= 0x2404,
+	osd_security_working_key_frozen				= 0x2405,
+	osd_nonce_not_unique					= 0x2406,
+	osd_nonce_timestamp_out_of_range			= 0x2407,
+	scsi_logical_unit_not_supported				= 0x2500,
+	scsi_invalid_field_in_parameter_list			= 0x2600,
+	scsi_parameter_not_supported				= 0x2601,
+	scsi_parameter_value_invalid				= 0x2602,
+	scsi_invalid_release_of_persistent_reservation		= 0x2604,
+	osd_invalid_dataout_buffer_integrity_check_value	= 0x260f,
+	scsi_not_ready_to_ready_change_medium_may_have_changed	= 0x2800,
+	scsi_power_on_reset_or_bus_device_reset_occurred	= 0x2900,
+	scsi_power_on_occurred					= 0x2901,
+	scsi_scsi_bus_reset_occurred				= 0x2902,
+	scsi_bus_device_reset_function_occurred			= 0x2903,
+	scsi_device_internal_reset				= 0x2904,
+	scsi_transceiver_mode_changed_to_single_ended		= 0x2905,
+	scsi_transceiver_mode_changed_to_lvd			= 0x2906,
+	scsi_i_t_nexus_loss_occurred				= 0x2907,
+	scsi_parameters_changed					= 0x2a00,
+	scsi_mode_parameters_changed				= 0x2a01,
+	scsi_asymmetric_access_state_changed			= 0x2a06,
+	scsi_priority_changed					= 0x2a08,
+	scsi_command_sequence_error				= 0x2c00,
+	scsi_previous_busy_status				= 0x2c07,
+	scsi_previous_task_set_full_status			= 0x2c08,
+	scsi_previous_reservation_conflict_status		= 0x2c09,
+	osd_partition_or_collection_contains_user_objects	= 0x2c0a,
+	scsi_commands_cleared_by_another_initiator		= 0x2f00,
+	scsi_cleaning_failure					= 0x3007,
+	scsi_enclosure_failure					= 0x3400,
+	scsi_enclosure_services_failure				= 0x3500,
+	scsi_unsupported_enclosure_function			= 0x3501,
+	scsi_enclosure_services_unavailable			= 0x3502,
+	scsi_enclosure_services_transfer_failure		= 0x3503,
+	scsi_enclosure_services_transfer_refused		= 0x3504,
+	scsi_enclosure_services_checksum_error			= 0x3505,
+	scsi_rounded_parameter					= 0x3700,
+	osd_read_past_end_of_user_object			= 0x3b17,
+	scsi_logical_unit_has_not_self_configured_yet		= 0x3e00,
+	scsi_logical_unit_failure				= 0x3e01,
+	scsi_timeout_on_logical_unit				= 0x3e02,
+	scsi_logical_unit_failed_selftest			= 0x3e03,
+	scsi_logical_unit_unable_to_update_selftest_log		= 0x3e04,
+	scsi_target_operating_conditions_have_changed		= 0x3f00,
+	scsi_microcode_has_been_changed				= 0x3f01,
+	scsi_inquiry_data_has_changed				= 0x3f03,
+	scsi_echo_buffer_overwritten				= 0x3f0f,
+	scsi_diagnostic_failure_on_component_nn_first		= 0x4080,
+	scsi_diagnostic_failure_on_component_nn_last		= 0x40ff,
+	scsi_message_error					= 0x4300,
+	scsi_internal_target_failure				= 0x4400,
+	scsi_select_or_reselect_failure				= 0x4500,
+	scsi_scsi_parity_error					= 0x4700,
+	scsi_data_phase_crc_error_detected			= 0x4701,
+	scsi_scsi_parity_error_detected_during_st_data_phase	= 0x4702,
+	scsi_asynchronous_information_protection_error_detected	= 0x4704,
+	scsi_protocol_service_crc_error				= 0x4705,
+	scsi_phy_test_function_in_progress			= 0x4706,
+	scsi_invalid_message_error				= 0x4900,
+	scsi_command_phase_error				= 0x4a00,
+	scsi_data_phase_error					= 0x4b00,
+	scsi_logical_unit_failed_self_configuration		= 0x4c00,
+	scsi_overlapped_commands_attempted			= 0x4e00,
+	osd_quota_error						= 0x5507,
+	scsi_failure_prediction_threshold_exceeded		= 0x5d00,
+	scsi_failure_prediction_threshold_exceeded_false	= 0x5dff,
+	scsi_voltage_fault					= 0x6500,
+};
+
+enum scsi_descriptor_types {
+	scsi_sense_information			= 0x0,
+	scsi_sense_command_specific_information	= 0x1,
+	scsi_sense_key_specific			= 0x2,
+	scsi_sense_field_replaceable_unit	= 0x3,
+	scsi_sense_stream_commands		= 0x4,
+	scsi_sense_block_commands		= 0x5,
+	osd_sense_object_identification		= 0x6,
+	osd_sense_response_integrity_check	= 0x7,
+	osd_sense_attribute_identification	= 0x8,
+	scsi_sense_ata_return			= 0x9,
+
+	scsi_sense_Reserved_first		= 0x0A,
+	scsi_sense_Reserved_last		= 0x7F,
+	scsi_sense_Vendor_specific_first	= 0x80,
+	scsi_sense_Vendor_specific_last		= 0xFF,
+};
+
+struct scsi_sense_descriptor { /* for picking into desc type */
+	u8	descriptor_type; /* one of enum scsi_descriptor_types */
+	u8	additional_length; /* n - 1 */
+	u8	data[];
+} __packed;
+
+/* OSD deploys only scsi descriptor_based sense buffers */
+struct scsi_sense_descriptor_based {
+/*0*/	u8 	response_code; /* 0x72 or 0x73 */
+/*1*/	u8 	sense_key; /* one of enum scsi_sense_keys (4 lower bits) */
+/*2*/	__be16	additional_sense_code; /* enum osd_additional_sense_codes */
+/*4*/	u8	Reserved[3];
+/*7*/	u8	additional_sense_length; /* n - 7 */
+/*8*/	struct	scsi_sense_descriptor ssd[0]; /* variable length, 1 or more */
+} __packed;
+
+/* some descriptors deployed by OSD */
+
+/* SPC3r23 4.5.2.3 Command-specific information sense data descriptor */
+/* Note: this is the same for descriptor_type=00 but with type=00 the
+ *        Reserved[0] == 0x80 (ie. bit-7 set)
+ */
+struct scsi_sense_command_specific_data_descriptor {
+/*0*/	u8	descriptor_type; /* (00h/01h) */
+/*1*/	u8	additional_length; /* (0Ah) */
+/*2*/	u8	Reserved[2];
+/*4*/	__be64  information;
+} __packed;
+/*12*/
+
+struct scsi_sense_key_specific_data_descriptor {
+/*0*/	u8	descriptor_type; /* (02h) */
+/*1*/	u8	additional_length; /* (06h) */
+/*2*/	u8	Reserved[2];
+/* SKSV, C/D, Reserved (2), BPV, BIT POINTER (3) */
+/*4*/	u8	sksv_cd_bpv_bp;
+/*5*/	__be16	value; /* field-pointer/progress-value/retry-count/... */
+/*7*/	u8	Reserved2;
+} __packed;
+/*8*/
+
+/* 4.16.2.1 OSD error identification sense data descriptor - table 52 */
+/* Note: these bits are defined LE order for easy definition, this way the BIT()
+ * number is the same as in the documentation. Below members at
+ * osd_sense_identification_data_descriptor are therefore defined __le32.
+ */
+enum osd_command_functions_bits {
+	OSD_CFB_COMMAND		 = BIT(4),
+	OSD_CFB_CMD_CAP_VERIFIED = BIT(5),
+	OSD_CFB_VALIDATION	 = BIT(7),
+	OSD_CFB_IMP_ST_ATT	 = BIT(12),
+	OSD_CFB_SET_ATT		 = BIT(20),
+	OSD_CFB_SA_CAP_VERIFIED	 = BIT(21),
+	OSD_CFB_GET_ATT		 = BIT(28),
+	OSD_CFB_GA_CAP_VERIFIED	 = BIT(29),
+};
+
+struct osd_sense_identification_data_descriptor {
+/*0*/	u8	descriptor_type; /* (06h) */
+/*1*/	u8	additional_length; /* (1Eh) */
+/*2*/	u8	Reserved[6];
+/*8*/	__le32	not_initiated_functions; /*osd_command_functions_bits*/
+/*12*/	__le32	completed_functions; /*osd_command_functions_bits*/
+/*16*/ 	__be64	partition_id;
+/*24*/	__be64	object_id;
+} __packed;
+/*32*/
+
+struct osd_sense_response_integrity_check_descriptor {
+/*0*/	u8	descriptor_type; /* (07h) */
+/*1*/	u8	additional_length; /* (20h) */
+/*2*/	u8	integrity_check_value[32]; /*FIXME: OSDv2_CRYPTO_KEYID_SIZE*/
+} __packed;
+/*34*/
+
+struct osd_sense_attributes_data_descriptor {
+/*0*/	u8	descriptor_type; /* (08h) */
+/*1*/	u8	additional_length; /* (n-2) */
+/*2*/	u8	Reserved[6];
+	struct osd_sense_attr {
+/*8*/		__be32	attr_page;
+/*12*/		__be32	attr_id;
+/*16*/	} sense_attrs[0]; /* 1 or more */
+} __packed;
+/*variable*/
+
+/* Dig into scsi_sk_illegal_request/scsi_invalid_field_in_cdb errors */
+
+/*FIXME: Support also field in CAPS*/
+#define OSD_CDB_OFFSET(F) offsetof(struct osd_cdb_head, F)
+
+enum osdv2_cdb_field_offset {
+	OSDv1_CFO_STARTING_BYTE	= OSD_CDB_OFFSET(v1.start_address),
+	OSD_CFO_STARTING_BYTE	= OSD_CDB_OFFSET(v2.start_address),
+	OSD_CFO_PARTITION_ID	= OSD_CDB_OFFSET(partition),
+	OSD_CFO_OBJECT_ID	= OSD_CDB_OFFSET(object),
+};
+
+#endif /* ndef __OSD_SENSE_H__ */
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 14/16] osd: Documentation for OSD library
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (12 preceding siblings ...)
  2009-01-25 15:15 ` [PATCH 13/16] libosd: SCSI/OSD Sense decoding support Boaz Harrosh
@ 2009-01-25 15:21 ` Boaz Harrosh
  2009-01-25 15:22 ` [PATCH 15/16] osd: Kconfig file for in-tree builds Boaz Harrosh
  2009-01-25 15:24 ` [PATCH 16/16] scsi: Add osd library to build system Boaz Harrosh
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 15:21 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Add osd.txt to Documentation/scsi/

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 Documentation/scsi/osd.txt |  198 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 198 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/scsi/osd.txt

diff --git a/Documentation/scsi/osd.txt b/Documentation/scsi/osd.txt
new file mode 100644
index 0000000..da162f7
--- /dev/null
+++ b/Documentation/scsi/osd.txt
@@ -0,0 +1,198 @@
+The OSD Standard
+================
+OSD (Object-Based Storage Device) is a T10 SCSI command set that is designed
+to provide efficient operation of input/output logical units that manage the
+allocation, placement, and accessing of variable-size data-storage containers,
+called objects. Objects are intended to contain operating system and application
+constructs. Each object has associated attributes attached to it, which are
+integral part of the object and provide metadata about the object. The standard
+defines some common obligatory attributes, but user attributes can be added as
+needed.
+
+See: http://www.t10.org/ftp/t10/drafts/osd2/ for the latest draft for OSD 2
+or search the web for "OSD SCSI"
+
+OSD in the Linux Kernel
+=======================
+osd-initiator:
+  The main component of OSD in Kernel is the osd-initiator library. Its main
+user is intended to be the pNFS-over-objects layout driver, which uses objects
+as its back-end data storage. Other clients are the other osd parts listed below.
+
+osd-uld:
+  This is a SCSI ULD that registers for OSD type devices and provides a testing
+platform, both for the in-kernel initiator as well as connected targets. It
+currently has no useful user-mode API, though it could have if need be.
+
+exofs:
+  Is an OSD based Linux file system. It uses the osd-initiator and osd-uld,
+to export a usable file system for users.
+See Documentation/filesystems/exofs.txt for more details
+
+osd target:
+  There are no current plans for an OSD target implementation in kernel. For all
+needs, a user-mode target that is based on the scsi tgt target framework is
+available from Ohio Supercomputer Center (OSC) at:
+http://www.open-osd.org/bin/view/Main/OscOsdProject
+There are several other target implementations. See http://open-osd.org for more
+links.
+
+Files and Folders
+=================
+This is the complete list of files included in this work:
+include/scsi/
+	osd_initiator.h   Main API for the initiator library
+	osd_types.h	  Common OSD types
+	osd_sec.h	  Security Manager API
+	osd_protocol.h	  Wire definitions of the OSD standard protocol
+	osd_attributes.h  Wire definitions of OSD attributes
+
+drivers/scsi/osd/
+	osd_initiator.c   OSD-Initiator library implementation
+	osd_uld.c	  The OSD scsi ULD
+	osd_ktest.{h,c}	  In-kernel test suite (called by osd_uld)
+	osd_debug.h	  Some printk macros
+	Makefile	  For both in-tree and out-of-tree compilation
+	Kconfig		  Enables inclusion of the different pieces
+	osd_test.c	  User-mode application to call the kernel tests
+
+The OSD-Initiator Library
+=========================
+osd_initiator is a low level implementation of an osd initiator encoder.
+But even though, it should be intuitive and easy to use. Perhaps over time an
+higher lever will form that automates some of the more common recipes.
+
+init/fini:
+- osd_dev_init() associates a scsi_device with an osd_dev structure
+  and initializes some global pools. This should be done once per scsi_device
+  (OSD LUN). The osd_dev structure is needed for calling osd_start_request().
+
+- osd_dev_fini() cleans up before a osd_dev/scsi_device destruction.
+
+OSD commands encoding, execution, and decoding of results:
+
+struct osd_request's is used to iteratively encode an OSD command and carry
+its state throughout execution. Each request goes through these stages:
+
+a. osd_start_request() allocates the request.
+
+b. Any of the osd_req_* methods is used to encode a request of the specified
+   type.
+
+c. osd_req_add_{get,set}_attr_* may be called to add get/set attributes to the
+   CDB. "List" or "Page" mode can be used exclusively. The attribute-list API
+   can be called multiple times on the same request. However, only one
+   attribute-page can be read, as mandated by the OSD standard.
+
+d. osd_finalize_request() computes offsets into the data-in and data-out buffers
+   and signs the request using the provided capability key and integrity-
+   check parameters.
+
+e. osd_execute_request() may be called to execute the request via the block
+   layer and wait for its completion.  The request can be executed
+   asynchronously by calling the block layer API directly.
+
+f. After execution, osd_req_decode_sense() can be called to decode the request's
+   sense information.
+
+g. osd_req_decode_get_attr() may be called to retrieve osd_add_get_attr_list()
+   values.
+
+h. osd_end_request() must be called to deallocate the request and any resource
+   associated with it. Note that osd_end_request cleans up the request at any
+   stage and it must always be called after a successful osd_start_request().
+
+osd_request's structure:
+
+The OSD standard defines a complex structure of IO segments pointed to by
+members in the CDB. Up to 3 segments can be deployed in the IN-Buffer and up to
+4 in the OUT-Buffer. The ASCII illustration below depicts a secure-read with
+associated get+set of attributes-lists. Other combinations very on the same
+basic theme. From no-segments-used up to all-segments-used.
+
+|________OSD-CDB__________|
+|                         |
+|read_len (offset=0)     -|---------\
+|                         |         |
+|get_attrs_list_length    |         |
+|get_attrs_list_offset   -|----\    |
+|                         |    |    |
+|retrieved_attrs_alloc_len|    |    |
+|retrieved_attrs_offset  -|----|----|-\
+|                         |    |    | |
+|set_attrs_list_length    |    |    | |
+|set_attrs_list_offset   -|-\  |    | |
+|                         | |  |    | |
+|in_data_integ_offset    -|-|--|----|-|-\
+|out_data_integ_offset   -|-|--|--\ | | |
+\_________________________/ |  |  | | | |
+                            |  |  | | | |
+|_______OUT-BUFFER________| |  |  | | | |
+|      Set attr list      |</  |  | | | |
+|                         |    |  | | | |
+|-------------------------|    |  | | | |
+|   Get attr descriptors  |<---/  | | | |
+|                         |       | | | |
+|-------------------------|       | | | |
+|    Out-data integrity   |<------/ | | |
+|                         |         | | |
+\_________________________/         | | |
+                                    | | |
+|________IN-BUFFER________|         | | |
+|      In-Data read       |<--------/ | |
+|                         |           | |
+|-------------------------|           | |
+|      Get attr list      |<----------/ |
+|                         |             |
+|-------------------------|             |
+|    In-data integrity    |<------------/
+|                         |
+\_________________________/
+
+A block device request can carry bidirectional payload by means of associating
+a bidi_read request with a main write-request. Each in/out request is described
+by a chain of BIOs associated with each request.
+The CDB is of a SCSI VARLEN CDB format, as described by OSD standard.
+The OSD standard also mandates alignment restrictions at start of each segment.
+
+In the code, in struct osd_request, there are two _osd_io_info structures to
+describe the IN/OUT buffers above, two BIOs for the data payload and up to five
+_osd_req_data_segment structures to hold the different segments allocation and
+information.
+
+Important: We have chosen to disregard the assumption that a BIO-chain (and
+the resulting sg-list) describes a linear memory buffer. Meaning only first and
+last scatter chain can be incomplete and all the middle chains are of PAGE_SIZE.
+For us, a scatter-gather-list, as its name implies and as used by the Networking
+layer, is to describe a vector of buffers that will be transferred to/from the
+wire. It works very well with current iSCSI transport. iSCSI is currently the
+only deployed OSD transport. In the future we anticipate SAS and FC attached OSD
+devices as well.
+
+The OSD Testing ULD
+===================
+TODO: More user-mode control on tests.
+
+Authors, Mailing list
+=====================
+Please communicate with us on any deployment of osd, whether using this code
+or not.
+
+Any problems, questions, bug reports, lonely OSD nights, please email:
+   OSD Dev List <osd-dev@open-osd.org>
+
+More up-to-date information can be found on:
+http://open-osd.org
+
+Boaz Harrosh <bharrosh@panasas.com>
+Benny Halevy <bhalevy@panasas.com>
+
+References
+==========
+Weber, R., "SCSI Object-Based Storage Device Commands",
+T10/1355-D ANSI/INCITS 400-2004,
+http://www.t10.org/ftp/t10/drafts/osd/osd-r10.pdf
+
+Weber, R., "SCSI Object-Based Storage Device Commands -2 (OSD-2)"
+T10/1729-D, Working Draft, rev. 3
+http://www.t10.org/ftp/t10/drafts/osd2/osd2r03.pdf
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 15/16] osd: Kconfig file for in-tree builds
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (13 preceding siblings ...)
  2009-01-25 15:21 ` [PATCH 14/16] osd: Documentation for OSD library Boaz Harrosh
@ 2009-01-25 15:22 ` Boaz Harrosh
  2009-01-25 15:24 ` [PATCH 16/16] scsi: Add osd library to build system Boaz Harrosh
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 15:22 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

Kconfig file for the drivers/scsi/osd subdirectory.
Adds the following config items:
	config SCSI_OSD_INITIATOR
	config SCSI_OSD_ULD
	config SCSI_OSD_DPRINT_SENSE
	config SCSI_OSD_DEBUG

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 drivers/scsi/osd/Kconfig |   53 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 53 insertions(+), 0 deletions(-)
 create mode 100644 drivers/scsi/osd/Kconfig

diff --git a/drivers/scsi/osd/Kconfig b/drivers/scsi/osd/Kconfig
new file mode 100644
index 0000000..861b5ce
--- /dev/null
+++ b/drivers/scsi/osd/Kconfig
@@ -0,0 +1,53 @@
+#
+# Kernel configuration file for the OSD scsi protocol
+#
+# Copyright (C) 2008 Panasas Inc.  All rights reserved.
+#
+# Authors:
+#   Boaz Harrosh <bharrosh@panasas.com>
+#   Benny Halevy <bhalevy@panasas.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public version 2 License as
+# published by the Free Software Foundation
+#
+# FIXME: SCSI_OSD_INITIATOR should select CONFIG (HMAC) SHA1 somehow.
+#        How is it done properly?
+#
+
+config SCSI_OSD_INITIATOR
+	tristate "OSD-Initiator library"
+	depends on SCSI
+	help
+		Enable the OSD-Initiator library (libosd.ko).
+		NOTE: You must also select CRYPTO_SHA1 + CRYPTO_HMAC and their
+		dependencies
+
+config SCSI_OSD_ULD
+	tristate "OSD Upper Level driver"
+	depends on SCSI_OSD_INITIATOR
+	help
+		Build a SCSI upper layer driver that exports /dev/osdX devices
+		to user-mode for testing and controlling OSD devices. It is also
+		needed by exofs, for mounting an OSD based file system.
+
+config SCSI_OSD_DPRINT_SENSE
+    int "(0-2) When sense is returned, DEBUG print all sense descriptors"
+    default 1
+    depends on SCSI_OSD_INITIATOR
+    help
+        When a CHECK_CONDITION status is returned from a target, and a
+        sense-buffer is retrieved, turning this on will dump a full
+        sense-decoding message. Setting to 2 will also print recoverable
+        errors that might be regularly returned for some filesystem
+        operations.
+
+config SCSI_OSD_DEBUG
+	bool "Compile All OSD modules with lots of DEBUG prints"
+	default n
+	depends on SCSI_OSD_INITIATOR
+	help
+		OSD Code is populated with lots of OSD_DEBUG(..) printouts to
+		dmesg. Enable this if you found a bug and you want to help us
+		track the problem (see also MAINTAINERS). Setting this will also
+		force SCSI_OSD_DPRINT_SENSE=2.
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 16/16] scsi: Add osd library to build system
  2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
                   ` (14 preceding siblings ...)
  2009-01-25 15:22 ` [PATCH 15/16] osd: Kconfig file for in-tree builds Boaz Harrosh
@ 2009-01-25 15:24 ` Boaz Harrosh
  15 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-25 15:24 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

OSD in kernel source code is assumed to be at:
drivers/scsi/osd/ with its own Makefile and Kconfig

Add includes to them from drivers/scsi Makefile and Kconfig
Add OSD to MAINTAINERS file

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
---
 MAINTAINERS           |   10 ++++++++++
 drivers/scsi/Kconfig  |    2 ++
 drivers/scsi/Makefile |    2 ++
 3 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6f65a26..3d05091 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3260,6 +3260,16 @@ L:	orinoco-devel@lists.sourceforge.net
 W:	http://www.nongnu.org/orinoco/
 S:	Maintained
 
+OSD LIBRARY
+P:	Boaz Harrosh
+M:	bharrosh@panasas.com
+P:	Benny Halevy
+M:	bhalevy@panasas.com
+L:	osd-dev@open-osd.org
+W:	http://open-osd.org
+T:	git://git.open-osd.org/open-osd.git
+S:	Maintained
+
 P54 WIRELESS DRIVER
 P:	Michael Wu
 M:	flamingice@sourmilk.net
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 601c2a8..e420ad0 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1806,4 +1806,6 @@ source "drivers/scsi/pcmcia/Kconfig"
 
 source "drivers/scsi/device_handler/Kconfig"
 
+source "drivers/scsi/osd/Kconfig"
+
 endmenu
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 7461eb0..05558b1 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -137,6 +137,8 @@ obj-$(CONFIG_CHR_DEV_SG)	+= sg.o
 obj-$(CONFIG_CHR_DEV_SCH)	+= ch.o
 obj-$(CONFIG_SCSI_ENCLOSURE)	+= ses.o
 
+obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/
+
 # This goes last, so that "real" scsi devices probe earlier
 obj-$(CONFIG_SCSI_DEBUG)	+= scsi_debug.o
 
-- 
1.6.0.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel
  2009-01-25 14:58 ` [PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel Boaz Harrosh
@ 2009-01-28 16:32   ` James Bottomley
  2009-01-29 11:12     ` Boaz Harrosh
  0 siblings, 1 reply; 23+ messages in thread
From: James Bottomley @ 2009-01-28 16:32 UTC (permalink / raw)
  To: Boaz Harrosh; +Cc: Andrew Morton, linux-scsi, open-osd ml

On Sun, 2009-01-25 at 16:58 +0200, Boaz Harrosh wrote:
> Kernel clients like exofs can retrieve struct osd_dev(s)
> by means of below API.
> 
> + osduld_path_lookup() - given a path (e.g "/dev/osd0") locks and
> returns the corresponding struct osd_dev, which is then needed
> for subsequent libosd use.
> 
> + osduld_put_device() - free up use of an osd_dev.
> 
> Devices can be shared by multiple clients. The osd_uld_device's
> life time is governed by an embedded kref structure.
> 
> The osd_uld_device holds an extra reference to both it's
> char-device and it's scsi_device, and will release these just
> before the final deallocation.
> 
> There are three possible lock sources of the osd_uld_device
> 1. First and for most is the probe() function called by
>   scsi-ml upon a successful login into a target. Released in release()
>   when logout.
> 2. Second by user-mode file handles opened on the char-dev.
> 3. Third is here by Kernel users.
> All three locks must be removed before the osd_uld_device is freed.
> 
> The MODULE has three lock sources as well:
> 1. scsi-ml at probe() time, removed after release(). (login/logout)
> 2. The user-mode file handles open/close.
> 3. Import symbols by client modules like exofs.
> 
> TODO:
>   This API is not enough for the pNFS-objects LD. A more versatile
>   API will be needed. Proposed API could be:
>   struct osd_dev *osduld_sysid_lookup(const char id[OSD_SYSTEMID_LEN]);
> 
> Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
> ---
>  drivers/scsi/osd/osd_uld.c   |   63 ++++++++++++++++++++++++++++++++++++++++++
>  include/scsi/osd_initiator.h |    4 ++
>  2 files changed, 67 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
> index f6f9a99..cd4ca7c 100644
> --- a/drivers/scsi/osd/osd_uld.c
> +++ b/drivers/scsi/osd/osd_uld.c
> @@ -173,6 +173,69 @@ static const struct file_operations osd_fops = {
>  	.unlocked_ioctl = osd_uld_ioctl,
>  };
>  
> +struct osd_dev *osduld_path_lookup(const char *path)

Is there no other way to do this?  A kernel component opening another
kernel component by device path is generally frowned upon.

The way it should work is to have a user space process initiate
everything because it can see the full device space and cope with the
problems that may occur on first open in user space.

> +{
> +	struct nameidata nd;
> +	struct inode *inode;
> +	struct cdev *cdev;
> +	struct osd_uld_device *uninitialized_var(oud);
> +	int error;
> +
> +	if (!path || !*path) {
> +		OSD_ERR("Mount with !path || !*path\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	error = path_lookup(path, LOOKUP_FOLLOW, &nd);
> +	if (error) {
> +		OSD_ERR("path_lookup of %s faild=>%d\n", path, error);
> +		return ERR_PTR(error);
> +	}
> +
> +	inode = nd.path.dentry->d_inode;
> +	error = -EINVAL; /* Not the right device e.g osd_uld_device */
> +	if (!S_ISCHR(inode->i_mode)) {
> +		OSD_DEBUG("!S_ISCHR()\n");
> +		goto out;
> +	}
> +
> +	cdev = inode->i_cdev;
> +	if (!cdev) {
> +		OSD_ERR("Before mounting an OSD Based filesystem\n");
> +		OSD_ERR("  user-mode must open+close the %s device\n", path);
> +		OSD_ERR("  Example: bash: echo < %s\n", path);
> +		goto out;
> +	}
> +
> +	/* The Magic wand. Is it our char-dev */
> +	/* TODO: Support sg devices */
> +	if (cdev->owner != THIS_MODULE) {
> +		OSD_ERR("Error mounting %s - is not an OSD device\n", path);
> +		goto out;
> +	}
> +
> +	oud = container_of(cdev, struct osd_uld_device, cdev);
> +
> +	__uld_get(oud);
> +	error = 0;
> +
> +out:
> +	path_put(&nd.path);
> +	return error ? ERR_PTR(error) : &oud->od;
> +}
> +EXPORT_SYMBOL(osduld_path_lookup);
> +
> +void osduld_put_device(struct osd_dev *od)
> +{
> +	if (od) {
> +		struct osd_uld_device *oud = container_of(od,
> +						struct osd_uld_device, od);
> +
> +		__uld_put(oud);
> +	}
> +}
> +EXPORT_SYMBOL(osduld_put_device);
> +
>  /*
>   * Scsi Device operations
>   */
> diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
> index a5dbbdd..e84dc7a 100644
> --- a/include/scsi/osd_initiator.h
> +++ b/include/scsi/osd_initiator.h
> @@ -33,6 +33,10 @@ struct osd_dev {
>  	unsigned def_timeout;
>  };
>  
> +/* Retrieve/return osd_dev(s) for use by Kernel clients */
> +struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/
> +void osduld_put_device(struct osd_dev *od);
> +
>  /* Add/remove test ioctls from external modules */
>  typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
>  int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
> -- 
> 1.6.0.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 13/16] libosd: SCSI/OSD Sense decoding support
  2009-01-25 15:15 ` [PATCH 13/16] libosd: SCSI/OSD Sense decoding support Boaz Harrosh
@ 2009-01-28 16:32   ` James Bottomley
  2009-01-29 10:19     ` Boaz Harrosh
  0 siblings, 1 reply; 23+ messages in thread
From: James Bottomley @ 2009-01-28 16:32 UTC (permalink / raw)
  To: Boaz Harrosh; +Cc: Andrew Morton, linux-scsi, open-osd ml

On Sun, 2009-01-25 at 17:15 +0200, Boaz Harrosh wrote:
> Implementation of the osd_req_decode_sense() API. Can be called by
> library users to decode what failed in command executions.
> 
> Add SCSI_OSD_DPRINT_SENSE Kconfig variable. Possible values are:
> 0 - Do not print any errors to messages file <KERN_ERR>
> 1 - (Default) Print only decoded errors that are not recoverable.
>     Recoverable errors are those that the target has complied with
>     the request but with a warning. For example read passed end of
>     object will return zeros after the last valid byte.
> 2- Print all errors.
> 
> Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
> ---
>  drivers/scsi/osd/Kbuild          |    6 +
>  drivers/scsi/osd/osd_initiator.c |  191 ++++++++++++++++++++++++++++
>  include/scsi/osd_initiator.h     |   49 +++++++
>  include/scsi/osd_sense.h         |  260 ++++++++++++++++++++++++++++++++++++++
>  4 files changed, 506 insertions(+), 0 deletions(-)
>  create mode 100644 include/scsi/osd_sense.h
> 
> diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild
> index 9d38248..0e207aa 100644
> --- a/drivers/scsi/osd/Kbuild
> +++ b/drivers/scsi/osd/Kbuild
> @@ -20,6 +20,12 @@ ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
>  CONFIG_SCSI_OSD_ULD=m
>  ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE
>  
> +# CONFIG_SCSI_OSD_DPRINT_SENSE =
> +#	0 - no print of errors
> +#	1 - print errors
> +#	2 - errors + warrnings
> +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1

Why are these all defines not Kconfig variables?

>  # Uncomment to turn debug on
>  # ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
>  
> diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
> index f6340c2..0bbbf27 100644
> --- a/drivers/scsi/osd/osd_initiator.c
> +++ b/drivers/scsi/osd/osd_initiator.c
> @@ -42,6 +42,8 @@
>  #include <scsi/osd_initiator.h>
>  #include <scsi/osd_sec.h>
>  #include <scsi/osd_attributes.h>
> +#include <scsi/osd_sense.h>
> +
>  #include <scsi/scsi_device.h>
>  
>  #include "osd_debug.h"
> @@ -1339,6 +1341,195 @@ int osd_finalize_request(struct osd_request *or,
>  }
>  EXPORT_SYMBOL(osd_finalize_request);
>  
> +#define OSD_SENSE_PRINT1(fmt, a...) \
> +	do { \
> +		if (__cur_sense_need_output) \
> +			OSD_ERR(fmt, ##a); \
> +	} while (0)
> +
> +#define OSD_SENSE_PRINT2(fmt, a...) OSD_SENSE_PRINT1("    " fmt, ##a)
> +
> +int osd_req_decode_sense_full(struct osd_request *or,
> +	struct osd_sense_info *osi, bool silent,
> +	struct osd_obj_id *bad_obj_list __unused, int max_obj __unused,
> +	struct osd_attr *bad_attr_list, int max_attr)
> +{
> +	int sense_len, original_sense_len;
> +	struct osd_sense_info local_osi;
> +	struct scsi_sense_descriptor_based *ssdb;
> +	void *cur_descriptor;
> +#if (CONFIG_SCSI_OSD_DPRINT_SENSE == 0)
> +	const bool __cur_sense_need_output = false;
> +#else
> +	bool __cur_sense_need_output = !silent;
> +#endif
> +
> +	if (!or->request->errors)
> +		return 0;
> +
> +	ssdb = or->request->sense;
> +	sense_len = or->request->sense_len;
> +	if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) {
> +		OSD_ERR("Block-layer returned error(0x%x) but "
> +			"sense_len(%u) || key(%d) is empty\n",
> +			or->request->errors, sense_len, ssdb->sense_key);
> +		return -EIO;
> +	}
> +
> +	if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) {
> +		OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n",
> +			ssdb->response_code, sense_len);
> +		return -EIO;
> +	}
> +
> +	osi = osi ? : &local_osi;
> +	memset(osi, 0, sizeof(*osi));
> +	osi->key = ssdb->sense_key;
> +	osi->additional_code = be16_to_cpu(ssdb->additional_sense_code);
> +	original_sense_len = ssdb->additional_sense_length + 8;
> +
> +#if (CONFIG_SCSI_OSD_DPRINT_SENSE == 1)
> +	if (__cur_sense_need_output)
> +		__cur_sense_need_output = (osi->key > scsi_sk_recovered_error);
> +#endif
> +	OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) "
> +			"additional_code=0x%x\n",
> +			osi->key, original_sense_len, sense_len,
> +			osi->additional_code);
> +
> +	if (original_sense_len < sense_len)
> +		sense_len = original_sense_len;
> +
> +	cur_descriptor = ssdb->ssd;
> +	sense_len -= sizeof(*ssdb);
> +	while (sense_len > 0) {
> +		struct scsi_sense_descriptor *ssd = cur_descriptor;
> +		int cur_len = ssd->additional_length + 2;
> +
> +		sense_len -= cur_len;
> +
> +		if (sense_len < 0)
> +			break; /* sense was truncated */
> +
> +		switch (ssd->descriptor_type) {
> +		case scsi_sense_information:
> +		case scsi_sense_command_specific_information:
> +		{
> +			struct scsi_sense_command_specific_data_descriptor
> +				*sscd = cur_descriptor;
> +
> +			osi->command_info =
> +				get_unaligned_be64(&sscd->information) ;
> +			OSD_SENSE_PRINT2(
> +				"command_specific_information 0x%llx \n",
> +				_LLU(osi->command_info));
> +			break;
> +		}
> +		case scsi_sense_key_specific:
> +		{
> +			struct scsi_sense_key_specific_data_descriptor
> +				*ssks = cur_descriptor;
> +
> +			osi->sense_info = get_unaligned_be16(&ssks->value);
> +			OSD_SENSE_PRINT2(
> +				"sense_key_specific_information %u"
> +				"sksv_cd_bpv_bp (0x%x)\n",
> +				osi->sense_info, ssks->sksv_cd_bpv_bp);
> +			break;
> +		}
> +		case osd_sense_object_identification:
> +		{ /*FIXME: Keep first not last, Store in array*/
> +			struct osd_sense_identification_data_descriptor
> +				*osidd = cur_descriptor;
> +
> +			osi->not_initiated_command_functions =
> +				le32_to_cpu(osidd->not_initiated_functions);
> +			osi->completed_command_functions =
> +				le32_to_cpu(osidd->completed_functions);
> +			osi->obj.partition = be64_to_cpu(osidd->partition_id);
> +			osi->obj.id = be64_to_cpu(osidd->object_id);
> +			OSD_SENSE_PRINT2(
> +				"object_identification pid=0x%llx oid=0x%llx\n",
> +				_LLU(osi->obj.partition), _LLU(osi->obj.id));
> +			OSD_SENSE_PRINT2(
> +				"not_initiated_bits(%x) "
> +				"completed_command_bits(%x)\n",
> +				osi->not_initiated_command_functions,
> +				osi->completed_command_functions);
> +			break;
> +		}
> +		case osd_sense_response_integrity_check:
> +		{
> +			struct osd_sense_response_integrity_check_descriptor
> +				*osricd = cur_descriptor;
> +			const unsigned len =
> +					  sizeof(osricd->integrity_check_value);
> +			char key_dump[len*4 + 2]; /* 2nibbles+space+ASCII */
> +
> +			hex_dump_to_buffer(osricd->integrity_check_value, len,
> +				       32, 1, key_dump, sizeof(key_dump), true);
> +			OSD_SENSE_PRINT2("response_integrity [%s]\n", key_dump);
> +		}
> +		case osd_sense_attribute_identification:
> +		{
> +			struct osd_sense_attributes_data_descriptor
> +				*osadd = cur_descriptor;
> +			int len = min(cur_len, sense_len);
> +			int i = 0;
> +			struct osd_sense_attr *pattr = osadd->sense_attrs;
> +
> +			while (len < 0) {
> +				u32 attr_page = be32_to_cpu(pattr->attr_page);
> +				u32 attr_id = be32_to_cpu(pattr->attr_id);
> +
> +				if (i++ == 0) {
> +					osi->attr.attr_page = attr_page;
> +					osi->attr.attr_id = attr_id;
> +				}
> +
> +				if (bad_attr_list && max_attr) {
> +					bad_attr_list->attr_page = attr_page;
> +					bad_attr_list->attr_id = attr_id;
> +					bad_attr_list++;
> +					max_attr--;
> +				}
> +				OSD_SENSE_PRINT2(
> +					"osd_sense_attribute_identification"
> +					"attr_page=0x%x attr_id=0x%x\n",
> +					attr_page, attr_id);
> +			}
> +		}
> +		/*These are not legal for OSD*/
> +		case scsi_sense_field_replaceable_unit:
> +			OSD_SENSE_PRINT2("scsi_sense_field_replaceable_unit\n");
> +			break;
> +		case scsi_sense_stream_commands:
> +			OSD_SENSE_PRINT2("scsi_sense_stream_commands\n");
> +			break;
> +		case scsi_sense_block_commands:
> +			OSD_SENSE_PRINT2("scsi_sense_block_commands\n");
> +			break;
> +		case scsi_sense_ata_return:
> +			OSD_SENSE_PRINT2("scsi_sense_ata_return\n");
> +			break;
> +		default:
> +			if (ssd->descriptor_type <= scsi_sense_Reserved_last)
> +				OSD_SENSE_PRINT2(
> +					"scsi_sense Reserved descriptor (0x%x)",
> +					ssd->descriptor_type);
> +			else
> +				OSD_SENSE_PRINT2(
> +					"scsi_sense Vendor descriptor (0x%x)",
> +					ssd->descriptor_type);
> +		}
> +
> +		cur_descriptor += cur_len;
> +	}
> +
> +	return (osi->key > scsi_sk_recovered_error) ? -EIO : 0;
> +}
> +EXPORT_SYMBOL(osd_req_decode_sense_full);
> +
>  /*
>   * Implementation of osd_sec.h API
>   * TODO: Move to a separate osd_sec.c file at a later stage.
> diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
> index 24edeae..b24d961 100644
> --- a/include/scsi/osd_initiator.h
> +++ b/include/scsi/osd_initiator.h
> @@ -217,6 +217,55 @@ int osd_execute_request_async(struct osd_request *or,
>  	osd_req_done_fn *done, void *private);
>  
>  /**
> + * osd_req_decode_sense_full - Decode sense information after execution.
> + *
> + * @or:           - osd_request to examine
> + * @osi           - Recievs a more detailed error report information (optional).
> + * @silent        - Do not print to dmsg (Even if enabled)
> + * @bad_obj_list  - Some commands act on multiple objects. Failed objects will
> + *                  be recieved here (optional)
> + * @max_obj       - Size of @bad_obj_list.
> + * @bad_attr_list - List of failing attributes (optional)
> + * @max_attr      - Size of @bad_attr_list.
> + *
> + * After execution, sense + return code can be analyzed using this function. The
> + * return code is the final disposition on the error. So it is possible that a
> + * CHECK_CONDITION was returned from target but this will return NO_ERROR, for
> + * example on recovered errors. All parameters are optional if caller does
> + * not need any returned information.
> + * Note: This function will also dump the error to dmsg according to settings
> + * of the SCSI_OSD_DPRINT_SENSE Kconfig value. Set @silent if you know the
> + * command would routinely fail, to not spam the dmsg file.
> + */
> +struct osd_sense_info {
> +	int key;		/* one of enum scsi_sense_keys */
> +	int additional_code ;	/* enum osd_additional_sense_codes */
> +	union { /* Sense specific information */
> +		u16 sense_info;
> +		u16 cdb_field_offset; 	/* scsi_invalid_field_in_cdb */
> +	};
> +	union { /* Command specific information */
> +		u64 command_info;
> +	};
> +
> +	u32 not_initiated_command_functions; /* osd_command_functions_bits */
> +	u32 completed_command_functions; /* osd_command_functions_bits */
> +	struct osd_obj_id obj;
> +	struct osd_attr attr;
> +};
> +
> +int osd_req_decode_sense_full(struct osd_request *or,
> +	struct osd_sense_info *osi, bool silent,
> +	struct osd_obj_id *bad_obj_list, int max_obj,
> +	struct osd_attr *bad_attr_list, int max_attr);
> +
> +static inline int osd_req_decode_sense(struct osd_request *or,
> +	struct osd_sense_info *osi)
> +{
> +	return osd_req_decode_sense_full(or, osi, false, NULL, 0, NULL, 0);
> +}
> +
> +/**
>   * osd_end_request - return osd_request to free store
>   *
>   * @or:		osd_request to free
> diff --git a/include/scsi/osd_sense.h b/include/scsi/osd_sense.h
> new file mode 100644
> index 0000000..ff9b33c
> --- /dev/null
> +++ b/include/scsi/osd_sense.h
> @@ -0,0 +1,260 @@
> +/*
> + * osd_sense.h - OSD Related sense handling definitions.
> + *
> + * Copyright (C) 2008 Panasas Inc.  All rights reserved.
> + *
> + * Authors:
> + *   Boaz Harrosh <bharrosh@panasas.com>
> + *   Benny Halevy <bhalevy@panasas.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + *
> + * This file contains types and constants that are defined by the protocol
> + * Note: All names and symbols are taken from the OSD standard's text.
> + */
> +#ifndef __OSD_SENSE_H__
> +#define __OSD_SENSE_H__
> +
> +#include <scsi/osd_protocol.h>
> +
> +/* SPC3r23 4.5.6 Sense key and sense code definitions table 27 */
> +enum scsi_sense_keys {
> +	scsi_sk_no_sense        = 0x0,
> +	scsi_sk_recovered_error = 0x1,
> +	scsi_sk_not_ready       = 0x2,
> +	scsi_sk_medium_error    = 0x3,
> +	scsi_sk_hardware_error  = 0x4,
> +	scsi_sk_illegal_request = 0x5,
> +	scsi_sk_unit_attention  = 0x6,
> +	scsi_sk_data_protect    = 0x7,
> +	scsi_sk_blank_check     = 0x8,
> +	scsi_sk_vendor_specific = 0x9,
> +	scsi_sk_copy_aborted    = 0xa,
> +	scsi_sk_aborted_command = 0xb,
> +	scsi_sk_volume_overflow = 0xd,
> +	scsi_sk_miscompare      = 0xe,
> +	scsi_sk_reserved        = 0xf,
> +};
> +
> +/* SPC3r23 4.5.6 Sense key and sense code definitions table 28 */
> +/* Note: only those which can be returned by an OSD target. Most of
> + *       these errors are taken care of by the generic scsi layer.
> + */
> +enum osd_additional_sense_codes {
> +	scsi_no_additional_sense_information			= 0x0000,
> +	scsi_operation_in_progress				= 0x0016,
> +	scsi_cleaning_requested					= 0x0017,
> +	scsi_lunr_cause_not_reportable				= 0x0400,
> +	scsi_logical_unit_is_in_process_of_becoming_ready	= 0x0401,
> +	scsi_lunr_initializing_command_required			= 0x0402,
> +	scsi_lunr_manual_intervention_required			= 0x0403,
> +	scsi_lunr_operation_in_progress				= 0x0407,
> +	scsi_lunr_selftest_in_progress				= 0x0409,
> +	scsi_luna_asymmetric_access_state_transition		= 0x040a,
> +	scsi_luna_target_port_in_standby_state			= 0x040b,
> +	scsi_luna_target_port_in_unavailable_state		= 0x040c,
> +	scsi_lunr_notify_enable_spinup_required			= 0x0411,
> +	scsi_logical_unit_does_not_respond_to_selection		= 0x0500,
> +	scsi_logical_unit_communication_failure			= 0x0800,
> +	scsi_logical_unit_communication_timeout			= 0x0801,
> +	scsi_logical_unit_communication_parity_error		= 0x0802,
> +	scsi_error_log_overflow					= 0x0a00,
> +	scsi_warning						= 0x0b00,
> +	scsi_warning_specified_temperature_exceeded		= 0x0b01,
> +	scsi_warning_enclosure_degraded				= 0x0b02,
> +	scsi_write_error_unexpected_unsolicited_data		= 0x0c0c,
> +	scsi_write_error_not_enough_unsolicited_data		= 0x0c0d,
> +	scsi_invalid_information_unit				= 0x0e00,
> +	scsi_invalid_field_in_command_information_unit		= 0x0e03,
> +	scsi_read_error_failed_retransmission_request		= 0x1113,
> +	scsi_parameter_list_length_error			= 0x1a00,
> +	scsi_invalid_command_operation_code			= 0x2000,
> +	scsi_invalid_field_in_cdb				= 0x2400,
> +	osd_security_audit_value_frozen				= 0x2404,
> +	osd_security_working_key_frozen				= 0x2405,
> +	osd_nonce_not_unique					= 0x2406,
> +	osd_nonce_timestamp_out_of_range			= 0x2407,
> +	scsi_logical_unit_not_supported				= 0x2500,
> +	scsi_invalid_field_in_parameter_list			= 0x2600,
> +	scsi_parameter_not_supported				= 0x2601,
> +	scsi_parameter_value_invalid				= 0x2602,
> +	scsi_invalid_release_of_persistent_reservation		= 0x2604,
> +	osd_invalid_dataout_buffer_integrity_check_value	= 0x260f,
> +	scsi_not_ready_to_ready_change_medium_may_have_changed	= 0x2800,
> +	scsi_power_on_reset_or_bus_device_reset_occurred	= 0x2900,
> +	scsi_power_on_occurred					= 0x2901,
> +	scsi_scsi_bus_reset_occurred				= 0x2902,
> +	scsi_bus_device_reset_function_occurred			= 0x2903,
> +	scsi_device_internal_reset				= 0x2904,
> +	scsi_transceiver_mode_changed_to_single_ended		= 0x2905,
> +	scsi_transceiver_mode_changed_to_lvd			= 0x2906,
> +	scsi_i_t_nexus_loss_occurred				= 0x2907,
> +	scsi_parameters_changed					= 0x2a00,
> +	scsi_mode_parameters_changed				= 0x2a01,
> +	scsi_asymmetric_access_state_changed			= 0x2a06,
> +	scsi_priority_changed					= 0x2a08,
> +	scsi_command_sequence_error				= 0x2c00,
> +	scsi_previous_busy_status				= 0x2c07,
> +	scsi_previous_task_set_full_status			= 0x2c08,
> +	scsi_previous_reservation_conflict_status		= 0x2c09,
> +	osd_partition_or_collection_contains_user_objects	= 0x2c0a,
> +	scsi_commands_cleared_by_another_initiator		= 0x2f00,
> +	scsi_cleaning_failure					= 0x3007,
> +	scsi_enclosure_failure					= 0x3400,
> +	scsi_enclosure_services_failure				= 0x3500,
> +	scsi_unsupported_enclosure_function			= 0x3501,
> +	scsi_enclosure_services_unavailable			= 0x3502,
> +	scsi_enclosure_services_transfer_failure		= 0x3503,
> +	scsi_enclosure_services_transfer_refused		= 0x3504,
> +	scsi_enclosure_services_checksum_error			= 0x3505,
> +	scsi_rounded_parameter					= 0x3700,
> +	osd_read_past_end_of_user_object			= 0x3b17,
> +	scsi_logical_unit_has_not_self_configured_yet		= 0x3e00,
> +	scsi_logical_unit_failure				= 0x3e01,
> +	scsi_timeout_on_logical_unit				= 0x3e02,
> +	scsi_logical_unit_failed_selftest			= 0x3e03,
> +	scsi_logical_unit_unable_to_update_selftest_log		= 0x3e04,
> +	scsi_target_operating_conditions_have_changed		= 0x3f00,
> +	scsi_microcode_has_been_changed				= 0x3f01,
> +	scsi_inquiry_data_has_changed				= 0x3f03,
> +	scsi_echo_buffer_overwritten				= 0x3f0f,
> +	scsi_diagnostic_failure_on_component_nn_first		= 0x4080,
> +	scsi_diagnostic_failure_on_component_nn_last		= 0x40ff,
> +	scsi_message_error					= 0x4300,
> +	scsi_internal_target_failure				= 0x4400,
> +	scsi_select_or_reselect_failure				= 0x4500,
> +	scsi_scsi_parity_error					= 0x4700,
> +	scsi_data_phase_crc_error_detected			= 0x4701,
> +	scsi_scsi_parity_error_detected_during_st_data_phase	= 0x4702,
> +	scsi_asynchronous_information_protection_error_detected	= 0x4704,
> +	scsi_protocol_service_crc_error				= 0x4705,
> +	scsi_phy_test_function_in_progress			= 0x4706,
> +	scsi_invalid_message_error				= 0x4900,
> +	scsi_command_phase_error				= 0x4a00,
> +	scsi_data_phase_error					= 0x4b00,
> +	scsi_logical_unit_failed_self_configuration		= 0x4c00,
> +	scsi_overlapped_commands_attempted			= 0x4e00,
> +	osd_quota_error						= 0x5507,
> +	scsi_failure_prediction_threshold_exceeded		= 0x5d00,
> +	scsi_failure_prediction_threshold_exceeded_false	= 0x5dff,
> +	scsi_voltage_fault					= 0x6500,
> +};
> +
> +enum scsi_descriptor_types {
> +	scsi_sense_information			= 0x0,
> +	scsi_sense_command_specific_information	= 0x1,
> +	scsi_sense_key_specific			= 0x2,
> +	scsi_sense_field_replaceable_unit	= 0x3,
> +	scsi_sense_stream_commands		= 0x4,
> +	scsi_sense_block_commands		= 0x5,
> +	osd_sense_object_identification		= 0x6,
> +	osd_sense_response_integrity_check	= 0x7,
> +	osd_sense_attribute_identification	= 0x8,
> +	scsi_sense_ata_return			= 0x9,
> +
> +	scsi_sense_Reserved_first		= 0x0A,
> +	scsi_sense_Reserved_last		= 0x7F,
> +	scsi_sense_Vendor_specific_first	= 0x80,
> +	scsi_sense_Vendor_specific_last		= 0xFF,
> +};
> +
> +struct scsi_sense_descriptor { /* for picking into desc type */
> +	u8	descriptor_type; /* one of enum scsi_descriptor_types */
> +	u8	additional_length; /* n - 1 */
> +	u8	data[];
> +} __packed;

Why is it necessary to do a complete duplication of all the sense header
handling and print out in include/scsi/scsi_eh.h and
drivers/scsi/constants.c ... can't these two frameworks be integrated?

James


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 13/16] libosd: SCSI/OSD Sense decoding support
  2009-01-28 16:32   ` James Bottomley
@ 2009-01-29 10:19     ` Boaz Harrosh
  2009-01-29 15:00       ` James Bottomley
  0 siblings, 1 reply; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-29 10:19 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

James Bottomley wrote:
> On Sun, 2009-01-25 at 17:15 +0200, Boaz Harrosh wrote:
>>  
>> +# CONFIG_SCSI_OSD_DPRINT_SENSE =
>> +#	0 - no print of errors
>> +#	1 - print errors
>> +#	2 - errors + warrnings
>> +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1
> 
> Why are these all defines not Kconfig variables?
> 

They are a "Kconfig variables". What you see above is a section of the 
Kbuild file that's for the out-of-tree compilation. [ifneq ($(OSD_INC),)]
For the out-of-tree compilation the Kbuild file defines everything as
configured in.

<snip>
diff --git a/include/scsi/osd_sense.h b/include/scsi/osd_sense.h
>> new file mode 100644
>> index 0000000..ff9b33c
>> --- /dev/null
>> +++ b/include/scsi/osd_sense.h
>> @@ -0,0 +1,260 @@
>> +/*
>> + * osd_sense.h - OSD Related sense handling definitions.
>> + *
>> + * Copyright (C) 2008 Panasas Inc.  All rights reserved.
>> + *
>> + * Authors:
>> + *   Boaz Harrosh <bharrosh@panasas.com>
>> + *   Benny Halevy <bhalevy@panasas.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2
>> + *
>> + * This file contains types and constants that are defined by the protocol
>> + * Note: All names and symbols are taken from the OSD standard's text.
>> + */
>> +#ifndef __OSD_SENSE_H__
>> +#define __OSD_SENSE_H__
>> 
<snip>
>> +	scsi_sense_Reserved_first		= 0x0A,
>> +	scsi_sense_Reserved_last		= 0x7F,
>> +	scsi_sense_Vendor_specific_first	= 0x80,
>> +	scsi_sense_Vendor_specific_last		= 0xFF,
>> +};
>> +
>> +struct scsi_sense_descriptor { /* for picking into desc type */
>> +	u8	descriptor_type; /* one of enum scsi_descriptor_types */
>> +	u8	additional_length; /* n - 1 */
>> +	u8	data[];
>> +} __packed;
> 
> Why is it necessary to do a complete duplication of all the sense header
> handling and print out in include/scsi/scsi_eh.h and
> drivers/scsi/constants.c ... can't these two frameworks be integrated?
> 

I have tried. 
Some of this stuff is new and exclusive to OSD so the file is needed.
The rest is buried in constants.c while I need them in an header file.
If it is accepted by you to take some of constants.c and put them in an
header then, sure I can do that. Refactor some of above stuff and constants.c
stuff into an scsi_sense.h file and use them at both places.
(I will send an RFC after things settle a bit)

Other then that, the source of the osd_req_decode_sense() is totally new to
osd. An osd target returns very detailed, variable length, sense information
that denotes exactly what field of the CDB and/or buffer-data failed it's checks
as well as details on other failures and conditions. Also later we will support
security signatures of sense data.

> James
> 

Thanks
Boaz

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel
  2009-01-28 16:32   ` James Bottomley
@ 2009-01-29 11:12     ` Boaz Harrosh
  0 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-29 11:12 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml, linux-fsdevel

James Bottomley wrote:
> On Sun, 2009-01-25 at 16:58 +0200, Boaz Harrosh wrote:
>> Kernel clients like exofs can retrieve struct osd_dev(s)
>> by means of below API.
>>
>> + osduld_path_lookup() - given a path (e.g "/dev/osd0") locks and
>> returns the corresponding struct osd_dev, which is then needed
>> for subsequent libosd use.
>>
>> + osduld_put_device() - free up use of an osd_dev.
>>
>> Devices can be shared by multiple clients. The osd_uld_device's
>> life time is governed by an embedded kref structure.
>>
>> The osd_uld_device holds an extra reference to both it's
>> char-device and it's scsi_device, and will release these just
>> before the final deallocation.
>>
>> There are three possible lock sources of the osd_uld_device
>> 1. First and for most is the probe() function called by
>>   scsi-ml upon a successful login into a target. Released in release()
>>   when logout.
>> 2. Second by user-mode file handles opened on the char-dev.
>> 3. Third is here by Kernel users.
>> All three locks must be removed before the osd_uld_device is freed.
>>
>> The MODULE has three lock sources as well:
>> 1. scsi-ml at probe() time, removed after release(). (login/logout)
>> 2. The user-mode file handles open/close.
>> 3. Import symbols by client modules like exofs.
>>
>> TODO:
>>   This API is not enough for the pNFS-objects LD. A more versatile
>>   API will be needed. Proposed API could be:
>>   struct osd_dev *osduld_sysid_lookup(const char id[OSD_SYSTEMID_LEN]);
>>
>> Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
>> ---
>>  drivers/scsi/osd/osd_uld.c   |   63 ++++++++++++++++++++++++++++++++++++++++++
>>  include/scsi/osd_initiator.h |    4 ++
>>  2 files changed, 67 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
>> index f6f9a99..cd4ca7c 100644
>> --- a/drivers/scsi/osd/osd_uld.c
>> +++ b/drivers/scsi/osd/osd_uld.c
>> @@ -173,6 +173,69 @@ static const struct file_operations osd_fops = {
>>  	.unlocked_ioctl = osd_uld_ioctl,
>>  };
>>  
>> +struct osd_dev *osduld_path_lookup(const char *path)
> 
> Is there no other way to do this?  A kernel component opening another
> kernel component by device path is generally frowned upon.
> 
> The way it should work is to have a user space process initiate
> everything because it can see the full device space and cope with the
> problems that may occur on first open in user space.
> 

Thank you for asking, this is something I was pondering on for a long
time.

I have based this work on the block-devices model and the way filesystems
mount a block device. In fact I have started with lookup_bdev() as reference
and only changed it slightly to match char-devices. I have looked in other
parts of the kernel on what do the few "FSs over char-dev" do, (there are a few)
and they all invent their own none-standard way of mount-options to denote a device
to load. While the actual mount-path is unused/empty. I thought it is much more
natural to the user of the mount command to just give the device path, just as if
it is a block-device. The way I see it, which was triggered by a lot of what you said,
an OSD device is just an advanced-API storage-device and all the rest of the stuff
should be as natural as possible.

That said, I'm very open to suggestions. What would be a better/more standard way
for an OSD based filesystem to look up it's devices, that could be easily denoted
by the mount command? 

[Please note that with above solution, contrary to all other solutions I've seen
except block-dev of course, I do not keep any list of OSD devices anywhere. The
vfs /dev/ directory does that for us. This, I would say, is a nice advantage no
duplicate lists]

However I have a question. I'm CCing fsdevel maybe someone there could help.
Please see below, at the exact code that fails.

>> +{
>> +	struct nameidata nd;
>> +	struct inode *inode;
>> +	struct cdev *cdev;
>> +	struct osd_uld_device *uninitialized_var(oud);
>> +	int error;
>> +
>> +	if (!path || !*path) {
>> +		OSD_ERR("Mount with !path || !*path\n");
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	error = path_lookup(path, LOOKUP_FOLLOW, &nd);
>> +	if (error) {
>> +		OSD_ERR("path_lookup of %s faild=>%d\n", path, error);
>> +		return ERR_PTR(error);
>> +	}
>> +
>> +	inode = nd.path.dentry->d_inode;
>> +	error = -EINVAL; /* Not the right device e.g osd_uld_device */
>> +	if (!S_ISCHR(inode->i_mode)) {
>> +		OSD_DEBUG("!S_ISCHR()\n");
>> +		goto out;
>> +	}
>> +
>> +	cdev = inode->i_cdev;
>> +	if (!cdev) {
>> +		OSD_ERR("Before mounting an OSD Based filesystem\n");
>> +		OSD_ERR("  user-mode must open+close the %s device\n", path);
>> +		OSD_ERR("  Example: bash: echo < %s\n", path);
>> +		goto out;
>> +	}

Here at this point, as it says by the error message, if I do not open the
device at least once in the life time of the char-device the check fails.
The device-inode is only half baked. My mount script just does a fast open+close
before it mounts exofs. Couple of questions:
* Is there something I can trigger from Kernel prior to the path_lookup() call
  that will force the inode binding to the char-device. Just like user-mode open
  does.
* How is lookup_bdev() different then what I do, in that it does not have that open/close
  problem?

>> +
>> +	/* The Magic wand. Is it our char-dev */
>> +	/* TODO: Support sg devices */
>> +	if (cdev->owner != THIS_MODULE) {
>> +		OSD_ERR("Error mounting %s - is not an OSD device\n", path);
>> +		goto out;
>> +	}
>> +
>> +	oud = container_of(cdev, struct osd_uld_device, cdev);
>> +
>> +	__uld_get(oud);
>> +	error = 0;
>> +
>> +out:
>> +	path_put(&nd.path);
>> +	return error ? ERR_PTR(error) : &oud->od;
>> +}
>> +EXPORT_SYMBOL(osduld_path_lookup);
>> +
>> +void osduld_put_device(struct osd_dev *od)
>> +{
>> +	if (od) {
>> +		struct osd_uld_device *oud = container_of(od,
>> +						struct osd_uld_device, od);
>> +
>> +		__uld_put(oud);
>> +	}
>> +}
>> +EXPORT_SYMBOL(osduld_put_device);
>> +
>>  /*
>>   * Scsi Device operations
>>   */
>> diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
>> index a5dbbdd..e84dc7a 100644
>> --- a/include/scsi/osd_initiator.h
>> +++ b/include/scsi/osd_initiator.h
>> @@ -33,6 +33,10 @@ struct osd_dev {
>>  	unsigned def_timeout;
>>  };
>>  
>> +/* Retrieve/return osd_dev(s) for use by Kernel clients */
>> +struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/
>> +void osduld_put_device(struct osd_dev *od);
>> +
>>  /* Add/remove test ioctls from external modules */
>>  typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
>>  int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
>> -- 

Thanks for reviewing
Boaz

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 13/16] libosd: SCSI/OSD Sense decoding support
  2009-01-29 10:19     ` Boaz Harrosh
@ 2009-01-29 15:00       ` James Bottomley
  2009-01-29 16:33         ` Boaz Harrosh
  0 siblings, 1 reply; 23+ messages in thread
From: James Bottomley @ 2009-01-29 15:00 UTC (permalink / raw)
  To: Boaz Harrosh; +Cc: Andrew Morton, linux-scsi, open-osd ml

On Thu, 2009-01-29 at 12:19 +0200, Boaz Harrosh wrote:
> James Bottomley wrote:
> > On Sun, 2009-01-25 at 17:15 +0200, Boaz Harrosh wrote:
> >>  
> >> +# CONFIG_SCSI_OSD_DPRINT_SENSE =
> >> +#	0 - no print of errors
> >> +#	1 - print errors
> >> +#	2 - errors + warrnings
> >> +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1
> > 
> > Why are these all defines not Kconfig variables?
> > 
> 
> They are a "Kconfig variables". What you see above is a section of the 
> Kbuild file that's for the out-of-tree compilation. [ifneq ($(OSD_INC),)]
> For the out-of-tree compilation the Kbuild file defines everything as
> configured in.

OK, let me rephrase the question "what's a file designed for out of tree
compiles doing in-tree?".

> <snip>
> diff --git a/include/scsi/osd_sense.h b/include/scsi/osd_sense.h
> >> new file mode 100644
> >> index 0000000..ff9b33c
> >> --- /dev/null
> >> +++ b/include/scsi/osd_sense.h
> >> @@ -0,0 +1,260 @@
> >> +/*
> >> + * osd_sense.h - OSD Related sense handling definitions.
> >> + *
> >> + * Copyright (C) 2008 Panasas Inc.  All rights reserved.
> >> + *
> >> + * Authors:
> >> + *   Boaz Harrosh <bharrosh@panasas.com>
> >> + *   Benny Halevy <bhalevy@panasas.com>
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License version 2
> >> + *
> >> + * This file contains types and constants that are defined by the protocol
> >> + * Note: All names and symbols are taken from the OSD standard's text.
> >> + */
> >> +#ifndef __OSD_SENSE_H__
> >> +#define __OSD_SENSE_H__
> >> 
> <snip>
> >> +	scsi_sense_Reserved_first		= 0x0A,
> >> +	scsi_sense_Reserved_last		= 0x7F,
> >> +	scsi_sense_Vendor_specific_first	= 0x80,
> >> +	scsi_sense_Vendor_specific_last		= 0xFF,
> >> +};
> >> +
> >> +struct scsi_sense_descriptor { /* for picking into desc type */
> >> +	u8	descriptor_type; /* one of enum scsi_descriptor_types */
> >> +	u8	additional_length; /* n - 1 */
> >> +	u8	data[];
> >> +} __packed;
> > 
> > Why is it necessary to do a complete duplication of all the sense header
> > handling and print out in include/scsi/scsi_eh.h and
> > drivers/scsi/constants.c ... can't these two frameworks be integrated?
> > 
> 
> I have tried. 
> Some of this stuff is new and exclusive to OSD so the file is needed.
> The rest is buried in constants.c while I need them in an header file.
> If it is accepted by you to take some of constants.c and put them in an
> header then, sure I can do that. Refactor some of above stuff and constants.c
> stuff into an scsi_sense.h file and use them at both places.
> (I will send an RFC after things settle a bit)

That's what I'd prefer to see, yes.  The linux tradition is that if a
particular piece of code, which was designed for use in X could be used
in Y, we don't duplicate it for Y, we redesign it so it can be used in
both X and Y ... that's how we keep the kernel clean and neat.   Of
course, if you're really lucky, the X user already figured out a more
generic framework and it's a simple matter to reuse it.  I'm afraid it's
a bit more work in this case.

> Other then that, the source of the osd_req_decode_sense() is totally new to
> osd. An osd target returns very detailed, variable length, sense information
> that denotes exactly what field of the CDB and/or buffer-data failed it's checks
> as well as details on other failures and conditions. Also later we will support
> security signatures of sense data.

But this is all just an extension of the basic SAM defined sense format.

James



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 13/16] libosd: SCSI/OSD Sense decoding support
  2009-01-29 15:00       ` James Bottomley
@ 2009-01-29 16:33         ` Boaz Harrosh
  0 siblings, 0 replies; 23+ messages in thread
From: Boaz Harrosh @ 2009-01-29 16:33 UTC (permalink / raw)
  To: James Bottomley; +Cc: Andrew Morton, linux-scsi, open-osd ml

James Bottomley wrote:
> On Thu, 2009-01-29 at 12:19 +0200, Boaz Harrosh wrote:
>> James Bottomley wrote:
>>> On Sun, 2009-01-25 at 17:15 +0200, Boaz Harrosh wrote:
>>>>  
>>>> +# CONFIG_SCSI_OSD_DPRINT_SENSE =
>>>> +#	0 - no print of errors
>>>> +#	1 - print errors
>>>> +#	2 - errors + warrnings
>>>> +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1
>>> Why are these all defines not Kconfig variables?
>>>
>> They are a "Kconfig variables". What you see above is a section of the 
>> Kbuild file that's for the out-of-tree compilation. [ifneq ($(OSD_INC),)]
>> For the out-of-tree compilation the Kbuild file defines everything as
>> configured in.
> 
> OK, let me rephrase the question "what's a file designed for out of tree
> compiles doing in-tree?".
> 

Sorry for not explaining better.
The Kbuild file is an in-tree file for sure. It is what builds the
drivers/scsi/osd directory. (The Makefile in that subdir is only for
out-of-tree and is not included in the patchset)

Now places in the source-code and in Kbuild itself depend on Kconfig
doing it's thing. But when the same-exact source is compiled out-of-tree,
possibly against a Kernel that does not have OSD at all, the Kconfigure
is emulated (above).

I have chosen to do that rather then keep two sets of files like other
projects do. Because I have one master git-tree. The in-tree has the
out-of-tree git as a remote. With an automatic script I rebase the out-of-tree
patches onto the relevant in-tree branch. This way I have only one master
repository.

All this is done by a small ifneq(,)/endif in Kbuild file. The rest is
totally transparent to source-code or otherwise.

Please let me keep it. If not I will need to patch Kbuild from out-of-tree
branches which is also in the in-tree branches. This will make it hard to
maintain in future versions without causing merge conflicts. I would like to
keep all individual files identical in the two views and keep the difference
in separate files.

Thanks in advance

>> <snip>
>> diff --git a/include/scsi/osd_sense.h b/include/scsi/osd_sense.h
>>>> new file mode 100644
>>>> index 0000000..ff9b33c
>>>> --- /dev/null
>>>> +++ b/include/scsi/osd_sense.h
>>>> @@ -0,0 +1,260 @@
>>>> +/*
>>>> + * osd_sense.h - OSD Related sense handling definitions.
>>>> + *
>>>> + * Copyright (C) 2008 Panasas Inc.  All rights reserved.
>>>> + *
>>>> + * Authors:
>>>> + *   Boaz Harrosh <bharrosh@panasas.com>
>>>> + *   Benny Halevy <bhalevy@panasas.com>
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2
>>>> + *
>>>> + * This file contains types and constants that are defined by the protocol
>>>> + * Note: All names and symbols are taken from the OSD standard's text.
>>>> + */
>>>> +#ifndef __OSD_SENSE_H__
>>>> +#define __OSD_SENSE_H__
>>>>
>> <snip>
>>>> +	scsi_sense_Reserved_first		= 0x0A,
>>>> +	scsi_sense_Reserved_last		= 0x7F,
>>>> +	scsi_sense_Vendor_specific_first	= 0x80,
>>>> +	scsi_sense_Vendor_specific_last		= 0xFF,
>>>> +};
>>>> +
>>>> +struct scsi_sense_descriptor { /* for picking into desc type */
>>>> +	u8	descriptor_type; /* one of enum scsi_descriptor_types */
>>>> +	u8	additional_length; /* n - 1 */
>>>> +	u8	data[];
>>>> +} __packed;
>>> Why is it necessary to do a complete duplication of all the sense header
>>> handling and print out in include/scsi/scsi_eh.h and
>>> drivers/scsi/constants.c ... can't these two frameworks be integrated?
>>>
>> I have tried. 
>> Some of this stuff is new and exclusive to OSD so the file is needed.
>> The rest is buried in constants.c while I need them in an header file.
>> If it is accepted by you to take some of constants.c and put them in an
>> header then, sure I can do that. Refactor some of above stuff and constants.c
>> stuff into an scsi_sense.h file and use them at both places.
>> (I will send an RFC after things settle a bit)
> 
> That's what I'd prefer to see, yes.  The linux tradition is that if a
> particular piece of code, which was designed for use in X could be used
> in Y, we don't duplicate it for Y, we redesign it so it can be used in
> both X and Y ... that's how we keep the kernel clean and neat.   Of
> course, if you're really lucky, the X user already figured out a more
> generic framework and it's a simple matter to reuse it.  I'm afraid it's
> a bit more work in this case.
> 

Yes, it's more work. And I don't yet have a clear picture on how to do it
in a way that does not inject pointless code to the regular case where OSD
is not used. Let me think about it for a small while. I promise to get to it
ASAP.

>> Other then that, the source of the osd_req_decode_sense() is totally new to
>> osd. An osd target returns very detailed, variable length, sense information
>> that denotes exactly what field of the CDB and/or buffer-data failed it's checks
>> as well as details on other failures and conditions. Also later we will support
>> security signatures of sense data.
> 
> But this is all just an extension of the basic SAM defined sense format.
> 

Well yes and no - 
Other then in OSD, nowhere in scsi is there a variable length of sense information.
That is: in osd you can return an array of bad attributes or an array of bad objects.
Also there are OSD specific extensions that are defined in the osd T10 document only.
I will try to divide the common work from the OSD extensions and submit the common
part to generic layer but in a way that could be reused by both.

Please note that I'm not the first offender. There are other error handlers that
duplicate some of what is done here for their specific transports / command-sets.

> James
> 
> 

Thanks
Boaz

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2009-01-29 16:33 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-25 14:46 [PATCHSET 00/16] open-osd: OSD Initiator library for 2.6.30 Boaz Harrosh
2009-01-25 14:50 ` [PATCH 01/16] major.h: char-major number for OSD device driver Boaz Harrosh
2009-01-25 14:51 ` [PATCH 02/16] scsi: OSD_TYPE Boaz Harrosh
2009-01-25 14:54 ` [PATCH 03/16] libosd: OSDv1 Headers Boaz Harrosh
2009-01-25 14:55 ` [PATCH 04/16] libosd: OSDv1 preliminary implementation Boaz Harrosh
2009-01-25 14:56 ` [PATCH 05/16] osd_uld: OSD scsi ULD Boaz Harrosh
2009-01-25 14:58 ` [PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel Boaz Harrosh
2009-01-28 16:32   ` James Bottomley
2009-01-29 11:12     ` Boaz Harrosh
2009-01-25 14:59 ` [PATCH 07/16] libosd: attributes Support Boaz Harrosh
2009-01-25 15:03 ` [PATCH 08/16] libosd: OSD Security processing stubs Boaz Harrosh
2009-01-25 15:05 ` [PATCH 09/16] libosd: Add Flush and List-objects support Boaz Harrosh
2009-01-25 15:07 ` [PATCH 10/16] libosd: Not implemented commands Boaz Harrosh
2009-01-25 15:09 ` [PATCH 11/16] libosd: OSD version 2 Support Boaz Harrosh
2009-01-25 15:13 ` [PATCH 12/16] libosd: OSDv2 auto detection Boaz Harrosh
2009-01-25 15:15 ` [PATCH 13/16] libosd: SCSI/OSD Sense decoding support Boaz Harrosh
2009-01-28 16:32   ` James Bottomley
2009-01-29 10:19     ` Boaz Harrosh
2009-01-29 15:00       ` James Bottomley
2009-01-29 16:33         ` Boaz Harrosh
2009-01-25 15:21 ` [PATCH 14/16] osd: Documentation for OSD library Boaz Harrosh
2009-01-25 15:22 ` [PATCH 15/16] osd: Kconfig file for in-tree builds Boaz Harrosh
2009-01-25 15:24 ` [PATCH 16/16] scsi: Add osd library to build system Boaz Harrosh

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