[PATCHSET 00/18] open-osd: OSD Initiator library for Linux - Kernel

This is a discussion on [PATCHSET 00/18] open-osd: OSD Initiator library for Linux - Kernel ; 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 ...

+ Reply to Thread
Page 1 of 3 1 2 3 LastLast
Results 1 to 20 of 53

Thread: [PATCHSET 00/18] open-osd: OSD Initiator library for Linux

  1. [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...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....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-s...8-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

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

  2. [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
    Reviewed-by: Benny Halevy
    ---
    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
    + * Benny Halevy
    + *
    + * 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
    +
    +#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
    + * Benny Halevy
    + *
    + * 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
    +#include
    +#include
    +
    +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 bharrosh@panasas.com */
    +} __packed;
    +
    +/* for osd_capability.format */
    +enum {
    + OSD_SEC_CAP_FORMAT_NO_CAPS = 0,
    + OSD_SEC_CAP_FORMAT_VER1 = 1,
    + OSD_SEC_CAP_FORMAT_VER2 = 2,
    +};
    +
    +/* security_method */
    +enum {
    + OSD_SEC_NOSEC = 0,
    + OSD_SEC_CAPKEY = 1,
    + OSD_SEC_CMDRSP = 2,
    + OSD_SEC_ALLDATA = 3,
    +};
    +
    +enum object_type {
    + OSD_SEC_OBJ_ROOT = 0x1,
    + OSD_SEC_OBJ_PARTITION = 0x2,
    + OSD_SEC_OBJ_COLLECTION = 0x40,
    + OSD_SEC_OBJ_USER = 0x80,
    +};
    +
    +enum osd_capability_bit_masks {
    + OSD_SEC_CAP_APPEND = (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
    + * Benny Halevy
    + *
    + * 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
    + * Benny Halevy
    + *
    + * 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

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

  3. [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
    Reviewed-by: Benny Halevy
    ---
    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
    +# Benny Halevy
    +#
    +# 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

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

  4. [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
    Reviewed-by: Benny Halevy
    ---
    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
    +# Benny Halevy
    +#
    +# 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
    +# Benny Halevy
    +#
    +# 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
    + * Benny Halevy
    + *
    + * 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
    + * Benny Halevy
    + *
    + * 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
    +#include
    +#include
    +
    +#include "osd_debug.h"
    +
    +enum { OSD_REQ_RETRIES = 1 };
    +
    +#ifdef CONFIG_SCSI_OSD_INITIATOR_MODULE
    +MODULE_AUTHOR("Boaz Harrosh ");
    +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

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

  5. [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
    ---
    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
    + * Benny Halevy
    + *
    + * 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
    +#include
    +#include
    +#include
    +
    +#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

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

  6. [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
    Reviewed-by: Benny Halevy
    ---
    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: orinoco-devel@lists.sourceforge.net
    W: http://www.nongnu.org/orinoco/
    S: Maintained

    +OSD LIBRARY
    +P: Boaz Harrosh
    +M: bharrosh@panasas.com
    +P: Benny Halevy
    +M: bhalevy@panasas.com
    +L: osd-dev@open-osd.org
    +W: http://open-osd.org
    +T: git://git.open-osd.org/osd-lib.git
    +S: Maintained
    +
    P54 WIRELESS DRIVER
    P: Michael Wu
    M: flamingice@sourmilk.net
    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

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

  7. [PATCH 02/18] scsi: OSD_TYPE

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

    Signed-off-by: Boaz Harrosh
    ---
    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

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

  8. [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
    Reviewed-by: Benny Halevy
    ---
    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

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

  9. [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
    Reviewed-by: Benny Halevy
    ---
    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
    #include
    +#include
    #include

    #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

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

  10. [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
    Reviewed-by: Benny Halevy
    ---
    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

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

  11. [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
    ---
    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
    #include
    #include
    #include
    @@ -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

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

  12. [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
    Reviewed-by: Benny Halevy
    ---
    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
    + * Benny Halevy
    + *
    + * 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
    +#include
    +#include
    +
    +#include
    +#include
    +
    +#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

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

  13. [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
    Reviewed-by: Benny Halevy
    ---
    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
    #include
    +#include

    #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

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

  14. [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
    Reviewed-by: Benny Halevy
    ---
    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

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

  15. [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
    Reviewed-by: Benny Halevy
    ---
    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

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

  16. [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
    Reviewed-by: Benny Halevy
    ---
    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
    + * Benny Halevy
    + *
    + * 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
    + * Benny Halevy
    + *
    + * 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
    +#include
    +#include
    +#include
    +#include
    +#include
    +
    +#include
    +#include
    +#include
    +#include
    +
    +#include
    +#include
    +
    +#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 ");
    +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

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

  17. [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
    Reviewed-by: Benny Halevy
    ---
    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

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

  18. [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
    CC: Torben Mathiasen
    ---
    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

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

  19. 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
    > Reviewed-by: Benny Halevy
    > ---
    > 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
    > +# Benny Halevy
    > +#
    > +# 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 ");
    > +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.


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

  20. Re: [PATCH 04/18] libosd: OSDv1 preliminary implementation

    On Tue, 4 Nov 2008 18:44:29 +0200
    Boaz Harrosh 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.


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

+ Reply to Thread
Page 1 of 3 1 2 3 LastLast