2008-11-04 16:09:50

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCHSET 00/18] open-osd: OSD Initiator library for Linux


Please consider for inclusion, an in-kernel OSD initiator
library. Its main users are planned to be various OSD based file
systems and the pNFS-Objects Layout Driver. (To be submitted soon)

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

Or a compact out-of-tree repository that includes sources
and some extras:
git://git.open-osd.org/open-osd.git master
http://git.open-osd.org/gitweb.cgi?p=open-osd.git;a=summary

The submitted patches add public header files to include/scsi/
for use by other subsystems. The source files and private headers
are put at a new drivers/scsi/osd/ directory, with the privilege of
a separate Makefile and Kconfig.

here is the list of patches:

[PATCH 01/18] major.h: char-major number for OSD device driver
A request for a new char-device major number

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

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

[PATCH 05/18] osd_uld: OSD scsi ULD
[PATCH 06/18] osd_uld: API for retrieving osd devices from Kernel
[PATCH 07/18] osd_test: User-mode application to run the OSD tests
[PATCH 08/18] osd_ktests: Add basic OSD tests
These patches add a scsi ULD for OSD type devices. Please see
commit logs for details.

[PATCH 09/18] libosd: attributes Support
[PATCH 10/18] osd_ktests: Test Attribute lists
[PATCH 11/18] libosd: OSD Security processing stubs
[PATCH 12/18] libosd: Add Flush and List-objects support
[PATCH 13/18] libosd: Not implemented commands
[PATCH 14/18] libosd: OSD version 2 Support
[PATCH 15/18] libosd: OSDv2 auto detection
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, so it was never tested.
And the absence of any OSD-security methods other then NO_SECURITY.
These will come in future versions.

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

[PATCH 17/18] osd: Kconfig file for in-tree builds
[PATCH 18/18] 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 if
Invoked out-of-tree style with the -M switch. (see out-of-tree URL for how)

We would like this to sit in -mm tree for a while to make sure it is compilable
on all platform. We don't see any danger of it being included in the next Kernel
as it will not break anything. Of course, given that we have addressed everyone's
comments, at this round.

What's new/changed since the last RFC:
Mainly work has been done to address James comments about the ULD.
See http://archive.netbsd.se/?ml=linux-scsi&a=2008-07&m=8051556
I hope I've nailed down all possible problems in the reference
counting / locking of both the osd_uld_device structure , and the MODULE.
Also a new API was devised for in-kernel users to query for osd devices.
See: "[PATCH 06/18] osd_uld: API for retrieving osd devices from Kernel"
for further discussion on this subject.
Also the development and support of osdfs, submitted as RFC last week, was
a good test bed for stability and usability. So there were a few fixes and
cleanups do to that effort.

All-in-all I'm very confident in this work and feel it can serve as a good
base for OSD work in the Linux Kernel. We welcome anyone to please try this
SW, test it, break it to pieces, and please tell us about your experience.

Thanks
Boaz


2008-11-04 16:43:59

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 02/18] scsi: OSD_TYPE

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

Signed-off-by: Boaz Harrosh <[email protected]>
---
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 b14dc02..633cb87 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -783,6 +783,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

2008-11-04 16:45:53

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 03/18] libosd: OSDv1 Headers

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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
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..24a70b7
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 <linux/blkdev.h>
+
+#include "osd_protocol.h"
+#include "osd_types.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_dev;
+ unsigned def_timeout;
+};
+
+void osd_dev_init(struct osd_dev *, struct scsi_device *scsi_dev);
+void osd_dev_fini(struct osd_dev *);
+
+struct osd_request;
+typedef void (osd_req_done_fn)(struct osd_request *, void *);
+
+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 not allocated by us */
+ 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 *, 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
+ * the 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 - submits the request for execution through
+ * the block-layer without waitting.
+ * @or: - osd_request to Executed
+ * @done: (Optional) - Called at end of execution
+ * @private: - Will be passes to @done function
+ *
+ * Calls blk_execute_rq_nowait to q the command. When execution is done
+ * Optionally calles @done with @private as parameter. or->async_error has 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 *, ...);/* NI */
+void osd_req_set_master_key(struct osd_request *, ...);/* NI */
+
+void osd_req_format(struct osd_request *, 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 *,
+ osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem);
+
+void osd_req_flush_obsd(struct osd_request *,
+ enum osd_options_flush_scope_values);
+
+void osd_req_perform_scsi_command(struct osd_request *,
+ const u8 *cdb, ...);/* NI */
+void osd_req_task_management(struct osd_request *, ...);/* NI */
+
+/*
+ * Partition commands
+ */
+void osd_req_create_partition(struct osd_request *, osd_id partition);
+void osd_req_remove_partition(struct osd_request *, osd_id partition);
+
+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]);/* 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 *,
+ 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 *,
+ osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
+ unsigned nelem);
+
+void osd_req_flush_partition(struct osd_request *,
+ osd_id partition, enum osd_options_flush_scope_values);
+
+/*
+ * Collection commands
+ */
+void osd_req_create_collection(struct osd_request *,
+ const struct osd_obj_id *);/* NI */
+void osd_req_remove_collection(struct osd_request *,
+ const struct osd_obj_id *);/* NI */
+
+/* list all objects in the collection */
+int osd_req_list_collection_objects(struct osd_request *,
+ 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 *, ...);/* NI */
+
+void osd_req_flush_collection(struct osd_request *,
+ const struct osd_obj_id *, enum osd_options_flush_scope_values);
+
+void osd_req_get_member_attrs(struct osd_request *, ...);/* V2-only NI */
+void osd_req_set_member_attrs(struct osd_request *, ...);/* V2-only NI */
+
+/*
+ * Object commands
+ */
+void osd_req_create_object(struct osd_request *, struct osd_obj_id *);
+void osd_req_remove_object(struct osd_request *, struct osd_obj_id *);
+
+void osd_req_write(struct osd_request *,
+ const struct osd_obj_id *, struct bio *data_out, u64 offset);
+void osd_req_append(struct osd_request *,
+ const struct osd_obj_id *, struct bio *data_out);/* NI */
+void osd_req_create_write(struct osd_request *,
+ const struct osd_obj_id *, struct bio *data_out, u64 offset);/* NI */
+void osd_req_clear(struct osd_request *,
+ const struct osd_obj_id *, u64 offset, u64 len);/* NI */
+void osd_req_punch(struct osd_request *,
+ const struct osd_obj_id *, u64 offset, u64 len);/* V2-only NI */
+
+void osd_req_flush_object(struct osd_request *,
+ const struct osd_obj_id *, enum osd_options_flush_scope_values,
+ /*V2*/ u64 offset, /*V2*/ u64 len);
+
+void osd_req_read(struct osd_request *,
+ 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 *, const struct osd_obj_id *);
+
+/* set before get */
+void osd_req_set_attributes(struct osd_request *, 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 *,
+ const struct osd_attr *, unsigned nelem);
+
+/* get a list of attributes */
+int osd_req_add_get_attr_list(struct osd_request *,
+ 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 *,
+ 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 *,
+ 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..77a74a3
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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;
+ } __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;
+ } __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[80-62];
+ } __packed attrs_cdb;
+/*52*/ u8 get_set_attributes_parameters[80-52];
+ };
+} __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 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 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 [email protected] */
+} __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 = (1 << 0),
+ OSD_SEC_CAP_OBJ_MGMT = (1 << 1),
+ OSD_SEC_CAP_REMOVE = (1 << 2),
+ OSD_SEC_CAP_CREATE = (1 << 3),
+ OSD_SEC_CAP_SET_ATTR = (1 << 4),
+ OSD_SEC_CAP_GET_ATTR = (1 << 5),
+ OSD_SEC_CAP_WRITE = (1 << 6),
+ OSD_SEC_CAP_READ = (1 << 7),
+
+ OSD_SEC_CAP_NONE1 = (1 << 8),
+ OSD_SEC_CAP_NONE2 = (1 << 9),
+ OSD_SEC_CAP_NONE3 = (1 << 10),
+ OSD_SEC_CAP_QUERY = (1 << 11), /*v2 only*/
+ OSD_SEC_CAP_M_OBJECT = (1 << 12), /*v2 only*/
+ OSD_SEC_CAP_POL_SEC = (1 << 13),
+ OSD_SEC_CAP_GLOBAL = (1 << 14),
+ OSD_SEC_CAP_DEV_MGMT = (1 << 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[30-10];
+/*30*/ u8 discriminator[42-30];
+/*42*/ struct osd_timestamp object_created_time;
+/*48*/ u8 object_type;
+ u8 permissions_bit_mask[54-49];
+/*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;
+
+ u8 object_descriptor[80-56];/*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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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..ea5372d
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 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

2008-11-04 16:46:36

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 04/18] libosd: OSDv1 preliminary implementation

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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
drivers/scsi/osd/Kbuild | 26 +++
drivers/scsi/osd/Makefile | 37 +++
drivers/scsi/osd/osd_debug.h | 27 +++
drivers/scsi/osd/osd_initiator.c | 450 ++++++++++++++++++++++++++++++++++++++
4 files changed, 540 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..b4678e0
--- /dev/null
+++ b/drivers/scsi/osd/Kbuild
@@ -0,0 +1,26 @@
+#
+# Kbuild for the OSD modules
+#
+# Copyright (C) 2008 Panasas Inc. All rights reserved.
+#
+# Authors:
+# Boaz Harrosh <[email protected]>
+# Benny Halevy <[email protected]>
+#
+# 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
+EXTRA_CFLAGS += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
+
+EXTRA_CFLAGS += -I$(OSD_INC)
+# EXTRA_CFLAGS += -DCONFIG_SCSI_OSD_DEBUG
+
+endif
+
+libosd-objs := 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 <[email protected]>
+# Benny Halevy <[email protected]>
+#
+# 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..0bc65fa
--- /dev/null
+++ b/drivers/scsi/osd/osd_debug.h
@@ -0,0 +1,27 @@
+/*
+ * osd_debug.h - Some kprintf macros
+ *
+ * Copyright (C) 2008 Panasas Inc. All rights reserved.
+ *
+ * Authors:
+ * Boaz Harrosh <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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
+
+#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..33450b8
--- /dev/null
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -0,0 +1,450 @@
+/*
+ * 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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 };
+
+#ifdef CONFIG_SCSI_OSD_INITIATOR_MODULE
+MODULE_AUTHOR("Boaz Harrosh <[email protected]>");
+MODULE_DESCRIPTION("open-osd initiator library libosd.ko");
+MODULE_LICENSE("GPL");
+#endif
+
+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_dev)
+{
+ memset(osdd, 0, sizeof(*osdd));
+ osdd->scsi_dev = scsi_dev;
+ 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_dev = NULL;
+}
+EXPORT_SYMBOL(osd_dev_fini);
+
+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;
+}
+
+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 &= __constant_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_dev = or->osd_dev->scsi_dev;
+ struct request_queue *q = scsi_dev->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",
+ 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",
+ 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

2008-11-04 16:47:12

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 17/18] osd: Kconfig file for in-tree builds

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

Signed-off-by: Boaz Harrosh <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
drivers/scsi/osd/Kconfig | 41 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 41 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..ac3be8a
--- /dev/null
+++ b/drivers/scsi/osd/Kconfig
@@ -0,0 +1,41 @@
+#
+# Kernel configuration file for the OSD scsi protocol
+#
+# Copyright (C) 2008 Panasas Inc. All rights reserved.
+#
+# Authors:
+# Boaz Harrosh <[email protected]>
+# Benny Halevy <[email protected]>
+#
+# 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 osdfs, for mounting an OSD based file system.
+
+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).
--
1.6.0.1

2008-11-04 16:47:48

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 14/18] libosd: OSD version 2 Support

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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
drivers/scsi/osd/osd_initiator.c | 94 ++++++++++++++++++++++++++++++++------
include/scsi/osd_initiator.h | 39 ++++++++++++++++
include/scsi/osd_protocol.h | 86 +++++++++++++++++++++++++++++++++--
3 files changed, 201 insertions(+), 18 deletions(-)

diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 567a2c6..9127fc4 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -57,36 +57,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,
@@ -95,10 +109,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;
}
}

@@ -108,15 +126,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 *
@@ -124,7 +149,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_dev)
@@ -132,6 +160,9 @@ void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_dev)
memset(osdd, 0, sizeof(*osdd));
osdd->scsi_dev = scsi_dev;
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);
@@ -332,10 +363,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);
}

/*
@@ -544,6 +595,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);
}
@@ -1166,6 +1223,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)
{
@@ -1207,9 +1268,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)
diff --git a/include/scsi/osd_initiator.h b/include/scsi/osd_initiator.h
index 0004df1..738312f 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_dev;
unsigned def_timeout;
+
+#ifdef OSD_VER1_SUPPORT
+ enum osd_std_version version;
+#endif
};

/* Retrieve/return osd_dev(s) for use by Kernel clients */
@@ -41,6 +62,14 @@ void osduld_put_device(struct osd_dev *od);
void osd_dev_init(struct osd_dev *, struct scsi_device *scsi_dev);
void osd_dev_fini(struct osd_dev *);

+/* we might want to use function vector in the future */
+static inline void osd_dev_set_ver(struct osd_dev *dev, enum osd_std_version v)
+{
+#ifdef OSD_VER1_SUPPORT
+ dev->version = v;
+#endif
+}
+
struct osd_request;
typedef void (osd_req_done_fn)(struct osd_request *, void *);

@@ -77,6 +106,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 77a74a3..ef7505e 100644
--- a/include/scsi/osd_protocol.h
+++ b/include/scsi/osd_protocol.h
@@ -25,9 +25,12 @@ 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,
@@ -108,6 +111,7 @@ enum {
OSD_OFFSET_MAX_BITS = 28,

OSDv1_OFFSET_MIN_SHIFT = 8,
+ OSD_OFFSET_MIN_SHIFT = 3,
OSD_OFFSET_MAX_SHIFT = 16,
};

@@ -129,6 +133,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 +158,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 +203,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 +211,7 @@ struct osd_security_parameters {
/*196*/osd_cdb_offset data_out_integrity_check_offset;
} __packed;
/*200 v1*/
+/*224 v2*/

struct osdv1_cdb {
struct osd_cdb_head h;
@@ -196,9 +219,16 @@ 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;
+} __packed;
+
struct osd_cdb {
union {
struct osdv1_cdb v1;
+ struct osdv2_cdb v2;
u8 buff[OSD_TOTAL_CDB_LEN];
};
} __packed;
@@ -269,6 +299,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 page;
@@ -279,6 +310,7 @@ struct osd_attributes_list_element {

enum {
OSDv1_ATTRIBUTES_ELEM_ALIGN = 1,
+ OSD_ATTRIBUTES_ELEM_ALIGN = 8,
};

enum {
@@ -292,6 +324,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 +364,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 +522,36 @@ struct osdv1_cap_object_descriptor {
} __packed;
/*80 v1*/

-struct osd_capability {
+/*56 v2*/
+struct osd_cap_object_descriptor {
+ union {
+ struct {
+ __be32 allowed_attributes_access;
+/*60*/ __be32 policy_access_tag;
+/*64*/ __be16 boot_epoch;
+/*66*/ u8 reserved[72-66];
+/*72*/ __be64 allowed_partition_id;
+/*80*/ __be64 allowed_object_id;
+/*88*/ __be64 allowed_range_length;
+/*96*/ __be64 allowed_range_start;
+ } __packed obj_desc;
+
+ u8 object_descriptor[104-56]; /*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

2008-11-04 16:47:32

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 18/18] scsi: Add osd library to build system

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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
MAINTAINERS | 10 ++++++++++
drivers/scsi/Kconfig | 2 ++
drivers/scsi/Makefile | 2 ++
3 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 355c192..03da1e7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3153,6 +3153,16 @@ L: [email protected]
W: http://www.nongnu.org/orinoco/
S: Maintained

+OSD LIBRARY
+P: Boaz Harrosh
+M: [email protected]
+P: Benny Halevy
+M: [email protected]
+L: [email protected]
+W: http://open-osd.org
+T: git://git.open-osd.org/osd-lib.git
+S: Maintained
+
P54 WIRELESS DRIVER
P: Michael Wu
M: [email protected]
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 403ecad..e6af21c 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1780,4 +1780,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 72fd504..1e49632 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -135,6 +135,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

2008-11-04 16:48:49

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 11/18] libosd: OSD Security processing stubs

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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
drivers/scsi/osd/osd_initiator.c | 85 ++++++++++++++++++++++++++++++++++++++
1 files changed, 85 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index da0c53c..2ed0429 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -109,6 +109,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_dev)
{
memset(osdd, 0, sizeof(*osdd));
@@ -796,6 +804,64 @@ int _osd_req_finalize_attr_page(struct osd_request *or)
return ret;
}

+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),
+ };
+ int 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),
+ };
+ int 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
*/
@@ -916,6 +982,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);

@@ -981,6 +1053,19 @@ 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)
+{
+ return false;
+}
+
+void osd_sec_sign_cdb(struct osd_cdb *ocdb, const u8 *cap_key)
+{
+}
+
+void osd_sec_sign_data(void *data_integ, struct bio *bio, const u8 *cap_key)
+{
+}
+
/*
* Declared in osd_protocol.h
* 4.12.5 Data-In and Data-Out buffer offsets
--
1.6.0.1

2008-11-04 16:48:33

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 15/18] libosd: OSDv2 auto detection

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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
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 9127fc4..8e59cdc 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"
@@ -61,6 +62,130 @@ 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)
+{
+ 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",
+ get_unaligned_be64(pFirst));
+
+ pFirst = get_attrs[a++].val_ptr;
+ OSD_INFO("OSD_ATTR_RI_USED_CAPACITY [0x%llx]\n",
+ get_unaligned_be64(pFirst));
+
+ pFirst = get_attrs[a++].val_ptr;
+ OSD_INFO("OSD_ATTR_RI_NUMBER_OF_PARTITIONS [%lld]\n",
+ 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 */
+ int len = get_attrs[a].len;
+ u8 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 1ce5eba..0f2bea7 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -201,6 +201,7 @@ EXPORT_SYMBOL(osduld_put_device);
static int __detect_osd(struct osd_uld_device *oud)
{
struct scsi_device *scsi_dev = oud->od.scsi_dev;
+ char caps[OSD_CAP_LEN];
int error;

/* sending a test_unit_ready as first command seems to be needed
@@ -212,6 +213,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 738312f..4fd5099 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -62,6 +62,9 @@ void osduld_put_device(struct osd_dev *od);
void osd_dev_init(struct osd_dev *, struct scsi_device *scsi_dev);
void osd_dev_fini(struct osd_dev *);

+/* some hi level device operations */
+int osd_auto_detect_ver(struct osd_dev *, void *caps); /* GFP_KERNEL */
+
/* we might want to use function vector in the future */
static inline void osd_dev_set_ver(struct osd_dev *dev, enum osd_std_version v)
{
--
1.6.0.1

2008-11-04 16:48:05

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 07/18] osd_test: User-mode application to run the OSD tests

Most simple user-app to invoke the in-kernel test ioctl of the
specified osd device.

Usage: osd_test "/dev/osdX"

Where /dev/osdX is the osd device (lun) to run tests on. The output
of the tests is in dmesg log file

Signed-off-by: Boaz Harrosh <[email protected]>
---
drivers/scsi/osd/Makefile | 10 +++++-
drivers/scsi/osd/osd_test.c | 74 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+), 2 deletions(-)
create mode 100644 drivers/scsi/osd/osd_test.c

diff --git a/drivers/scsi/osd/Makefile b/drivers/scsi/osd/Makefile
index d905344..92d8b19 100755
--- a/drivers/scsi/osd/Makefile
+++ b/drivers/scsi/osd/Makefile
@@ -28,10 +28,16 @@ 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
+all: libosd osd_test

libosd: ;
$(KBUILD_BASE) OSD_INC=$(OSD_INC) modules

-clean:
+clean: osd_test_clean
$(KBUILD_BASE) clean
+
+osd_test: osd_test.o
+ $(CC) -o $@ $<
+
+osd_test_clean:
+ rm -vf osd_test
diff --git a/drivers/scsi/osd/osd_test.c b/drivers/scsi/osd/osd_test.c
new file mode 100644
index 0000000..dc74865
--- /dev/null
+++ b/drivers/scsi/osd/osd_test.c
@@ -0,0 +1,74 @@
+/*
+ * osd_test.c - A user-mode program that calls into the osd ULD
+ *
+ * Copyright (C) 2008 Panasas Inc. All rights reserved.
+ *
+ * Authors:
+ * Boaz Harrosh <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+#include "osd_ktests.h"
+
+void usage(void)
+{
+ printf("usage: osd_test /dev/osdX testNo\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int osd_file, ret;
+
+ if (argc <= 1) {
+ usage();
+ return -2;
+ }
+
+ osd_file = open(argv[1], O_RDWR);
+ if (osd_file < 0) {
+ printf("Error opening <%s>\n", argv[1]);
+ return -3;
+ }
+
+ ret = ioctl(osd_file, OSD_TEST_ALL, 0);
+ if (ret) {
+ printf("ioctl 17 returned %d\n", ret);
+ return ret;
+ }
+
+ close(osd_file);
+ return 0;
+}
--
1.6.0.1

2008-11-04 16:49:14

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 13/18] libosd: Not implemented commands

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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
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 23f7e95..567a2c6 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -341,6 +341,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,
@@ -371,6 +374,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
*/
@@ -397,6 +404,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)
@@ -462,6 +473,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)
@@ -471,6 +487,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)
{
@@ -479,6 +497,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
*/
@@ -494,6 +515,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)
{
@@ -505,6 +531,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

2008-11-04 16:49:50

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 12/18] libosd: Add Flush and List-objects support

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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
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 2ed0429..23f7e95 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -102,6 +102,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)
{
@@ -338,6 +348,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
*/
@@ -364,6 +397,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_dev->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
*/
@@ -390,6 +505,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

2008-11-04 16:49:32

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 05/18] osd_uld: OSD scsi ULD

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-rc3).

A single ioctl is currently supported that will invoke an in-kernel
test on the specified OSD device (lun).

Signed-off-by: Boaz Harrosh <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
drivers/scsi/osd/Kbuild | 7 +
drivers/scsi/osd/osd_ktests.h | 27 +++
drivers/scsi/osd/osd_uld.c | 388 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 422 insertions(+), 0 deletions(-)
create mode 100644 drivers/scsi/osd/osd_ktests.h
create mode 100644 drivers/scsi/osd/osd_uld.c

diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild
index b4678e0..f39f82f 100644
--- a/drivers/scsi/osd/Kbuild
+++ b/drivers/scsi/osd/Kbuild
@@ -17,6 +17,9 @@ ifneq ($(OSD_INC),)
CONFIG_SCSI_OSD_INITIATOR=m
EXTRA_CFLAGS += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE

+CONFIG_SCSI_OSD_ULD=m
+EXTRA_CFLAGS += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE
+
EXTRA_CFLAGS += -I$(OSD_INC)
# EXTRA_CFLAGS += -DCONFIG_SCSI_OSD_DEBUG

@@ -24,3 +27,7 @@ endif

libosd-objs := osd_initiator.o
obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
+
+# osd.ko - SCSI ULD and char-device
+osd-objs := osd_uld.o
+obj-$(CONFIG_SCSI_OSD_ULD) += osd.o
diff --git a/drivers/scsi/osd/osd_ktests.h b/drivers/scsi/osd/osd_ktests.h
new file mode 100644
index 0000000..a9e5e00
--- /dev/null
+++ b/drivers/scsi/osd/osd_ktests.h
@@ -0,0 +1,27 @@
+/*
+ * osd_ktests.h - Define the ktests.c API
+ *
+ * Copyright (C) 2008 Panasas Inc. All rights reserved.
+ *
+ * Authors:
+ * Boaz Harrosh <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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_KTESTS_H__
+#define __OSD_KTESTS_H__
+
+/* Tests from osd_ktests.c */
+/* TODO: Only one simple test for now. Later I will add a test definition
+ * structure that will define what tests to preform and with some
+ * parametrization, so concurrent tests could be run on same OSD lun
+ * without stepping on each other. (E.g. Format called when other tests
+ * are in progress)
+ */
+
+enum { OSD_TEST_ALL = 17 };
+
+#endif /*ndef __OSD_KTESTS_H__*/
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
new file mode 100644
index 0000000..87b4540
--- /dev/null
+++ b/drivers/scsi/osd/osd_uld.c
@@ -0,0 +1,388 @@
+/*
+ * 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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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/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_ktests.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 <[email protected]>");
+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;
+}
+
+static long osd_uld_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct osd_uld_device *oud = file->private_data;
+ int ret;
+
+ switch (cmd) {
+ case OSD_TEST_ALL:
+ OSD_DEBUG("Kernel test %d: osd_uld_device=%p\n", cmd, oud);
+ ret = 0;
+ break;
+ default:
+ OSD_ERR("Unknown osd_uld_ioctl %d\n", cmd);
+ 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_dev = oud->od.scsi_dev;
+ 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_dev, scsi_dev->request_queue);
+ error = scsi_test_unit_ready(scsi_dev, 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_dev = to_scsi_device(dev);
+ struct gendisk *disk;
+ struct osd_uld_device *oud;
+ int minor;
+ int error;
+
+ if (scsi_dev->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_dev that will get released
+ * in __release, in case a logout is happening while fs is mounted
+ */
+ scsi_device_get(scsi_dev);
+ osd_dev_init(&oud->od, scsi_dev);
+
+ /* 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_dev->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_dev);
+ 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_dev = to_scsi_device(dev);
+ struct osd_uld_device *oud = dev_get_drvdata(dev);
+
+ if (!oud || (oud->od.scsi_dev != scsi_dev)) {
+ OSD_ERR("Half cooked osd-device %p,%p || %p!=%p",
+ dev, oud, oud ? oud->od.scsi_dev : NULL,
+ scsi_dev);
+ }
+
+ sysfs_remove_link(&oud->od.scsi_dev->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_dev = oud->od.scsi_dev;
+
+ /* now let delete the char_dev */
+ kobject_put(&oud->cdev.kobj);
+
+ osd_dev_fini(&oud->od);
+ scsi_device_put(scsi_dev);
+
+ 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);
--
1.6.0.1

2008-11-04 16:50:11

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 08/18] osd_ktests: Add basic OSD tests

Currently testing what is implemented in the osd_initiator library.
That is - format, create/remove partition, create/remove object,
read and write to objects.

This test passes against the IBM-OSD-SIM OSDv1 target.

Signed-off-by: Boaz Harrosh <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
drivers/scsi/osd/Kbuild | 2 +-
drivers/scsi/osd/osd_ktests.c | 331 +++++++++++++++++++++++++++++++++++++++++
drivers/scsi/osd/osd_ktests.h | 4 +
drivers/scsi/osd/osd_uld.c | 2 +-
4 files changed, 337 insertions(+), 2 deletions(-)
create mode 100644 drivers/scsi/osd/osd_ktests.c

diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild
index f39f82f..da00ddb 100644
--- a/drivers/scsi/osd/Kbuild
+++ b/drivers/scsi/osd/Kbuild
@@ -29,5 +29,5 @@ libosd-objs := osd_initiator.o
obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o

# osd.ko - SCSI ULD and char-device
-osd-objs := osd_uld.o
+osd-objs := osd_uld.o osd_ktests.o
obj-$(CONFIG_SCSI_OSD_ULD) += osd.o
diff --git a/drivers/scsi/osd/osd_ktests.c b/drivers/scsi/osd/osd_ktests.c
new file mode 100644
index 0000000..f620915
--- /dev/null
+++ b/drivers/scsi/osd/osd_ktests.c
@@ -0,0 +1,331 @@
+/*
+ * osd_ktests.c - An osd_initiator library in-kernel test suite
+ * called by the osd_uld module
+ *
+ * Copyright (C) 2008 Panasas Inc. All rights reserved.
+ *
+ * Authors:
+ * Boaz Harrosh <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 <asm/unaligned.h>
+#include <linux/vmalloc.h>
+#include <scsi/scsi_device.h>
+
+#include <scsi/osd_initiator.h>
+#include <scsi/osd_sec.h>
+
+#include "osd_ktests.h"
+#include "osd_debug.h"
+
+enum {
+ K = 1024,
+ M = 1024 * K,
+ G = 1024 * M,
+};
+
+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 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)
+{
+ int ret;
+
+ osd_sec_init_nosec_doall_caps(caps, obj, false, true);
+ ret = osd_finalize_request(or, 0, caps, NULL);
+ if (ret)
+ return ret;
+
+ ret = osd_execute_request(or);
+ /* osd_req_decode_sense(or, ret); */
+ 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__,\
+ __LINE__); \
+ return -ENOMEM; \
+ } \
+} while (0)
+
+#define KTEST_EXEC_END(or, obj, g_caps, msg) do { \
+ ret = test_exec(or, g_caps, obj); \
+ osd_end_request(or); \
+ if (ret) { \
+ OSD_ERR("Error executing "msg" => %d\n", ret); \
+ return ret; \
+ } \
+ OSD_DEBUG(msg "\n"); \
+} while (0)
+
+int ktest_format(struct osd_dev *osd_dev)
+{
+ struct osd_request *or;
+ u8 g_caps[OSD_CAP_LEN];
+ int ret;
+
+ KTEST_START_REQ(osd_dev, or);
+ osd_req_format(or, format_total_capacity);
+ KTEST_EXEC_END(or, &osd_root_object, g_caps, "format");
+ return 0;
+}
+
+int ktest_creat_par(struct osd_dev *osd_dev)
+{
+ struct osd_request *or;
+ u8 g_caps[OSD_CAP_LEN];
+ int ret;
+ int p;
+
+ for (p = 0; p < num_partitions; p++) {
+ struct osd_obj_id par = {
+ .partition = first_par_id + p,
+ .id = 0
+ };
+
+ KTEST_START_REQ(osd_dev, or);
+ osd_req_create_partition(or, par.partition);
+ KTEST_EXEC_END(or, &par, g_caps, "create_partition");
+ }
+
+ return 0;
+}
+
+int ktest_creat_obj(struct osd_dev *osd_dev)
+{
+ struct osd_request *or;
+ u8 g_caps[OSD_CAP_LEN];
+ int ret;
+ int p, o;
+
+ for (p = 0; p < num_partitions; p++)
+ for (o = 0; o < num_objects; o++) {
+ struct osd_obj_id obj = {
+ .partition = first_par_id + p,
+ .id = first_obj_id + o
+ };
+
+ KTEST_START_REQ(osd_dev, or);
+ osd_req_create_object(or, &obj);
+ KTEST_EXEC_END(or, &obj, g_caps, "create_object");
+ }
+
+ return 0;
+}
+
+int ktest_write_obj(struct osd_dev *osd_dev, void *write_buff)
+{
+ struct request_queue *req_q = osd_dev->scsi_dev->request_queue;
+ struct osd_request *or;
+ u8 g_caps[OSD_CAP_LEN];
+ int ret;
+ int p, o; u64 offset = 0;
+ struct bio *write_bio;
+
+ for (p = 0; p < num_partitions; p++)
+ for (o = 0; o < num_objects; o++) {
+ struct osd_obj_id obj = {
+ .partition = first_par_id + p,
+ .id = first_obj_id + o
+ };
+
+ KTEST_START_REQ(osd_dev, or);
+ write_bio = bio_map_kern(req_q, write_buff,
+ BUFF_SIZE, GFP_KERNEL);
+ if (!write_bio) {
+ OSD_ERR("!!! Failed to allocate write BIO\n");
+ return -ENOMEM;
+ }
+
+ osd_req_write(or, &obj, write_bio, offset);
+ KTEST_EXEC_END(or, &obj, g_caps, "write");
+ write_bio = NULL; /* released by scsi_midlayer */
+ offset += BUFF_SIZE;
+ }
+
+ return 0;
+}
+
+int ktest_read_obj(struct osd_dev *osd_dev, void *write_buff, void *read_buff)
+{
+ struct request_queue *req_q = osd_dev->scsi_dev->request_queue;
+ struct osd_request *or;
+ u8 g_caps[OSD_CAP_LEN];
+ int ret;
+ int p, o; u64 offset = 0;
+ struct bio *read_bio;
+
+ for (p = 0; p < num_partitions; p++)
+ for (o = 0; o < num_objects; o++) {
+ struct osd_obj_id obj = {
+ .partition = first_par_id + p,
+ .id = first_obj_id + o
+ };
+
+ KTEST_START_REQ(osd_dev, or);
+ read_bio = bio_map_kern(req_q, read_buff,
+ BUFF_SIZE, GFP_KERNEL);
+ if (!read_bio) {
+ OSD_ERR("!!! Failed to allocate read BIO\n");
+ return -ENOMEM;
+ }
+
+ osd_req_read(or, &obj, read_bio, offset);
+ 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");
+ offset += BUFF_SIZE;
+ }
+
+ return 0;
+}
+
+int ktest_remove_obj(struct osd_dev *osd_dev)
+{
+ struct osd_request *or;
+ u8 g_caps[OSD_CAP_LEN];
+ int ret;
+ int p, o;
+
+ for (p = 0; p < num_partitions; p++)
+ for (o = 0; o < num_objects; o++) {
+ struct osd_obj_id obj = {
+ .partition = first_par_id + p,
+ .id = first_obj_id + o
+ };
+
+ KTEST_START_REQ(osd_dev, or);
+ osd_req_remove_object(or, &obj);
+ KTEST_EXEC_END(or, &obj, g_caps, "remove_object");
+ }
+
+ return 0;
+}
+
+int ktest_remove_par(struct osd_dev *osd_dev)
+{
+ struct osd_request *or;
+ u8 g_caps[OSD_CAP_LEN];
+ int ret;
+ int p;
+
+ for (p = 0; p < num_partitions; p++) {
+ struct osd_obj_id par = {
+ .partition = first_par_id + p,
+ .id = 0
+ };
+
+ KTEST_START_REQ(osd_dev, or);
+ osd_req_remove_partition(or, par.partition);
+ KTEST_EXEC_END(or, &par, g_caps, "remove_partition");
+ }
+
+ return 0;
+}
+
+int do_test_17(struct osd_dev *od)
+{
+ void *write_buff = NULL;
+ void *read_buff = NULL;
+ int ret = -ENOMEM, i;
+
+/* osd_format */
+ if (ktest_format(od))
+ goto dev_fini;
+
+/* create some partition */
+ if (ktest_creat_par(od))
+ goto dev_fini;
+/* list partition see if they're all there */
+/* create some objects on some partitions */
+ if (ktest_creat_obj(od))
+ goto dev_fini;
+
+/* Alloc some buffers and bios */
+/* write_buff = kmalloc(BUFF_SIZE, or->alloc_flags);*/
+/* read_buff = kmalloc(BUFF_SIZE, or->alloc_flags);*/
+ write_buff = (void *)__get_free_page(GFP_KERNEL);
+ read_buff = (void *)__get_free_page(GFP_KERNEL);
+ if (!write_buff || !read_buff) {
+ OSD_ERR("!!! Failed to allocate memory for test\n");
+ goto dev_fini;
+ }
+ for (i = 0; i < BUFF_SIZE / 4; i++)
+ ((int *)write_buff)[i] = i;
+ OSD_DEBUG("allocate buffers\n");
+
+/* write to objects */
+ ret = ktest_write_obj(od, write_buff);
+ if (ret)
+ goto dev_fini;
+
+/* read from objects and compare to write */
+ ret = ktest_read_obj(od, write_buff, read_buff);
+ if (ret)
+ goto dev_fini;
+
+/* List all objects */
+
+/* Write with get_attr */
+/* Write with set_attr */
+/* Write with set_attr + get_attr */
+/* Read with set_attr */
+/* Read with get_attr */
+/* Read with get_attr + set_attr */
+/* remove objects */
+ ret = ktest_remove_obj(od);
+ if (ret)
+ goto dev_fini;
+
+/* remove partitions */
+ ret = ktest_remove_par(od);
+ if (ret)
+ goto dev_fini;
+
+/* good and done */
+ OSD_INFO("test17: All good and done\n");
+dev_fini:
+ if (read_buff)
+ free_page((ulong)read_buff);
+ if (write_buff)
+ free_page((ulong)write_buff);
+
+ return ret;
+}
diff --git a/drivers/scsi/osd/osd_ktests.h b/drivers/scsi/osd/osd_ktests.h
index a9e5e00..b625ee5 100644
--- a/drivers/scsi/osd/osd_ktests.h
+++ b/drivers/scsi/osd/osd_ktests.h
@@ -24,4 +24,8 @@

enum { OSD_TEST_ALL = 17 };

+#ifdef __KERNEL__
+extern int do_test_17(struct osd_dev *od);
+#endif /* __KERNEL__ */
+
#endif /*ndef __OSD_KTESTS_H__*/
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 0229301..1ce5eba 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -127,7 +127,7 @@ static long osd_uld_ioctl(struct file *file, unsigned int cmd,
switch (cmd) {
case OSD_TEST_ALL:
OSD_DEBUG("Kernel test %d: osd_uld_device=%p\n", cmd, oud);
- ret = 0;
+ ret = do_test_17(&oud->od);
break;
default:
OSD_ERR("Unknown osd_uld_ioctl %d\n", cmd);
--
1.6.0.1

2008-11-04 16:50:42

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 10/18] osd_ktests: Test Attribute lists

Add tests for setting/getting Attribute lists. All combinations
of read/write with set/get attributes are tested.
(6 possibilities), So all but data integrity request structure
layouts are attempted.

This test passes against the IBM-OSD-SIM OSDv1 target.

Signed-off-by: Boaz Harrosh <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
drivers/scsi/osd/osd_ktests.c | 110 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 110 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/osd/osd_ktests.c b/drivers/scsi/osd/osd_ktests.c
index f620915..f0a791f 100644
--- a/drivers/scsi/osd/osd_ktests.c
+++ b/drivers/scsi/osd/osd_ktests.c
@@ -43,6 +43,7 @@

#include <scsi/osd_initiator.h>
#include <scsi/osd_sec.h>
+#include <scsi/osd_attributes.h>

#include "osd_ktests.h"
#include "osd_debug.h"
@@ -260,6 +261,91 @@ int ktest_remove_par(struct osd_dev *osd_dev)
return 0;
}

+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_dev->request_queue;
+ struct osd_request *or;
+ char g_caps[OSD_CAP_LEN];
+ int ret;
+ struct bio *bio;
+ char *domsg;
+ /* set attrs */
+ static char name[] = "ktest_write_read_attr";
+ __be64 max_len = cpu_to_be64(0x80000000L);
+ struct osd_obj_id obj = {
+ .partition = first_par_id,
+ .id = first_obj_id,
+ };
+ struct osd_attr set_attrs[] = {
+ ATTR_SET(OSD_APAGE_OBJECT_QUOTAS, OSD_ATTR_OQ_MAXIMUM_LENGTH,
+ sizeof(max_len), &max_len),
+ ATTR_SET(OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_USERNAME,
+ sizeof(name), name),
+ };
+ struct osd_attr get_attrs[] = {
+ ATTR_DEF(OSD_APAGE_OBJECT_INFORMATION,
+ OSD_ATTR_OI_USED_CAPACITY, sizeof(__be64)),
+ ATTR_DEF(OSD_APAGE_OBJECT_INFORMATION,
+ OSD_ATTR_OI_LOGICAL_LENGTH, sizeof(__be64)),
+ };
+
+ KTEST_START_REQ(osd_dev, or);
+ bio = bio_map_kern(req_q, buff, BUFF_SIZE, GFP_KERNEL);
+ if (!bio) {
+ OSD_ERR("!!! Failed to allocate BIO\n");
+ return -ENOMEM;
+ }
+
+ if (doread) {
+ osd_req_read(or, &obj, bio, 0);
+ domsg = "Read-with-attr";
+ } else {
+ osd_req_write(or, &obj, bio, 0);
+ domsg = "Write-with-attr";
+ }
+
+ if (doset)
+ osd_req_add_set_attr_list(or, set_attrs, 2);
+ 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;
+ int nelem = 2;
+ u64 capacity_len = ~0;
+ u64 logical_len = ~0;
+
+ osd_req_decode_get_attr_list(or, get_attrs, &nelem, &iter);
+
+ /*FIXME: Std does not guaranty order of return attrs */
+ pFirst = get_attrs[0].val_ptr;
+ if (pFirst)
+ capacity_len = get_unaligned_be64(pFirst);
+ else
+ OSD_ERR("failed to read capacity_used\n");
+ pSec = get_attrs[1].val_ptr;
+ if (pSec)
+ logical_len = get_unaligned_be64(pSec);
+ else
+ OSD_ERR("failed to read logical_length\n");
+ OSD_INFO("%s capacity=%llu len=%llu\n",
+ domsg, capacity_len, logical_len);
+ }
+
+ osd_end_request(or);
+ if (ret) {
+ OSD_ERR("!!! Error executing %s => %d doset=%d doget=%d\n",
+ domsg, ret, doset, doget);
+ return ret;
+ }
+ OSD_DEBUG("%s\n", domsg);
+
+ return 0;
+}
+
int do_test_17(struct osd_dev *od)
{
void *write_buff = NULL;
@@ -304,11 +390,35 @@ int do_test_17(struct osd_dev *od)
/* List all objects */

/* Write with get_attr */
+ ret = ktest_write_read_attr(od, write_buff, false, false, true);
+ if (ret)
+ goto dev_fini;
+
/* Write with set_attr */
+ ret = ktest_write_read_attr(od, write_buff, false, true, false);
+ if (ret)
+ goto dev_fini;
+
/* Write with set_attr + get_attr */
+ ret = ktest_write_read_attr(od, write_buff, false, true, true);
+ if (ret)
+ goto dev_fini;
+
/* Read with set_attr */
+ ret = ktest_write_read_attr(od, write_buff, true, true, false);
+ if (ret)
+ goto dev_fini;
+
/* Read with get_attr */
+ ret = ktest_write_read_attr(od, write_buff, true, false, true);
+ if (ret)
+ goto dev_fini;
+
/* Read with get_attr + set_attr */
+ ret = ktest_write_read_attr(od, write_buff, true, true, true);
+ if (ret)
+ goto dev_fini;
+
/* remove objects */
ret = ktest_remove_obj(od);
if (ret)
--
1.6.0.1

2008-11-04 16:50:58

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 09/18] libosd: attributes Support

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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
drivers/scsi/osd/osd_initiator.c | 573 ++++++++++++++++++++++++++++++++++++++
include/scsi/osd_attributes.h | 327 ++++++++++++++++++++++
2 files changed, 900 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 33450b8..da0c53c 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -65,6 +65,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_dev)
{
memset(osdd, 0, sizeof(*osdd));
@@ -127,10 +171,25 @@ static void _abort_unexecuted_bios(struct request *rq)
}
}

+static void _osd_free_seg(struct osd_request *or,
+ 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);
@@ -178,6 +237,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
*/
@@ -286,6 +393,409 @@ 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->page = cpu_to_be32(oa->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,
+ int 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);
+ int 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->page = cpu_to_be32(oa->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, 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->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->page = be32_to_cpu(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->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);
+
+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;
+ 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
*/
@@ -380,9 +890,31 @@ int osd_finalize_request(struct osd_request *or,
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);
@@ -448,3 +980,44 @@ 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=%lld mantissa=%lld exp=%d encoded=%x pad=%d\n",
+ offset, 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..c53f49b
--- /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) \
+ { .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

2008-11-04 16:51:42

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 06/18] osd_uld: API for retrieving osd devices from Kernel

Kernel clients like osdfs 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 osdfs.

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 <[email protected]>
---
drivers/scsi/osd/osd_uld.c | 52 ++++++++++++++++++++++++++++++++++++++++++
include/scsi/osd_initiator.h | 5 ++++
2 files changed, 57 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 87b4540..0229301 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -42,6 +42,7 @@
* 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>
@@ -142,6 +143,57 @@ 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 *oud;
+ int error;
+
+ if (!path || !*path)
+ return ERR_PTR(-EINVAL);
+
+ error = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ if (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))
+ goto out;
+
+ cdev = inode->i_cdev;
+ if (!cdev)
+ goto out;
+
+ /* The Magic wand. Is it our char-dev */
+ /* TODO: Support sg devices */
+ if (cdev->owner != THIS_MODULE)
+ 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 24a70b7..0004df1 100644
--- a/include/scsi/osd_initiator.h
+++ b/include/scsi/osd_initiator.h
@@ -33,6 +33,11 @@ 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);
+
+/* These are called by uld at probe time */
void osd_dev_init(struct osd_dev *, struct scsi_device *scsi_dev);
void osd_dev_fini(struct osd_dev *);

--
1.6.0.1

2008-11-04 16:51:23

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 16/18] osd: Documentation for OSD library

Add osd.txt to Documentation/scsi/

Signed-off-by: Boaz Harrosh <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
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..a6735ae
--- /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.
+
+osdfs:
+ 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/osdfs.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 <[email protected]>
+
+More up-to-date information can be found on:
+http://open-osd.org
+
+Boaz Harrosh <[email protected]>
+Benny Halevy <[email protected]>
+
+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

2008-11-04 17:23:48

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 01/18] major.h: char-major number for OSD device driver

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 <[email protected]>
CC: Torben Mathiasen <[email protected]>
---
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 05c8064..d18070b 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -3142,6 +3142,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

2008-11-04 18:07:41

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 04/18] libosd: OSDv1 preliminary implementation

On Tue, Nov 04, 2008 at 06:44:29PM +0200, Boaz Harrosh wrote:
> 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

A few comments below.

Sam


>
> Signed-off-by: Boaz Harrosh <[email protected]>
> Reviewed-by: Benny Halevy <[email protected]>
> ---
> drivers/scsi/osd/Kbuild | 26 +++
> drivers/scsi/osd/Makefile | 37 +++
> drivers/scsi/osd/osd_debug.h | 27 +++
> drivers/scsi/osd/osd_initiator.c | 450 ++++++++++++++++++++++++++++++++++++++
> 4 files changed, 540 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..b4678e0
> --- /dev/null
> +++ b/drivers/scsi/osd/Kbuild
> @@ -0,0 +1,26 @@
> +#
> +# Kbuild for the OSD modules
> +#
> +# Copyright (C) 2008 Panasas Inc. All rights reserved.
> +#
> +# Authors:
> +# Boaz Harrosh <[email protected]>
> +# Benny Halevy <[email protected]>
> +#
> +# 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
> +EXTRA_CFLAGS += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
> +
> +EXTRA_CFLAGS += -I$(OSD_INC)
> +# EXTRA_CFLAGS += -DCONFIG_SCSI_OSD_DEBUG
> +
> +endif
> +
> +libosd-objs := osd_initiator.o
> +obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o

When you submit for inclusion please clean this up.
1) use ccflags-y as replacement for EXTRA_CFLAGS
2) use libosd-y as replacement for libosd-objs

> +
> +#ifdef CONFIG_SCSI_OSD_INITIATOR_MODULE
> +MODULE_AUTHOR("Boaz Harrosh <[email protected]>");
> +MODULE_DESCRIPTION("open-osd initiator library libosd.ko");
> +MODULE_LICENSE("GPL");
> +#endif

no ifdef around here.

> +void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_dev)
> +{
> + memset(osdd, 0, sizeof(*osdd));
> + osdd->scsi_dev = scsi_dev;
> + osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT;
> + /* TODO: Allocate pools for osd_request attributes ... */
> +}
> +EXPORT_SYMBOL(osd_dev_init);
kernel-doc comments for all exported funtions / variables.

2008-11-04 19:12:30

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 03/18] libosd: OSDv1 Headers

On Tue, 4 Nov 2008 18:44:06 +0200
Boaz Harrosh <[email protected]> wrote:

> 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]
>
> --- /dev/null
> +++ b/include/scsi/osd_initiator.h

This header uses quite a few things without including the header files
which define them. That's a bit risky - it causes compile breakage
across architectures, across config changes and across time.

> @@ -0,0 +1,332 @@
> +/*
> + * osd_initiator.h - OSD initiator API definition
> + *
> + * Copyright (C) 2008 Panasas Inc. All rights reserved.
> + *
> + * Authors:
> + * Boaz Harrosh <[email protected]>
> + * Benny Halevy <[email protected]>
> + *
> + * 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 <linux/blkdev.h>
> +
> +#include "osd_protocol.h"
> +#include "osd_types.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_dev;

scsi_device

> + unsigned def_timeout;
> +};
> +
> +void osd_dev_init(struct osd_dev *, struct scsi_device *scsi_dev);
> +void osd_dev_fini(struct osd_dev *);
> +
> +struct osd_request;
> +typedef void (osd_req_done_fn)(struct osd_request *, void *);
> +
> +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 not allocated by us */
> + unsigned total_bytes;
> + } set_attr, enc_get_attr, get_attr;
> +
> + struct _osd_io_info {
> + struct bio *bio;
> + u64 total_bytes;

u64(!)

> + struct request *req;
> + struct _osd_req_data_segment *last_seg;
> + u8 *pad_buff;
> + } out, in;
> +
> + gfp_t alloc_flags;

gfp_t

> + 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;
> +};

etc, etc, etc. Please review all that.

> +struct osd_request *osd_start_request(struct osd_dev *, gfp_t gfp);
> +int osd_finalize_request(struct osd_request *or,
> + u8 options, const void *cap, const u8 *cap_key);
> +void osd_req_set_master_seed_xchg(struct osd_request *, ...);/* NI */
> +void osd_req_set_master_key(struct osd_request *, ...);/* NI */
> +void osd_req_format(struct osd_request *, u64 tot_capacity);
> +int osd_req_list_dev_partitions(struct osd_request *,
> + osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem);

hm. It appears that someone made the decision to omit the name from
the `struct osd_request *' parameter in the prototypes and to include
the argument names for all other arguments.

Not a bad idea, really.

2008-11-04 19:17:47

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 04/18] libosd: OSDv1 preliminary implementation

On Tue, 4 Nov 2008 18:44:29 +0200
Boaz Harrosh <[email protected]> wrote:

> Implementation of the most basic OSD functionality and
> infrastructure. Mainly Format, Create/Remove Partition,
> Create/Remove Object, and read/write.
>
>
> ...
>
> +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;
> +}
> +
> +void _osd_request_free(struct osd_request *or)
> +{
> + kfree(or);
> +}

These two functions can/should be made static. Please generally check
for this.

Also it'd probably make sense to declare both these inline. The
compiler _shoudl_ get it right, but stranger things have happened...

>
> ...
>
> +/*
> + * 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);
> + }
> +}

Boy, that's a scary function. bye-bye data.

2008-11-04 19:20:37

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCHSET 00/18] open-osd: OSD Initiator library for Linux

On Tue, 04 Nov 2008 18:09:31 +0200
Boaz Harrosh <[email protected]> wrote:

>
> Please consider for inclusion, an in-kernel OSD initiator
> library. Its main users are planned to be various OSD based file
> systems and the pNFS-Objects Layout Driver. (To be submitted soon)
>
> 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
>
> Or a compact out-of-tree repository that includes sources
> and some extras:
> git://git.open-osd.org/open-osd.git master
> http://git.open-osd.org/gitweb.cgi?p=open-osd.git;a=summary
>
> ...
>
> We would like this to sit in -mm tree for a while to make sure it is compilable
> on all platform.

The best way to do that is to include your git tree in linux-next. If
this code has a probably-will-be-merged-in-2.6.29 status then please
prepare a branch for Stephen to include in the linux-next lineup.

2008-11-04 19:43:31

by Jörn Engel

[permalink] [raw]
Subject: Re: [PATCH 03/18] libosd: OSDv1 Headers

On Tue, 4 November 2008 11:10:37 -0800, Andrew Morton wrote:
>
> etc, etc, etc. Please review all that.

One easy way to review 98% is to include the header in an otherwise
empty foo.c and compile that. The remaining 2% are hidden behind
different config options and architectures. Although your header may be
fine on that front.

Jörn

--
He who knows others is wise.
He who knows himself is enlightened.
-- Lao Tsu

2008-11-04 20:29:47

by Jörn Engel

[permalink] [raw]
Subject: Re: [PATCH 03/18] libosd: OSDv1 Headers

On Tue, 4 November 2008 20:42:40 +0100, Jörn Engel wrote:
> On Tue, 4 November 2008 11:10:37 -0800, Andrew Morton wrote:
> >
> > etc, etc, etc. Please review all that.
>
> One easy way to review 98% is to include the header in an otherwise
> empty foo.c and compile that. The remaining 2% are hidden behind
> different config options and architectures. Although your header may be
> fine on that front.

Btw, running such a script on include/linux detects a lot of trouble
even with i386 allnoconfig. Most of which looks it could be 'fixed' by
a drunken monkey inserting #includes. But some of those #includes may
be fs.h and pull the kitchensink, adding tons of dependencies and some
compile time.

Unsure.

Jörn

--
Rules of Optimization:
Rule 1: Don't do it.
Rule 2 (for experts only): Don't do it yet.
-- M.A. Jackson

2008-11-05 12:54:31

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCH 03/18] libosd: OSDv1 Headers

Andrew Morton wrote:
> On Tue, 4 Nov 2008 18:44:06 +0200
> Boaz Harrosh <[email protected]> wrote:
>
>> 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]
>>
>> --- /dev/null
>> +++ b/include/scsi/osd_initiator.h
>
> This header uses quite a few things without including the header files
> which define them. That's a bit risky - it causes compile breakage
> across architectures, across config changes and across time.
>

It's OK. I'm very pedantic about these things.

The first header included at osd_initiator.c is this header precisely
for the check Jörn has suggested. What happens is that all the types
in osd_initiator.h are actually derived from osd_protocol.h below.
osd_protocol.h does include exactly what it needs. (Also checked)

The only new definitions used by this header are from linux/blkdev.h
hence included here.

(I will re-check that osd_protocol.h is self-sustained)

>> @@ -0,0 +1,332 @@
>> +/*
>> + * osd_initiator.h - OSD initiator API definition
>> + *
>> + * Copyright (C) 2008 Panasas Inc. All rights reserved.
>> + *
>> + * Authors:
>> + * Boaz Harrosh <[email protected]>
>> + * Benny Halevy <[email protected]>
>> + *
>> + * 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 <linux/blkdev.h>
>> +
>> +#include "osd_protocol.h"
>> +#include "osd_types.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_dev;
>
> scsi_device
>
>> + unsigned def_timeout;
>> +};
>> +
>> +void osd_dev_init(struct osd_dev *, struct scsi_device *scsi_dev);
>> +void osd_dev_fini(struct osd_dev *);
>> +
>> +struct osd_request;
>> +typedef void (osd_req_done_fn)(struct osd_request *, void *);
>> +
>> +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 not allocated by us */
>> + unsigned total_bytes;
>> + } set_attr, enc_get_attr, get_attr;
>> +
>> + struct _osd_io_info {
>> + struct bio *bio;
>> + u64 total_bytes;
>
> u64(!)
>

Do you mean that I need to use __u64? or what do you mean?

I will change it. but just for curiosity, I have seen this mentioned
once before, but never understood. What's wrong with the uXX types?
I include linux/types.h and I get them as well as the __uXX set.
Why are we not suppose to use them? And if we are not, then why do
they exist? And also why the u8 is used everywhere but the u{16-64}
are not?

(Please for give me for attacking so strongly I just personally like
them, style wise. I'm just sad to see them go ;) )

>> + struct request *req;
>> + struct _osd_req_data_segment *last_seg;
>> + u8 *pad_buff;
>> + } out, in;
>> +
>> + gfp_t alloc_flags;
>
> gfp_t
>

I prefer my name. I've seen the gfp_t use in Kernel, but I needed
that name while thinking the code. But now it's OK I'll change it.

>> + 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;
>> +};
>
> etc, etc, etc. Please review all that.
>

You mean the uXX => __uXX? I'll change all that.

>> +struct osd_request *osd_start_request(struct osd_dev *, gfp_t gfp);
>> +int osd_finalize_request(struct osd_request *or,
>> + u8 options, const void *cap, const u8 *cap_key);
>> +void osd_req_set_master_seed_xchg(struct osd_request *, ...);/* NI */
>> +void osd_req_set_master_key(struct osd_request *, ...);/* NI */
>> +void osd_req_format(struct osd_request *, u64 tot_capacity);
>> +int osd_req_list_dev_partitions(struct osd_request *,
>> + osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem);
>
> hm. It appears that someone made the decision to omit the name from
> the `struct osd_request *' parameter in the prototypes and to include
> the argument names for all other arguments.
>
> Not a bad idea, really.
>

It's a programing style thing. The "this" parameter name is dropped
for been obvious and redundant. I like to keep the Header files
most readable and self-documenting. I know that in C, the style is
to look at .c files for answers, but I borrowed the C++ way of
making it as easy as possible on the user and summarizing all exported
types and services at the header file. Not just for the sake of the compiler
but also for the reader.

Note that I put the kernel-doc comments in the header and not in the
source file.

Thank you for your comments
Boaz

2008-11-05 13:00:36

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCH 03/18] libosd: OSDv1 Headers

Jörn Engel wrote:
> On Tue, 4 November 2008 11:10:37 -0800, Andrew Morton wrote:
>> etc, etc, etc. Please review all that.
>
> One easy way to review 98% is to include the header in an otherwise
> empty foo.c and compile that. The remaining 2% are hidden behind
> different config options and architectures. Although your header may be
> fine on that front.
>
> Jörn
>

I have done just that. It's an old habit of mine. The very first
#include in osd_initiator.c is osd_initiator.h precisely for that.
So it's not just a one time test it's always tested.

Thanks
Boaz

2008-11-05 13:10:09

by James Bottomley

[permalink] [raw]
Subject: Re: [PATCH 03/18] libosd: OSDv1 Headers

On Wed, 2008-11-05 at 14:54 +0200, Boaz Harrosh wrote:
> >> + struct _osd_io_info {
> >> + struct bio *bio;
> >> + u64 total_bytes;
> >
> > u64(!)
> >
>
> Do you mean that I need to use __u64? or what do you mean?

He means you've used u64 in a header without actually including any file
that defines the typedef. Linux header files aren't supposed to depend
on include order. They're supposed to stand alone. The point is that
if I include just #include osd_initiator.h into an empty kernel file
it's not supposed to spit undefined errors.

Right at the moment the u64 probably works because blkdev.h #includes
the file which defines it, but you're not supposed to rely on that.

James

2008-11-05 13:12:30

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCH 04/18] libosd: OSDv1 preliminary implementation

Sam Ravnborg wrote:

> On Tue, Nov 04, 2008 at 06:44:29PM +0200, Boaz Harrosh wrote:
>> 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
>
> A few comments below.
>
> Sam
>

Thanks Sam for looking

>
>> Signed-off-by: Boaz Harrosh <[email protected]>
>> Reviewed-by: Benny Halevy <[email protected]>
>> ---
>> drivers/scsi/osd/Kbuild | 26 +++
>> drivers/scsi/osd/Makefile | 37 +++
>> drivers/scsi/osd/osd_debug.h | 27 +++
>> drivers/scsi/osd/osd_initiator.c | 450 ++++++++++++++++++++++++++++++++++++++
>> 4 files changed, 540 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..b4678e0
>> --- /dev/null
>> +++ b/drivers/scsi/osd/Kbuild
>> @@ -0,0 +1,26 @@
>> +#
>> +# Kbuild for the OSD modules
>> +#
>> +# Copyright (C) 2008 Panasas Inc. All rights reserved.
>> +#
>> +# Authors:
>> +# Boaz Harrosh <[email protected]>
>> +# Benny Halevy <[email protected]>
>> +#
>> +# 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
>> +EXTRA_CFLAGS += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
>> +
>> +EXTRA_CFLAGS += -I$(OSD_INC)
>> +# EXTRA_CFLAGS += -DCONFIG_SCSI_OSD_DEBUG
>> +
>> +endif
>> +
>> +libosd-objs := osd_initiator.o
>> +obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
>
> When you submit for inclusion please clean this up.
> 1) use ccflags-y as replacement for EXTRA_CFLAGS
> 2) use libosd-y as replacement for libosd-objs
>

This is a most valuable information thanks. I have copy
pasted these stuff, while learning. I guess from the wrong
example. Thanks it looks much more logical that way.

>> +
>> +#ifdef CONFIG_SCSI_OSD_INITIATOR_MODULE
>> +MODULE_AUTHOR("Boaz Harrosh <[email protected]>");
>> +MODULE_DESCRIPTION("open-osd initiator library libosd.ko");
>> +MODULE_LICENSE("GPL");
>> +#endif
>
> no ifdef around here.
>

Grate, thanks. Again the wrong copy-paste.

>> +void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_dev)
>> +{
>> + memset(osdd, 0, sizeof(*osdd));
>> + osdd->scsi_dev = scsi_dev;
>> + osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT;
>> + /* TODO: Allocate pools for osd_request attributes ... */
>> +}
>> +EXPORT_SYMBOL(osd_dev_init);
> kernel-doc comments for all exported funtions / variables.
>

I have some kernel-doc comments of exported functions in the Header
file. I have not yet finished all of them. (Laziness on my part).

Are kernel-doc comments in headers a big NO-NO. I like it this way,
so when I have to learn a new Library all the information
I need to know is in the header. Also the header is a much better place
when you do programing by shopping, that is you don't know what you need
and you look for what's available.

Thanks
Boaz

2008-11-05 13:30:13

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCH 03/18] libosd: OSDv1 Headers

James Bottomley wrote:
> On Wed, 2008-11-05 at 14:54 +0200, Boaz Harrosh wrote:
>>>> + struct _osd_io_info {
>>>> + struct bio *bio;
>>>> + u64 total_bytes;
>>> u64(!)
>>>
>> Do you mean that I need to use __u64? or what do you mean?
>
> He means you've used u64 in a header without actually including any file
> that defines the typedef. Linux header files aren't supposed to depend
> on include order. They're supposed to stand alone. The point is that
> if I include just #include osd_initiator.h into an empty kernel file
> it's not supposed to spit undefined errors.
>
> Right at the moment the u64 probably works because blkdev.h #includes
> the file which defines it, but you're not supposed to rely on that.
>
> James
>

I have addressed that issue. The osd_initiator.h includes the
osd_protocol.h file. osd_protocol.h does include all the types
needed. All of the osd_initiator.h types are derived from
osd_protocol.h, the only added definitions are from blkdev.h.

The very first #include in osd_initiator.c is osd_initiator.h
which preforms exactly the check you suggest.

Boaz

2008-11-05 13:44:52

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCH 04/18] libosd: OSDv1 preliminary implementation

Andrew Morton wrote:
> On Tue, 4 Nov 2008 18:44:29 +0200
> Boaz Harrosh <[email protected]> wrote:
>
>> Implementation of the most basic OSD functionality and
>> infrastructure. Mainly Format, Create/Remove Partition,
>> Create/Remove Object, and read/write.
>>
>>
>> ...
>>
>> +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;
>> +}
>> +
>> +void _osd_request_free(struct osd_request *or)
>> +{
>> + kfree(or);
>> +}
>
> These two functions can/should be made static. Please generally check
> for this.
>

Thanks, I usually do, but these are from the last iteration and were
rushed in. Will fix.

> Also it'd probably make sense to declare both these inline. The
> compiler _shoudl_ get it right, but stranger things have happened...
>

I do not inline them, because one - I will use mem_pools very soon they
are just place holders for now. two - I let the compiler
do that, I made sure the only user is below the definition and I let
the compiler decide. I like to leave these things controlled from outside,
so when I compile a UML kernel and finally need to fire up a debugger,
I can un-inline them very easily.

(This is why I hate forward declarations. If they are not used
it is a proof that inlineing of single callers will always happen.)

>> ...
>>
>> +/*
>> + * 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);
>> + }
>> +}
>
> Boy, that's a scary function. bye-bye data.
>

Thank's for mentioning that. I use it at the very end just before
the de-allocation of the block request. What happens today is: that
if for some reason the driver failed to call blk_end_request,
or in this case the driver was never called, the last blk_put_request()
will leak BIOs. There are currently corner cases and bugs in the Kernel
that cause exactly that.

That loop above should be moved from here to inside blk_put_request().
if some one needs to hold the BIOs longer then the life span of the request they
should simply inc-ref them.

Note that here it is totally safe since It's only called just before
blk_put_request().

This code is actually a bug fix, for the error cases when a request is allocated
but is never executed do to other error returns.

Thanks
Boaz

2008-11-05 13:57:32

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCHSET 00/18] open-osd: OSD Initiator library for Linux

Andrew Morton wrote:
> On Tue, 04 Nov 2008 18:09:31 +0200
> Boaz Harrosh <[email protected]> wrote:
>
>> Please consider for inclusion, an in-kernel OSD initiator
>> library. Its main users are planned to be various OSD based file
>> systems and the pNFS-Objects Layout Driver. (To be submitted soon)
>>
>> 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
>>
>> Or a compact out-of-tree repository that includes sources
>> and some extras:
>> git://git.open-osd.org/open-osd.git master
>> http://git.open-osd.org/gitweb.cgi?p=open-osd.git;a=summary
>>
>> ...
>>
>> We would like this to sit in -mm tree for a while to make sure it is compilable
>> on all platform.
>
> The best way to do that is to include your git tree in linux-next. If
> this code has a probably-will-be-merged-in-2.6.29 status then please
> prepare a branch for Stephen to include in the linux-next lineup.
>

Thanks Andrew
I was thinking this code would eventually go into Linux-next threw
James tree. But thought if there was a way for some exposure, so to
give James some confidence in the code before he commits to it. But
this way it could be perfect, thanks.

Stephen Hi
I have just that branch ready it is:
git://git.open-osd.org/linux-open-osd.git osd
Note the "osd" branch. Do I need to call it something special like
"linux-next"? (Give me 24 hours to fix all current comments)

Also one more question. This tree is based on latest scsi-misc-2.6.git,
Because it is destined to go threw James tree at the end. Do I need
to prepare a special tree based on Linus-latest?

Thanks in advance
Boaz

2008-11-05 16:40:10

by Jörn Engel

[permalink] [raw]
Subject: [Patch] Always include <linux/types.h>

Hardly any file in the kernel can be compiled without including
<linux/types.h>, directly or indirectly. And I'd wager a beer that
noone can find a non-trivial example. I couldn't.

So instead of sprinkling even more #include <linux/types.h> everywhere -
140 headers in include/linux/ would need that to compile standalone -
let us just pass it automatically.

The existing 4000 odd includes for types.h, plus some 300 each for
compiler.h and stddef.h, which get pulled through types.h, can get
removed at leasure.

diff --git a/Makefile b/Makefile
index 6192922..8a3fb66 100644
--- a/Makefile
+++ b/Makefile
@@ -326,7 +326,8 @@ AFLAGS_KERNEL =
# Needed to be compatible with the O= option
LINUXINCLUDE := -Iinclude \
$(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
- -include include/linux/autoconf.h
+ -include include/linux/autoconf.h \
+ -include include/linux/types.h

KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)

2008-11-05 17:20:10

by Alexey Dobriyan

[permalink] [raw]
Subject: Re: [Patch] Always include <linux/types.h>

On Wed, Nov 05, 2008 at 05:39:41PM +0100, J?rn Engel wrote:
> Hardly any file in the kernel can be compiled without including
> <linux/types.h>, directly or indirectly. And I'd wager a beer that
> noone can find a non-trivial example. I couldn't.
>
> So instead of sprinkling even more #include <linux/types.h> everywhere -
> 140 headers in include/linux/ would need that to compile standalone -
> let us just pass it automatically.
>
> The existing 4000 odd includes for types.h, plus some 300 each for
> compiler.h and stddef.h, which get pulled through types.h, can get
> removed at leasure.
>
> --- a/Makefile
> +++ b/Makefile
> @@ -326,7 +326,8 @@ AFLAGS_KERNEL =
> # Needed to be compatible with the O= option
> LINUXINCLUDE := -Iinclude \
> $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
> - -include include/linux/autoconf.h
> + -include include/linux/autoconf.h \
> + -include include/linux/types.h

This is only going to slow down compilation and types.h is not causing much
compilation problems, in fact, I can't recall a compilation problem due to
types.h. Contary to config.h situation which was a pain.

2008-11-05 17:48:48

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [Patch] Always include <linux/types.h>

Jörn Engel wrote:
> Hardly any file in the kernel can be compiled without including
> <linux/types.h>, directly or indirectly. And I'd wager a beer that
> noone can find a non-trivial example. I couldn't.
>
> So instead of sprinkling even more #include <linux/types.h> everywhere -
> 140 headers in include/linux/ would need that to compile standalone -
> let us just pass it automatically.
>
> The existing 4000 odd includes for types.h, plus some 300 each for
> compiler.h and stddef.h, which get pulled through types.h, can get
> removed at leasure.
>
> diff --git a/Makefile b/Makefile
> index 6192922..8a3fb66 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -326,7 +326,8 @@ AFLAGS_KERNEL =
> # Needed to be compatible with the O= option
> LINUXINCLUDE := -Iinclude \
> $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
> - -include include/linux/autoconf.h
> + -include include/linux/autoconf.h \
> + -include include/linux/types.h
>
> KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
>
> --

I think that if:
[A]
<header1.h>
/* no includes pure level A header */
</header1.h>

[B]
<header2.h>
#include "header1.h"
/* Level B header depends on level A */
</header2.h>

[C]
<header3.h>
#include "header2.h"
use some types of header1.h
/* Level C header depends on level B */
</header3.h>

[D]
<source.c>
#include "header3.h"
use types from A, B, C
</source.c>

Then that's fine any other file that includes any one of A, B, or C will have
no problem compiling and headers include order does not matter. Actually it is
nice, since the reader of header3.h knows that it is derived/dependent work of
header2.h.

Now what happens in the future when at B #include "header1.h" is removed.
At C header3.h stops compiling. So here I think it is the programmer's decision.
If he thinks that usage of A types used at C are do to B and if B's implementation
changes to use another set of types, then also C should change with it. Then leave
it as above. If the programmer decides that there is independent use of A types
in C unrelated to B, then he should also include A directly. If in doubt just don't
include it.

In any case I'm still not breaking the self-contained / order-independent headers
rule.

So please don't do that, Most of these places you found are the A-B-C case

Just my $0.017
Boaz

2008-11-05 19:16:50

by Jörn Engel

[permalink] [raw]
Subject: Re: [Patch] Always include <linux/types.h>

[ Threading should have been broken. Doh! ]

On Wed, 5 November 2008 20:23:12 +0300, Alexey Dobriyan wrote:
> On Wed, Nov 05, 2008 at 05:39:41PM +0100, Jörn Engel wrote:
> > Hardly any file in the kernel can be compiled without including
> > <linux/types.h>, directly or indirectly. And I'd wager a beer that
> > noone can find a non-trivial example. I couldn't.
>
> This is only going to slow down compilation and types.h is not causing much
> compilation problems, in fact, I can't recall a compilation problem due to
> types.h. Contary to config.h situation which was a pain.

My hope was actually to speed up compilation. If the average c file
includes 10 headers, on types.h will get included by most of them,
possibly multiple times. Each run after the first still has to parse
the whole file, just to drop everything between #ifndef _LINUX_TYPES_H
and #endif.

By passing types.h on the command line we can drop it from all headers
and only have to parse it once. Just the intermediate step of parsing
types.h 11 times instead of 10 will slow things down. By about .4% on
my not very beefy notebook.

Before:
real 4m33.241s
user 3m58.524s
sys 0m18.539s

After:
real 4m29.707s
user 3m59.674s
sys 0m18.182s

And while testing this I noticed that a_flags shouldn't include the
file. Updated patch below.

Jörn

--
to show off how geeky they were.
-- Rob Enderle

diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index ea48b82..328f345 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -121,7 +121,8 @@ endif

c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__c_flags) $(modkern_cflags) \
- -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+ -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
+ -include include/linux/types.h

a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \
$(__a_flags) $(modkern_aflags)

2008-11-05 19:50:42

by Andreas Schwab

[permalink] [raw]
Subject: Re: [Patch] Always include <linux/types.h>

J?rn Engel <[email protected]> writes:

> My hope was actually to speed up compilation. If the average c file
> includes 10 headers, on types.h will get included by most of them,
> possibly multiple times. Each run after the first still has to parse
> the whole file, just to drop everything between #ifndef _LINUX_TYPES_H
> and #endif.

Actually GCC is smart enought to note the bracketing and avoid even
looking at it a second time.

Andreas.

--
Andreas Schwab, SuSE Labs, [email protected]
SuSE Linux Products GmbH, Maxfeldstra?e 5, 90409 N?rnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."

2008-11-05 20:04:20

by Jörn Engel

[permalink] [raw]
Subject: Re: [Patch] Always include <linux/types.h>

On Wed, 5 November 2008 20:16:28 +0100, Jörn Engel wrote:
>
> My hope was actually to speed up compilation. If the average c file
> includes 10 headers, on types.h will get included by most of them,
> possibly multiple times. Each run after the first still has to parse
> the whole file, just to drop everything between #ifndef _LINUX_TYPES_H
> and #endif.
>
> By passing types.h on the command line we can drop it from all headers
> and only have to parse it once. Just the intermediate step of parsing
> types.h 11 times instead of 10 will slow things down. By about .4% on
> my not very beefy notebook.
>
> Before:
> real 4m33.241s
> user 3m58.524s
> sys 0m18.539s
>
> After:
> real 4m29.707s
> user 3m59.674s
> sys 0m18.182s

And after removing all explicit #include <linux/types.h> from headers:
real 4m31.946s
user 3m59.521s
sys 0m18.752s

All this may be lost in the noise. The build machine wasn't completely
idle and the variation in system time is rather random. So it neither
helps nor hurts much. Nor does it solve any real problem.

We might just as well drop it, I guess.

Jörn

--
The story so far:
In the beginning the Universe was created. This has made a lot
of people very angry and been widely regarded as a bad move.
-- Douglas Adams

2008-11-05 20:17:25

by Alexey Dobriyan

[permalink] [raw]
Subject: Re: [Patch] Always include <linux/types.h>

On Wed, Nov 05, 2008 at 08:16:29PM +0100, J?rn Engel wrote:
> [ Threading should have been broken. Doh! ]
>
> On Wed, 5 November 2008 20:23:12 +0300, Alexey Dobriyan wrote:
> > On Wed, Nov 05, 2008 at 05:39:41PM +0100, J?rn Engel wrote:
> > > Hardly any file in the kernel can be compiled without including
> > > <linux/types.h>, directly or indirectly. And I'd wager a beer that
> > > noone can find a non-trivial example. I couldn't.
> >
> > This is only going to slow down compilation and types.h is not causing much
> > compilation problems, in fact, I can't recall a compilation problem due to
> > types.h. Contary to config.h situation which was a pain.
>
> My hope was actually to speed up compilation. If the average c file
> includes 10 headers, on types.h will get included by most of them,
> possibly multiple times. Each run after the first still has to parse
> the whole file, just to drop everything between #ifndef _LINUX_TYPES_H
> and #endif.
>
> By passing types.h on the command line we can drop it from all headers
> and only have to parse it once. Just the intermediate step of parsing
> types.h 11 times instead of 10 will slow things down. By about .4% on
> my not very beefy notebook.
>
> Before:
> real 4m33.241s
> user 3m58.524s
> sys 0m18.539s
>
> After:
> real 4m29.707s
> user 3m59.674s
> sys 0m18.182s

Could be anything.

2008-11-05 20:39:18

by Alexey Dobriyan

[permalink] [raw]
Subject: Re: [Patch] Always include <linux/types.h>

On Wed, Nov 05, 2008 at 09:02:17PM +0100, J?rn Engel wrote:
> On Wed, 5 November 2008 20:16:28 +0100, J?rn Engel wrote:
> >
> > My hope was actually to speed up compilation. If the average c file
> > includes 10 headers, on types.h will get included by most of them,
> > possibly multiple times. Each run after the first still has to parse
> > the whole file, just to drop everything between #ifndef _LINUX_TYPES_H
> > and #endif.
> >
> > By passing types.h on the command line we can drop it from all headers
> > and only have to parse it once. Just the intermediate step of parsing
> > types.h 11 times instead of 10 will slow things down. By about .4% on
> > my not very beefy notebook.
> >
> > Before:
> > real 4m33.241s
> > user 3m58.524s
> > sys 0m18.539s
> >
> > After:
> > real 4m29.707s
> > user 3m59.674s
> > sys 0m18.182s
>
> And after removing all explicit #include <linux/types.h> from headers:
> real 4m31.946s
> user 3m59.521s
> sys 0m18.752s
>
> All this may be lost in the noise. The build machine wasn't completely
> idle and the variation in system time is rather random. So it neither
> helps nor hurts much. Nor does it solve any real problem.
>
> We might just as well drop it, I guess.

If you are working on improving compile times, it's better concentrate
on removing unneeded includes. If just removing "extern"s from prototypes
can reliably save several seconds, reducing headers can do wonders.

2008-11-07 08:02:59

by Jörn Engel

[permalink] [raw]
Subject: Re: [Patch] Always include <linux/types.h>

On Wed, 5 November 2008 23:32:12 +0300, Alexey Dobriyan wrote:
>
> If you are working on improving compile times, it's better concentrate
> on removing unneeded includes. If just removing "extern"s from prototypes
> can reliably save several seconds, reducing headers can do wonders.

My goal was more to assume we want all headers to compile standalone and
see where that would lead. Result for include/linux/ was some 500 added
lines, 170 of which were to add types.h or compiler.h. Another 50-100
further includes were fairly well-spread across the spectrum. The
remainder was declarations like
struct super_block;

Overall we have three evils to choose from. Headers with unresolved
dependencies lead to random compile breakage after removing a header
from some .c file. Even if the change was tested, it can still break
for some config/architecture combination month down the line.

Sprinkling more includes throughout the headers increase compile time.
And the common practice of declaring a structure instead of including
the header is a pita when working with ctags. The last problem is
particularly annoying since I have no idea what problem this warning is
supposed to solve:
In file included from include/linux/coda_cache.c:1:
include/linux/coda_cache.h:18: warning: ‘struct super_block’ declared inside parameter list
include/linux/coda_cache.h:18: warning: its scope is only this definition or declaration, which is probably not what you want

Should we just teach gcc to shut up about that one?

Jörn

--
Anything that can go wrong, will.
-- Finagle's Law

2008-11-09 14:50:32

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 04/18 ver2] libosd: OSDv1 preliminary implementation


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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
drivers/scsi/osd/Kbuild | 26 +++
drivers/scsi/osd/Makefile | 37 +++
drivers/scsi/osd/osd_debug.h | 27 +++
drivers/scsi/osd/osd_initiator.c | 448 ++++++++++++++++++++++++++++++++++++++
4 files changed, 538 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..b6328e6
--- /dev/null
+++ b/drivers/scsi/osd/Kbuild
@@ -0,0 +1,26 @@
+#
+# Kbuild for the OSD modules
+#
+# Copyright (C) 2008 Panasas Inc. All rights reserved.
+#
+# Authors:
+# Boaz Harrosh <[email protected]>
+# Benny Halevy <[email protected]>
+#
+# 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
+
+ccflags-y += -I$(OSD_INC)
+# ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
+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 <[email protected]>
+# Benny Halevy <[email protected]>
+#
+# 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..0bc65fa
--- /dev/null
+++ b/drivers/scsi/osd/osd_debug.h
@@ -0,0 +1,27 @@
+/*
+ * osd_debug.h - Some kprintf macros
+ *
+ * Copyright (C) 2008 Panasas Inc. All rights reserved.
+ *
+ * Authors:
+ * Boaz Harrosh <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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
+
+#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..63b8a91
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 <[email protected]>");
+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 &= __constant_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",
+ 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",
+ 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

2008-11-09 14:52:50

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 03/18 ver2] libosd: OSDv1 Headers


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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
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..9bab95d
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 *, struct scsi_device *scsi_dev);
+void osd_dev_fini(struct osd_dev *);
+
+struct osd_request;
+typedef void (osd_req_done_fn)(struct osd_request *, void *);
+
+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 not allocated by us */
+ 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 *, 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
+ * the 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 - submits the request for execution through
+ * the block-layer without waitting.
+ * @or: - osd_request to Executed
+ * @done: (Optional) - Called at end of execution
+ * @private: - Will be passes to @done function
+ *
+ * Calls blk_execute_rq_nowait to q the command. When execution is done
+ * Optionally calles @done with @private as parameter. or->async_error has 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 *, ...);/* NI */
+void osd_req_set_master_key(struct osd_request *, ...);/* NI */
+
+void osd_req_format(struct osd_request *, 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 *,
+ osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem);
+
+void osd_req_flush_obsd(struct osd_request *,
+ enum osd_options_flush_scope_values);
+
+void osd_req_perform_scsi_command(struct osd_request *,
+ const u8 *cdb, ...);/* NI */
+void osd_req_task_management(struct osd_request *, ...);/* NI */
+
+/*
+ * Partition commands
+ */
+void osd_req_create_partition(struct osd_request *, osd_id partition);
+void osd_req_remove_partition(struct osd_request *, osd_id partition);
+
+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]);/* 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 *,
+ 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 *,
+ osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
+ unsigned nelem);
+
+void osd_req_flush_partition(struct osd_request *,
+ osd_id partition, enum osd_options_flush_scope_values);
+
+/*
+ * Collection commands
+ */
+void osd_req_create_collection(struct osd_request *,
+ const struct osd_obj_id *);/* NI */
+void osd_req_remove_collection(struct osd_request *,
+ const struct osd_obj_id *);/* NI */
+
+/* list all objects in the collection */
+int osd_req_list_collection_objects(struct osd_request *,
+ 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 *, ...);/* NI */
+
+void osd_req_flush_collection(struct osd_request *,
+ const struct osd_obj_id *, enum osd_options_flush_scope_values);
+
+void osd_req_get_member_attrs(struct osd_request *, ...);/* V2-only NI */
+void osd_req_set_member_attrs(struct osd_request *, ...);/* V2-only NI */
+
+/*
+ * Object commands
+ */
+void osd_req_create_object(struct osd_request *, struct osd_obj_id *);
+void osd_req_remove_object(struct osd_request *, struct osd_obj_id *);
+
+void osd_req_write(struct osd_request *,
+ const struct osd_obj_id *, struct bio *data_out, u64 offset);
+void osd_req_append(struct osd_request *,
+ const struct osd_obj_id *, struct bio *data_out);/* NI */
+void osd_req_create_write(struct osd_request *,
+ const struct osd_obj_id *, struct bio *data_out, u64 offset);/* NI */
+void osd_req_clear(struct osd_request *,
+ const struct osd_obj_id *, u64 offset, u64 len);/* NI */
+void osd_req_punch(struct osd_request *,
+ const struct osd_obj_id *, u64 offset, u64 len);/* V2-only NI */
+
+void osd_req_flush_object(struct osd_request *,
+ const struct osd_obj_id *, enum osd_options_flush_scope_values,
+ /*V2*/ u64 offset, /*V2*/ u64 len);
+
+void osd_req_read(struct osd_request *,
+ 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 *, const struct osd_obj_id *);
+
+/* set before get */
+void osd_req_set_attributes(struct osd_request *, 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 *,
+ const struct osd_attr *, unsigned nelem);
+
+/* get a list of attributes */
+int osd_req_add_get_attr_list(struct osd_request *,
+ 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 *,
+ 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 *,
+ 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..77a74a3
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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;
+ } __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;
+ } __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[80-62];
+ } __packed attrs_cdb;
+/*52*/ u8 get_set_attributes_parameters[80-52];
+ };
+} __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 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 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 [email protected] */
+} __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 = (1 << 0),
+ OSD_SEC_CAP_OBJ_MGMT = (1 << 1),
+ OSD_SEC_CAP_REMOVE = (1 << 2),
+ OSD_SEC_CAP_CREATE = (1 << 3),
+ OSD_SEC_CAP_SET_ATTR = (1 << 4),
+ OSD_SEC_CAP_GET_ATTR = (1 << 5),
+ OSD_SEC_CAP_WRITE = (1 << 6),
+ OSD_SEC_CAP_READ = (1 << 7),
+
+ OSD_SEC_CAP_NONE1 = (1 << 8),
+ OSD_SEC_CAP_NONE2 = (1 << 9),
+ OSD_SEC_CAP_NONE3 = (1 << 10),
+ OSD_SEC_CAP_QUERY = (1 << 11), /*v2 only*/
+ OSD_SEC_CAP_M_OBJECT = (1 << 12), /*v2 only*/
+ OSD_SEC_CAP_POL_SEC = (1 << 13),
+ OSD_SEC_CAP_GLOBAL = (1 << 14),
+ OSD_SEC_CAP_DEV_MGMT = (1 << 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[30-10];
+/*30*/ u8 discriminator[42-30];
+/*42*/ struct osd_timestamp object_created_time;
+/*48*/ u8 object_type;
+ u8 permissions_bit_mask[54-49];
+/*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;
+
+ u8 object_descriptor[80-56];/*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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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..ea5372d
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 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

2008-11-09 14:55:52

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [osd-dev] [PATCH 04/18] libosd: OSDv1 preliminary implementation

Boaz Harrosh wrote:
> Sam Ravnborg wrote:
>>> +EXPORT_SYMBOL(osd_dev_init);
>> kernel-doc comments for all exported funtions / variables.
>>
>
> I have some kernel-doc comments of exported functions in the Header
> file. I have not yet finished all of them. (Laziness on my part).
>
> Are kernel-doc comments in headers a big NO-NO. I like it this way,
> so when I have to learn a new Library all the information
> I need to know is in the header. Also the header is a much better place
> when you do programing by shopping, that is you don't know what you need
> and you look for what's available.
>
> Thanks
> Boaz

Sam please comment if kernel-doc comments are OK in headers

Thanks
Boaz

2008-11-09 14:59:08

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCHSET 00/18] open-osd: OSD Initiator library for Linux

Andrew Morton wrote:
> On Tue, 04 Nov 2008 18:09:31 +0200
> Boaz Harrosh <[email protected]> wrote:
>
>> Please consider for inclusion, an in-kernel OSD initiator
>> library. Its main users are planned to be various OSD based file
>> systems and the pNFS-Objects Layout Driver. (To be submitted soon)
>>
>> 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
>>
>> Or a compact out-of-tree repository that includes sources
>> and some extras:
>> git://git.open-osd.org/open-osd.git master
>> http://git.open-osd.org/gitweb.cgi?p=open-osd.git;a=summary
>>
>> ...
>>
>> We would like this to sit in -mm tree for a while to make sure it is compilable
>> on all platform.
>
> The best way to do that is to include your git tree in linux-next. If
> this code has a probably-will-be-merged-in-2.6.29 status then please
> prepare a branch for Stephen to include in the linux-next lineup.
>

Hi Stephen and James

I have prepared a branch for linux-next based on today's Linus tree
It is here:
git://git.open-osd.org/linux-open-osd.git linux-next
This is if it's OK with James, as these bits are his responsibility.
They need only sit in linux-next for a couple of weeks to get some wider
compilation exposure. Other then that they are totally new code and
are safe. Eventually they should be included into Linux-next through
scsi-misc-2.6.

I have only posted "ver 2" updates to a couple of patches that had
comments by people but more patches changed. Mainly:
- rename of scsi_dev => scsi_device
- missing static keyword
- Kbuild fixes and comments by Sam Ravnborg
- small typos found on the way

The new patchset can be reviewed at:
git://git.open-osd.org/linux-open-osd.git linux-next
http://git.open-osd.org/gitweb.cgi?p=linux-open-osd.git;a=shortlog;h=linux-next

or Based on current scsi-misc-2.6:
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

I did not want to spam the mailing-list with somewhat same patches.
I will post them, if any one needs me to.

Thanks everyone for your help
Boaz

2008-11-09 17:45:59

by Jörn Engel

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver2] libosd: OSDv1 Headers

On Sun, 9 November 2008 16:52:36 +0200, Boaz Harrosh wrote:
>
> +struct osdv1_cdb {
> + struct osd_cdb_head h;
> + u8 caps[OSDv1_CAP_LEN];
> + struct osd_security_parameters sec_params;
> +} __packed;

__packed can result in slow code being generated. But removing the
attribute can lead to bugs on other architectures. F.e. the size of
the structure below is different for i386 and x86_64.

struct foo {
u64 bar;
u32 baz;
};

My personal solution is to use this little macro and then just follow
every structure defition with a size check.

#define SIZE_CHECK(type, size) \
static inline void check_##type(void) \
{ \
BUILD_BUG_ON(sizeof(struct type) != (size)); \
}
...
struct foo {
u64 bar;
u32 baz;
};

SIZE_CHECK(foo, 12);

The above would not compile on x86_64 and clearly indicate a missing
__packed. In other cases the attribute can be removed.

Jörn

--
Invincibility is in oneself, vulnerability is in the opponent.
-- Sun Tzu

2008-11-09 23:26:36

by Stephen Rothwell

[permalink] [raw]
Subject: Re: [PATCHSET 00/18] open-osd: OSD Initiator library for Linux

Hi Boaz,

On Sun, 09 Nov 2008 16:58:59 +0200 Boaz Harrosh <[email protected]> wrote:
>
> I have prepared a branch for linux-next based on today's Linus tree
> It is here:
> git://git.open-osd.org/linux-open-osd.git linux-next
> This is if it's OK with James, as these bits are his responsibility.
> They need only sit in linux-next for a couple of weeks to get some wider
> compilation exposure. Other then that they are totally new code and
> are safe. Eventually they should be included into Linux-next through
> scsi-misc-2.6.

I have added that tree to linux-next for today.

What I say to everyone: commits in that branch must have been posted
somewhere appropriate, reviewed, unit tested and destined for the next
merge window. Also, note that my (new) practise is to temporarily drop a
tree if it causes non-trivial conflicts (especially with Linus' tree), so
don't be too upset if you get a message from me to that effect.

--
Cheers,
Stephen Rothwell [email protected]
http://www.canb.auug.org.au/~sfr/


Attachments:
(No filename) (1.02 kB)
(No filename) (197.00 B)
Download all attachments

2008-11-10 05:38:57

by Randy Dunlap

[permalink] [raw]
Subject: Re: [osd-dev] [PATCH 04/18] libosd: OSDv1 preliminary implementation

Boaz Harrosh wrote:
> Boaz Harrosh wrote:
>> Sam Ravnborg wrote:
>>>> +EXPORT_SYMBOL(osd_dev_init);
>>> kernel-doc comments for all exported funtions / variables.
>>>
>> I have some kernel-doc comments of exported functions in the Header
>> file. I have not yet finished all of them. (Laziness on my part).
>>
>> Are kernel-doc comments in headers a big NO-NO. I like it this way,
>> so when I have to learn a new Library all the information
>> I need to know is in the header. Also the header is a much better place
>> when you do programing by shopping, that is you don't know what you need
>> and you look for what's available.
>>
>> Thanks
>> Boaz
>
> Sam please comment if kernel-doc comments are OK in headers

Hi,

The de facto standard for kernel-doc comments is at the implementation site,
which means normally in .c files, except for macros or inline functions.

Sure you can find some exceptions to that. And there is no hard requirement
in Documentation/kernel-doc-nano-HOWTO.txt.

IMO the biggest concern is making sure that the (kernel-doc) comments are
updated when the function implementation changes (if updates are needed).
Where would be the best place for this to be more likely to happen?
Usually at the function implementation, I would say.

~Randy


--
~Randy

2008-11-10 08:47:16

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver2] libosd: OSDv1 Headers

Jörn Engel wrote:
> On Sun, 9 November 2008 16:52:36 +0200, Boaz Harrosh wrote:
>> +struct osdv1_cdb {
>> + struct osd_cdb_head h;
>> + u8 caps[OSDv1_CAP_LEN];
>> + struct osd_security_parameters sec_params;
>> +} __packed;
>
> __packed can result in slow code being generated. But removing the
> attribute can lead to bugs on other architectures. F.e. the size of
> the structure below is different for i386 and x86_64.
>
> struct foo {
> u64 bar;
> u32 baz;
> };
>
> My personal solution is to use this little macro and then just follow
> every structure defition with a size check.
>
> #define SIZE_CHECK(type, size) \
> static inline void check_##type(void) \
> { \
> BUILD_BUG_ON(sizeof(struct type) != (size)); \
> }
> ...
> struct foo {
> u64 bar;
> u32 baz;
> };
>
> SIZE_CHECK(foo, 12);
>
> The above would not compile on x86_64 and clearly indicate a missing
> __packed. In other cases the attribute can be removed.
>
> Jörn
>

Hi Jörn
Thank you for your comments

I do have a size check that governs the complete structure it is the first
code in osd_initiator.c at build_test(). It will catch any discrepancies
from the protocol.

I have done some experimentation with __packed both on 32 and 64 bit x86.
When it does nothing like the above foo in 32bit, then there is no code
difference with it or with out it, but on 64bit I must have it otherwise
the structure grows.

These are all, on-the-wire structures. I must have __packed, otherwise
I'm at the compiler mercy and that's bad.

If the assembly - size and offsets - of foo is exactly the same with or
without the __packed, but the generated code is different then clearly this
is a compiler bug. I've herd of this myth before, and at least with my
gcc 4.1.2 there is no such bug. Either the structure gets packed, or there is
no difference. All the places I have __packed in the code are absolutely must
be so, stated by the protocol.

Boaz

2008-11-10 09:00:31

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [osd-dev] [PATCH 04/18] libosd: OSDv1 preliminary implementation

Randy Dunlap wrote:
> Boaz Harrosh wrote:
>> Boaz Harrosh wrote:
>>> Sam Ravnborg wrote:
>>>>> +EXPORT_SYMBOL(osd_dev_init);
>>>> kernel-doc comments for all exported funtions / variables.
>>>>
>>> I have some kernel-doc comments of exported functions in the Header
>>> file. I have not yet finished all of them. (Laziness on my part).
>>>
>>> Are kernel-doc comments in headers a big NO-NO. I like it this way,
>>> so when I have to learn a new Library all the information
>>> I need to know is in the header. Also the header is a much better place
>>> when you do programing by shopping, that is you don't know what you need
>>> and you look for what's available.
>>>
>>> Thanks
>>> Boaz
>> Sam please comment if kernel-doc comments are OK in headers
>
> Hi,
>
> The de facto standard for kernel-doc comments is at the implementation site,
> which means normally in .c files, except for macros or inline functions.
>
> Sure you can find some exceptions to that. And there is no hard requirement
> in Documentation/kernel-doc-nano-HOWTO.txt.
>
> IMO the biggest concern is making sure that the (kernel-doc) comments are
> updated when the function implementation changes (if updates are needed).
> Where would be the best place for this to be more likely to happen?
> Usually at the function implementation, I would say.
>
> ~Randy
>
>
Thanks Randy

I would like to keep them in the Headers then. This is because I make
sure that the implementation includes the declaring header, so any miss-matches
are caught by the compiler.
And because these are all library routines exported to other modules. The important
thing is the API you linked with. If the API/parametrization change it must first
change in the header. The internal implementation is not documented only the external
black-box functionality is documented in these places.

I will think about it some more, but for now, if it's OK I would like to keep them
like submitted. In this particular library they make more sense to me in the header.

Boaz

2008-11-10 12:52:24

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCHSET 00/18] open-osd: OSD Initiator library for Linux

Stephen Rothwell wrote:
> Hi Boaz,
>
> On Sun, 09 Nov 2008 16:58:59 +0200 Boaz Harrosh <[email protected]> wrote:
>> I have prepared a branch for linux-next based on today's Linus tree
>> It is here:
>> git://git.open-osd.org/linux-open-osd.git linux-next
>> This is if it's OK with James, as these bits are his responsibility.
>> They need only sit in linux-next for a couple of weeks to get some wider
>> compilation exposure. Other then that they are totally new code and
>> are safe. Eventually they should be included into Linux-next through
>> scsi-misc-2.6.
>
> I have added that tree to linux-next for today.
>
> What I say to everyone: commits in that branch must have been posted
> somewhere appropriate, reviewed, unit tested and destined for the next
> merge window. Also, note that my (new) practise is to temporarily drop a
> tree if it causes non-trivial conflicts (especially with Linus' tree), so
> don't be too upset if you get a message from me to that effect.
>

Thank you Stephen, very much

This has proven itself already. I found some warnings on some ARCHs
concerning printk of u64 types. I have made a sweep and fixed all these
places and others.
(same place: git://git.open-osd.org/linux-open-osd.git linux-next)

If you could keep it for the next round it could be grate. So I can make
sure I got rid of all the warnings.

Thanks again
Boaz

2008-11-10 13:04:37

by Stephen Rothwell

[permalink] [raw]
Subject: Re: [PATCHSET 00/18] open-osd: OSD Initiator library for Linux

Hi Boaz,

On Mon, 10 Nov 2008 14:52:21 +0200 Boaz Harrosh <[email protected]> wrote:
>
> This has proven itself already. I found some warnings on some ARCHs
> concerning printk of u64 types. I have made a sweep and fixed all these
> places and others.

Good. That's partly what -next is for (to find the arch dependent
problems).

> If you could keep it for the next round it could be grate. So I can make
> sure I got rid of all the warnings.

Normally trees stay in linux-next until they are no longer needed
(usually at least until they have been integrated into Linus' tree) and I
automatically refetch the trees each day.

--
Cheers,
Stephen Rothwell [email protected]
http://www.canb.auug.org.au/~sfr/


Attachments:
(No filename) (735.00 B)
(No filename) (197.00 B)
Download all attachments

2008-11-10 15:18:32

by Jörn Engel

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver2] libosd: OSDv1 Headers

On Mon, 10 November 2008 10:47:07 +0200, Boaz Harrosh wrote:
>
> If the assembly - size and offsets - of foo is exactly the same with or
> without the __packed, but the generated code is different then clearly this
> is a compiler bug. I've herd of this myth before, and at least with my
> gcc 4.1.2 there is no such bug. Either the structure gets packed, or there is
> no difference. All the places I have __packed in the code are absolutely must
> be so, stated by the protocol.

Ok, if current compilers are fine, I won't complain.

Jörn

--
There's nothing better for promoting creativity in a medium than
making an audience feel "Hmm ­ I could do better than that!"
-- Douglas Adams in a slashdot interview

2008-11-10 17:32:20

by Randy Dunlap

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver2] libosd: OSDv1 Headers

On Sun, 09 Nov 2008 16:52:36 +0200 Boaz Harrosh wrote:

> 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 <[email protected]>
> Reviewed-by: Benny Halevy <[email protected]>
> ---
> 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..9bab95d
> --- /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 <[email protected]>
> + * Benny Halevy <[email protected]>
> + *
> + * 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 *, struct scsi_device *scsi_dev);

Don't mix having parameter names and not having them.
Preferred is having them.

> +void osd_dev_fini(struct osd_dev *);
> +
> +struct osd_request;
> +typedef void (osd_req_done_fn)(struct osd_request *, void *);
> +
> +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 not allocated by us */

Could/would some other code allocate it, or is the "by us" just redundant?

> + 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;
> +};
> +
> +/**

Don't start comment blocks with /** when they are not kernel-doc,
like this one is not.

> + * 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 *, 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.

Last 2 parameters need a ':' after the @param_name, like the first 2 have.

> + *
> + * 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
> + * the block-layer

Function name and short description need to be on one line.

> + * @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 - submits the request for execution through
> + * the block-layer without waitting.

Ditto.

> + * @or: - osd_request to Executed
> + * @done: (Optional) - Called at end of execution
> + * @private: - Will be passes to @done function

s/passes/passed/

> + *
> + * Calls blk_execute_rq_nowait to q the command. When execution is done
> + * Optionally calles @done with @private as parameter. or->async_error has the

s/calles/calls/

> + * Return code

and don't start each line with a Capital letter since they are not the
beginning of sentences. What's with that period ('.') before "or->async_error"
(which needs a space after "or").


> + */
> +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 *, ...);/* NI */
> +void osd_req_set_master_key(struct osd_request *, ...);/* NI */
> +
> +void osd_req_format(struct osd_request *, 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 *,
> + osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem);
> +
> +void osd_req_flush_obsd(struct osd_request *,
> + enum osd_options_flush_scope_values);
> +
> +void osd_req_perform_scsi_command(struct osd_request *,
> + const u8 *cdb, ...);/* NI */
> +void osd_req_task_management(struct osd_request *, ...);/* NI */
> +
> +/*
> + * Partition commands
> + */
> +void osd_req_create_partition(struct osd_request *, osd_id partition);
> +void osd_req_remove_partition(struct osd_request *, osd_id partition);
> +
> +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]);/* 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 *,
> + 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 *,
> + osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
> + unsigned nelem);
> +
> +void osd_req_flush_partition(struct osd_request *,
> + osd_id partition, enum osd_options_flush_scope_values);
> +
> +/*
> + * Collection commands
> + */
> +void osd_req_create_collection(struct osd_request *,
> + const struct osd_obj_id *);/* NI */
> +void osd_req_remove_collection(struct osd_request *,
> + const struct osd_obj_id *);/* NI */
> +
> +/* list all objects in the collection */
> +int osd_req_list_collection_objects(struct osd_request *,
> + 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 *, ...);/* NI */
> +
> +void osd_req_flush_collection(struct osd_request *,
> + const struct osd_obj_id *, enum osd_options_flush_scope_values);
> +
> +void osd_req_get_member_attrs(struct osd_request *, ...);/* V2-only NI */
> +void osd_req_set_member_attrs(struct osd_request *, ...);/* V2-only NI */
> +
> +/*
> + * Object commands
> + */
> +void osd_req_create_object(struct osd_request *, struct osd_obj_id *);
> +void osd_req_remove_object(struct osd_request *, struct osd_obj_id *);
> +
> +void osd_req_write(struct osd_request *,
> + const struct osd_obj_id *, struct bio *data_out, u64 offset);
> +void osd_req_append(struct osd_request *,
> + const struct osd_obj_id *, struct bio *data_out);/* NI */
> +void osd_req_create_write(struct osd_request *,
> + const struct osd_obj_id *, struct bio *data_out, u64 offset);/* NI */
> +void osd_req_clear(struct osd_request *,
> + const struct osd_obj_id *, u64 offset, u64 len);/* NI */
> +void osd_req_punch(struct osd_request *,
> + const struct osd_obj_id *, u64 offset, u64 len);/* V2-only NI */
> +
> +void osd_req_flush_object(struct osd_request *,
> + const struct osd_obj_id *, enum osd_options_flush_scope_values,
> + /*V2*/ u64 offset, /*V2*/ u64 len);
> +
> +void osd_req_read(struct osd_request *,
> + 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 *, const struct osd_obj_id *);
> +
> +/* set before get */
> +void osd_req_set_attributes(struct osd_request *, 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 *,
> + const struct osd_attr *, unsigned nelem);
> +
> +/* get a list of attributes */
> +int osd_req_add_get_attr_list(struct osd_request *,
> + 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 *,
> + 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 *,
> + 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..77a74a3
> --- /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 <[email protected]>
> + * Benny Halevy <[email protected]>
> + *
> + * 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;
> + } __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;
> + } __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[80-62];
> + } __packed attrs_cdb;
> +/*52*/ u8 get_set_attributes_parameters[80-52];
> + };
> +} __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 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 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 [email protected] */
> +} __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 = (1 << 0),
> + OSD_SEC_CAP_OBJ_MGMT = (1 << 1),
> + OSD_SEC_CAP_REMOVE = (1 << 2),
> + OSD_SEC_CAP_CREATE = (1 << 3),
> + OSD_SEC_CAP_SET_ATTR = (1 << 4),
> + OSD_SEC_CAP_GET_ATTR = (1 << 5),
> + OSD_SEC_CAP_WRITE = (1 << 6),
> + OSD_SEC_CAP_READ = (1 << 7),
> +
> + OSD_SEC_CAP_NONE1 = (1 << 8),
> + OSD_SEC_CAP_NONE2 = (1 << 9),
> + OSD_SEC_CAP_NONE3 = (1 << 10),
> + OSD_SEC_CAP_QUERY = (1 << 11), /*v2 only*/
> + OSD_SEC_CAP_M_OBJECT = (1 << 12), /*v2 only*/
> + OSD_SEC_CAP_POL_SEC = (1 << 13),
> + OSD_SEC_CAP_GLOBAL = (1 << 14),
> + OSD_SEC_CAP_DEV_MGMT = (1 << 15),

These could use BIT(nr) from bitops.h.

> +};
> +
> +/* 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[30-10];
> +/*30*/ u8 discriminator[42-30];
> +/*42*/ struct osd_timestamp object_created_time;
> +/*48*/ u8 object_type;
> + u8 permissions_bit_mask[54-49];

The offset comments are OK with me, but please lose the [b-a] length specifiers.


> +/*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;
> +
> + u8 object_descriptor[80-56];/*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__ */

---
~Randy

2008-11-12 13:10:37

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver2] libosd: OSDv1 Headers

Randy Dunlap wrote:
> On Sun, 09 Nov 2008 16:52:36 +0200 Boaz Harrosh wrote:
>
>> 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 <[email protected]>
>> Reviewed-by: Benny Halevy <[email protected]>

Thank you Randy for your review, I will post a fixed
patch shortly. I have changed according to your comments
except in one place, see arguments below.

>> ---
>> 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..9bab95d
>> --- /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 <[email protected]>
>> + * Benny Halevy <[email protected]>
>> + *
>> + * 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 *, struct scsi_device *scsi_dev);
>
> Don't mix having parameter names and not having them.
> Preferred is having them.
>

I don't know what got into me. I thought it would be more readable this
way. But you are right consistency is very important.

>> +void osd_dev_fini(struct osd_dev *);
>> +
>> +struct osd_request;
>> +typedef void (osd_req_done_fn)(struct osd_request *, void *);
>> +
>> +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 not allocated by us */
>
> Could/would some other code allocate it, or is the "by us" just redundant?
>

I've changed the comment as it was not clear it is now:
+ 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;
>> +};
>> +
>> +/**
>
> Don't start comment blocks with /** when they are not kernel-doc,
> like this one is not.
>

OK, I must confess my kernel-doc total ignorance. I was imagining that
each source file's kernel-doc comments are collected into an html file.
I thought that this comment will be like an introduction to the following
function-by-function reference. Anyway it's fixed

>> + * 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 *, 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.
>
> Last 2 parameters need a ':' after the @param_name, like the first 2 have.
>
oops

>> + *
>> + * 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
>> + * the block-layer
>
> Function name and short description need to be on one line.
>

OK I re-worded so it will fit in one line. What happens if it does not
fit, both name and description, in 80 characters? is there a continuation
symbol or something?

>> + * @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 - submits the request for execution through
>> + * the block-layer without waitting.
>
> Ditto.
>
>> + * @or: - osd_request to Executed
>> + * @done: (Optional) - Called at end of execution
>> + * @private: - Will be passes to @done function
>
> s/passes/passed/
>
Thanks

>> + *
>> + * Calls blk_execute_rq_nowait to q the command. When execution is done
>> + * Optionally calles @done with @private as parameter. or->async_error has the
>
> s/calles/calls/
>
>> + * Return code
>
> and don't start each line with a Capital letter since they are not the
> beginning of sentences. What's with that period ('.') before "or->async_error"
> (which needs a space after "or").
>

I reworded these so they are more clear, I hope.

>
>> + */
>> +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 *, ...);/* NI */
>> +void osd_req_set_master_key(struct osd_request *, ...);/* NI */
>> +
>> +void osd_req_format(struct osd_request *, 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 *,
>> + osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem);
>> +
>> +void osd_req_flush_obsd(struct osd_request *,
>> + enum osd_options_flush_scope_values);
>> +
>> +void osd_req_perform_scsi_command(struct osd_request *,
>> + const u8 *cdb, ...);/* NI */
>> +void osd_req_task_management(struct osd_request *, ...);/* NI */
>> +
>> +/*
>> + * Partition commands
>> + */
>> +void osd_req_create_partition(struct osd_request *, osd_id partition);
>> +void osd_req_remove_partition(struct osd_request *, osd_id partition);
>> +
>> +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]);/* 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 *,
>> + 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 *,
>> + osd_id partition, osd_id initial_id, struct osd_obj_id_list *list,
>> + unsigned nelem);
>> +
>> +void osd_req_flush_partition(struct osd_request *,
>> + osd_id partition, enum osd_options_flush_scope_values);
>> +
>> +/*
>> + * Collection commands
>> + */
>> +void osd_req_create_collection(struct osd_request *,
>> + const struct osd_obj_id *);/* NI */
>> +void osd_req_remove_collection(struct osd_request *,
>> + const struct osd_obj_id *);/* NI */
>> +
>> +/* list all objects in the collection */
>> +int osd_req_list_collection_objects(struct osd_request *,
>> + 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 *, ...);/* NI */
>> +
>> +void osd_req_flush_collection(struct osd_request *,
>> + const struct osd_obj_id *, enum osd_options_flush_scope_values);
>> +
>> +void osd_req_get_member_attrs(struct osd_request *, ...);/* V2-only NI */
>> +void osd_req_set_member_attrs(struct osd_request *, ...);/* V2-only NI */
>> +
>> +/*
>> + * Object commands
>> + */
>> +void osd_req_create_object(struct osd_request *, struct osd_obj_id *);
>> +void osd_req_remove_object(struct osd_request *, struct osd_obj_id *);
>> +
>> +void osd_req_write(struct osd_request *,
>> + const struct osd_obj_id *, struct bio *data_out, u64 offset);
>> +void osd_req_append(struct osd_request *,
>> + const struct osd_obj_id *, struct bio *data_out);/* NI */
>> +void osd_req_create_write(struct osd_request *,
>> + const struct osd_obj_id *, struct bio *data_out, u64 offset);/* NI */
>> +void osd_req_clear(struct osd_request *,
>> + const struct osd_obj_id *, u64 offset, u64 len);/* NI */
>> +void osd_req_punch(struct osd_request *,
>> + const struct osd_obj_id *, u64 offset, u64 len);/* V2-only NI */
>> +
>> +void osd_req_flush_object(struct osd_request *,
>> + const struct osd_obj_id *, enum osd_options_flush_scope_values,
>> + /*V2*/ u64 offset, /*V2*/ u64 len);
>> +
>> +void osd_req_read(struct osd_request *,
>> + 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 *, const struct osd_obj_id *);
>> +
>> +/* set before get */
>> +void osd_req_set_attributes(struct osd_request *, 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 *,
>> + const struct osd_attr *, unsigned nelem);
>> +
>> +/* get a list of attributes */
>> +int osd_req_add_get_attr_list(struct osd_request *,
>> + 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 *,
>> + 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 *,
>> + 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..77a74a3
>> --- /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 <[email protected]>
>> + * Benny Halevy <[email protected]>
>> + *
>> + * 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;
>> + } __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;
>> + } __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[80-62];
>> + } __packed attrs_cdb;
>> +/*52*/ u8 get_set_attributes_parameters[80-52];
>> + };
>> +} __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 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 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 [email protected] */
>> +} __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 = (1 << 0),
>> + OSD_SEC_CAP_OBJ_MGMT = (1 << 1),
>> + OSD_SEC_CAP_REMOVE = (1 << 2),
>> + OSD_SEC_CAP_CREATE = (1 << 3),
>> + OSD_SEC_CAP_SET_ATTR = (1 << 4),
>> + OSD_SEC_CAP_GET_ATTR = (1 << 5),
>> + OSD_SEC_CAP_WRITE = (1 << 6),
>> + OSD_SEC_CAP_READ = (1 << 7),
>> +
>> + OSD_SEC_CAP_NONE1 = (1 << 8),
>> + OSD_SEC_CAP_NONE2 = (1 << 9),
>> + OSD_SEC_CAP_NONE3 = (1 << 10),
>> + OSD_SEC_CAP_QUERY = (1 << 11), /*v2 only*/
>> + OSD_SEC_CAP_M_OBJECT = (1 << 12), /*v2 only*/
>> + OSD_SEC_CAP_POL_SEC = (1 << 13),
>> + OSD_SEC_CAP_GLOBAL = (1 << 14),
>> + OSD_SEC_CAP_DEV_MGMT = (1 << 15),
>
> These could use BIT(nr) from bitops.h.
>
Thanks. It looks much better with this macro.

>> +};
>> +
>> +/* 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[30-10];
>> +/*30*/ u8 discriminator[42-30];
>> +/*42*/ struct osd_timestamp object_created_time;
>> +/*48*/ u8 object_type;
>> + u8 permissions_bit_mask[54-49];
>
> The offset comments are OK with me, but please lose the [b-a] length specifiers.
>

I would, please, like to keep them. For the user it does not matter.
Because he is not suppose to care if he is doing:
- memset(och->permissions_bit_mask, 0, 5); // BAD
+ memset(och->permissions_bit_mask, 0, sizeof(och->permissions_bit_mask)); // GOOD

But for the protocol reader / debuggerer this is much easier since this is the
way he will see them on the wire and the way it is laid out in the standard text.

It was much easier to read the standard text and develop the header this way, complicated
by the fact that OSD v2 was a moving target and the changes from OSD v1. And it helped in
finding bugs. Now to go over all of them and calculate the difference and remove it. I'm
loosing information, and I feel sad to loose it.

But if you are totally not convinced I will remove them?

>
>> +/*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;
>> +
>> + u8 object_descriptor[80-56];/*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__ */
>
> ---
> ~Randy

Thanks
Boaz

2008-11-12 13:14:01

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 03/18 ver3] libosd: OSDv1 Headers


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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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..ce678c5
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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;
+ } __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;
+ } __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[80-62];
+ } __packed attrs_cdb;
+/*52*/ u8 get_set_attributes_parameters[80-52];
+ };
+} __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 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 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 [email protected] */
+} __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[30-10];
+/*30*/ u8 discriminator[42-30];
+/*42*/ struct osd_timestamp object_created_time;
+/*48*/ u8 object_type;
+ u8 permissions_bit_mask[54-49];
+/*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;
+
+ u8 object_descriptor[80-56];/*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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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..ea5372d
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 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

2008-11-12 16:51:11

by Randy Dunlap

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver2] libosd: OSDv1 Headers

Boaz Harrosh wrote:
>
> Thank you Randy for your review, I will post a fixed
> patch shortly. I have changed according to your comments
> except in one place, see arguments below.
>
>>> ---
>>> 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

>>> +/**
>> Don't start comment blocks with /** when they are not kernel-doc,
>> like this one is not.
>>
>
> OK, I must confess my kernel-doc total ignorance. I was imagining that
> each source file's kernel-doc comments are collected into an html file.
> I thought that this comment will be like an introduction to the following
> function-by-function reference. Anyway it's fixed

You can choose to have comments included in the kernel-doc's collected
output. You do this by using this notation:

/** DOC <topic_name>:
* <these lines are added to kernel-doc output when you use:
!P<filename> <topic_name>
* a Documentation/DocBook/*.tmpl file.
*/

See Documentation/DocBook/mac80211.tmpl for examples.

Johannes, I thought that you had some usage documentation for DOC:.
Did you not or did it not get merged??
It needs to be added to Documentation/kernel-doc-nano-HOWTO.txt.


>>> + * 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.
>>> + */

>>> +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
>>> + * the block-layer
>> Function name and short description need to be on one line.
>>
>
> OK I re-worded so it will fit in one line. What happens if it does not
> fit, both name and description, in 80 characters? is there a continuation
> symbol or something?

Nope. It can (a) be longer than 80 characters (an exception is made here)
or (b) split up like this:

/**
* func_name - some short description here
* @prm1: prm1 description
* @prmn: prmn description
*
* <longer function description here>
*/

>>> + * @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);

>>> diff --git a/include/scsi/osd_protocol.h b/include/scsi/osd_protocol.h
>>> new file mode 100644
>>> index 0000000..77a74a3
>>> --- /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 <[email protected]>
>>> + * Benny Halevy <[email protected]>
>>> + *
>>> + * 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>

...

>>> +/* (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[30-10];
>>> +/*30*/ u8 discriminator[42-30];
>>> +/*42*/ struct osd_timestamp object_created_time;
>>> +/*48*/ u8 object_type;
>>> + u8 permissions_bit_mask[54-49];
>> The offset comments are OK with me, but please lose the [b-a] length specifiers.
>>
>
> I would, please, like to keep them. For the user it does not matter.
> Because he is not suppose to care if he is doing:
> - memset(och->permissions_bit_mask, 0, 5); // BAD
> + memset(och->permissions_bit_mask, 0, sizeof(och->permissions_bit_mask)); // GOOD
>
> But for the protocol reader / debuggerer this is much easier since this is the
> way he will see them on the wire and the way it is laid out in the standard text.
>
> It was much easier to read the standard text and develop the header this way, complicated
> by the fact that OSD v2 was a moving target and the changes from OSD v1. And it helped in
> finding bugs. Now to go over all of them and calculate the difference and remove it. I'm
> loosing information, and I feel sad to loose it.
>
> But if you are totally not convinced I will remove them?

I've debugged plenty of code so I'll respectfully disagree with you.
It's confusing and ugly. But I don't control whether it is merged upstream
or not.

>>> +/*54*/ u8 reserved2;
>>> +/*55*/ u8 object_descriptor_type; /* high nibble */
>>> +} __packed;

--
~Randy

2008-11-12 17:09:53

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver2] libosd: OSDv1 Headers

Randy Dunlap wrote:
> Boaz Harrosh wrote:
>> Thank you Randy for your review, I will post a fixed
>> patch shortly. I have changed according to your comments
>> except in one place, see arguments below.
>>
>>>> ---
>>>> 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
>
>>>> +/**
>>> Don't start comment blocks with /** when they are not kernel-doc,
>>> like this one is not.
>>>
>> OK, I must confess my kernel-doc total ignorance. I was imagining that
>> each source file's kernel-doc comments are collected into an html file.
>> I thought that this comment will be like an introduction to the following
>> function-by-function reference. Anyway it's fixed
>
> You can choose to have comments included in the kernel-doc's collected
> output. You do this by using this notation:
>
> /** DOC <topic_name>:
> * <these lines are added to kernel-doc output when you use:
> !P<filename> <topic_name>
> * a Documentation/DocBook/*.tmpl file.
> */
>
> See Documentation/DocBook/mac80211.tmpl for examples.
>
> Johannes, I thought that you had some usage documentation for DOC:.
> Did you not or did it not get merged??
> It needs to be added to Documentation/kernel-doc-nano-HOWTO.txt.
>

OK Thanks I'll give it a shot

<snip>
>>>> +/**
>>>> + * osd_execute_request - Execute the request synchronously through
>>>> + * the block-layer
>>> Function name and short description need to be on one line.
>>>
>> OK I re-worded so it will fit in one line. What happens if it does not
>> fit, both name and description, in 80 characters? is there a continuation
>> symbol or something?
>
> Nope. It can (a) be longer than 80 characters (an exception is made here)
> or (b) split up like this:
>
> /**
> * func_name - some short description here
> * @prm1: prm1 description
> * @prmn: prmn description
> *
> * <longer function description here>
> */
>

OK So I guess I took (b). Thanks.

<snip>
>>>> +/* (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[30-10];
>>>> +/*30*/ u8 discriminator[42-30];
>>>> +/*42*/ struct osd_timestamp object_created_time;
>>>> +/*48*/ u8 object_type;
>>>> + u8 permissions_bit_mask[54-49];
>>> The offset comments are OK with me, but please lose the [b-a] length specifiers.
>>>
>> I would, please, like to keep them. For the user it does not matter.
>> Because he is not suppose to care if he is doing:
>> - memset(och->permissions_bit_mask, 0, 5); // BAD
>> + memset(och->permissions_bit_mask, 0, sizeof(och->permissions_bit_mask)); // GOOD
>>
>> But for the protocol reader / debuggerer this is much easier since this is the
>> way he will see them on the wire and the way it is laid out in the standard text.
>>
>> It was much easier to read the standard text and develop the header this way, complicated
>> by the fact that OSD v2 was a moving target and the changes from OSD v1. And it helped in
>> finding bugs. Now to go over all of them and calculate the difference and remove it. I'm
>> loosing information, and I feel sad to loose it.
>>
>> But if you are totally not convinced I will remove them?
>
> I've debugged plenty of code so I'll respectfully disagree with you.
> It's confusing and ugly. But I don't control whether it is merged upstream
> or not.
>

If it's "confusing and ugly" then that's bad. I guess I'm so much into the
standard-text, that I like it this way, but not so for an onlooker.
I'll change it. Last thing I want is ugly confusing code.

Thanks again
Boaz

2008-11-12 17:16:25

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver2] libosd: OSDv1 Headers

On Wed, 2008-11-12 at 08:48 -0800, Randy Dunlap wrote:

> /** DOC <topic_name>:
> * <these lines are added to kernel-doc output when you use:
> !P<filename> <topic_name>
> * a Documentation/DocBook/*.tmpl file.
> */
>
> See Documentation/DocBook/mac80211.tmpl for examples.
>
> Johannes, I thought that you had some usage documentation for DOC:.
> Did you not or did it not get merged??
> It needs to be added to Documentation/kernel-doc-nano-HOWTO.txt.

I honestly don't remember! Grepping through all my old patches didn't
find anything though, so I suspect I didn't have anything.

johannes


Attachments:
signature.asc (836.00 B)
This is a digitally signed message part

2008-11-12 19:01:42

by Randy Dunlap

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver3] libosd: OSDv1 Headers

On Wed, 12 Nov 2008 15:13:59 +0200 Boaz Harrosh wrote:

>
> 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 <[email protected]>
> Reviewed-by: Benny Halevy <[email protected]>
> ---
> 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_protocol.h b/include/scsi/osd_protocol.h
> new file mode 100644
> index 0000000..ce678c5
> --- /dev/null
> +++ b/include/scsi/osd_protocol.h
> @@ -0,0 +1,497 @@
> +#ifndef __OSD_PROTOCOL_H__
> +#define __OSD_PROTOCOL_H__

...

> +/* 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;
> + } __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;
> + } __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[80-62];

ugh

> + } __packed attrs_cdb;
> +/*52*/ u8 get_set_attributes_parameters[80-52];

ugh

> + };
> +} __packed;
> +/*80*/


> +/* (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[30-10];
> +/*30*/ u8 discriminator[42-30];
> +/*42*/ struct osd_timestamp object_created_time;
> +/*48*/ u8 object_type;
> + u8 permissions_bit_mask[54-49];

more of the same

> +/*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;
> +
> + u8 object_descriptor[80-56];/*24*/

ditto. nice comment ;)

> + };
> +} __packed;
> +/*80 v1*/
> +
> +#endif /* ndef __OSD_PROTOCOL_H__ */


Thanks for the fixes.

---
~Randy

2008-11-13 09:38:40

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver3] libosd: OSDv1 Headers

Randy Dunlap wrote:
>
> ugh
>
>> + } __packed attrs_cdb;
>> +/*52*/ u8 get_set_attributes_parameters[80-52];
>
> ugh
>
>
> more of the same
>
>
> ditto. nice comment ;)
>
>
>
> Thanks for the fixes.
>

Yes Yes that was version 3 where I was asking if I might convince you
for its merits.

As I said in that reply I will change it. Just did not have the chance
to send out version 4 out yet.

Thanks
Boaz

2008-11-13 12:25:34

by Boaz Harrosh

[permalink] [raw]
Subject: [PATCH 03/18 ver4] libosd: OSDv1 Headers


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 <[email protected]>
Reviewed-by: Benny Halevy <[email protected]>
---
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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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..eeb899b
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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 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 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 [email protected] */
+} __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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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..ea5372d
--- /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 <[email protected]>
+ * Benny Halevy <[email protected]>
+ *
+ * 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__c6e00c1
+
+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 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

2008-11-13 18:18:33

by Randy Dunlap

[permalink] [raw]
Subject: Re: [PATCH 03/18 ver4] libosd: OSDv1 Headers

On Thu, 13 Nov 2008 14:25:35 +0200 Boaz Harrosh wrote:

> 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 <[email protected]>
> Reviewed-by: Benny Halevy <[email protected]>

OK by me. Thanks for the changes.

> ---
> 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

---
~Randy

2008-11-13 22:41:23

by Benny Halevy

[permalink] [raw]
Subject: Re: [osd-dev] [PATCH 03/18 ver4] libosd: OSDv1 Headers

Acked-and-liked-by me too :-)

Benny

On Nov. 13, 2008, 20:16 +0200, Randy Dunlap <[email protected]> wrote:
> On Thu, 13 Nov 2008 14:25:35 +0200 Boaz Harrosh wrote:
>
>> 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 <[email protected]>
>> Reviewed-by: Benny Halevy <[email protected]>
>
> OK by me. Thanks for the changes.
>
>> ---
>> 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
>
> ---
> ~Randy
> _______________________________________________
> osd-dev mailing list
> [email protected]
> http://mailman.open-osd.org/mailman/listinfo/osd-dev

2008-11-26 17:33:40

by Boaz Harrosh

[permalink] [raw]
Subject: Re: [osd-dev] [PATCH 01/18] major.h: char-major number for OSD device driver

Boaz Harrosh wrote:
> 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 <[email protected]>
> CC: Torben Mathiasen <[email protected]>

Hi Torben Mathiasen

The maintainers file as well as the lanana.org website only states
this <[email protected]> email address. I hope it is the right one.

Please you have not confirmed or revoked my ability to use 260
as a Major for a new char-device. Please review

What git tree should this go through?

Thanks
Boaz

> ---
> 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 05c8064..d18070b 100644
> --- a/Documentation/devices.txt
> +++ b/Documentation/devices.txt
> @@ -3142,6 +3142,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

2008-11-26 18:08:47

by Randy Dunlap

[permalink] [raw]
Subject: Re: [osd-dev] [PATCH 01/18] major.h: char-major number for OSD device driver

Boaz Harrosh wrote:
> Boaz Harrosh wrote:
>> 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 <[email protected]>
>> CC: Torben Mathiasen <[email protected]>
>
> Hi Torben Mathiasen
>
> The maintainers file as well as the lanana.org website only states
> this <[email protected]> email address. I hope it is the right one.
>
> Please you have not confirmed or revoked my ability to use 260
> as a Major for a new char-device. Please review

Was it cc-ed to [email protected]? I can't see that. Adding it now.

John Cagle, can you comment on this, please?

And also have the attached patch merged into the MAINTAINERS file, please.

The http://www.lanana.org web page also needs to be updated:
Maintained by Torben Mathiasen
is no longer correct.


> What git tree should this go through?
>
> Thanks
> Boaz
>
>> ---
>> 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 05c8064..d18070b 100644
>> --- a/Documentation/devices.txt
>> +++ b/Documentation/devices.txt
>> @@ -3142,6 +3142,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
>


--
~Randy


Attachments:
maint-update-lanana.patch (547.00 B)