open-osd: OSD Initiator library for 2.6.30
Subsystems (3)
cover open-osd: OSD Initiator library for 2.6.30
James hi.
Since we missed the 2.6.29 merge window, sigh, I'm taking the opportunity to refresh the patchset. It's basically the same, but for a few changes listed below:
- Exact same submitted code is now compilable as a user-mode library so utilities like exofs.mkfs can be compiled as regular application. When compiling in user-mode using my preferred -W switches to gcc I've unearthed little warnings, which are now fixed. Mainly:
* signed/unsigned comparison
* char * pointing to a const string (This one is grave in my opinion)
* more missing statics.
* ...
- I have added an API to the osd_uld for test modules to register an ioctl test vector. In the last patchset, as requested, I have removed the tests code from upstream submission. This meant that the out-of-tree git was patching the osd_uld.c and Kbuild kernel files in-order to add the tests. This is an administrative night-mare both for developers and users alike. Since they must patch their running kernel and install/replace distro modules. So I put the osd_ktests.c code in its own module and enable it to register at run-time into the running osd_uld, though injecting tests into running code.
Please take these patches off my hands this time ASAP, and let them rot in scsi-misc until 2.6.30 merge-window ;)
[A patch is attached that showed what was changed from last time.]
---
here is the usual stuff for first-time viewers
OSD (Object-Based Storage Device) is a T10 SCSI command set that is designed to provide efficient operation of input/output logical units that manage the allocation, placement, and accessing of variable-size data-storage containers, called objects. Objects are intended to contain operating system and application constructs. Each object has associated attributes attached to it, which are integral part of the object and provide metadata about the object. The standard defines some common obligatory attributes, but user attributes can be added as needed.
The patches are cut over scsi-misc-2.6-7e106029 but apply cleanly over Linus git.
To try out and run the library please visit
http://open-osd.org and follow the instructions there.
The submitted patchset is also available via git at:
git://git.open-osd.org/linux-open-osd.git osd
http://git.open-osd.org/gitweb.cgi?p=linux-open-osd.git;a=shortlog;h=osd
here is the list of patches:
[PATCH 01/16] major.h: char-major number for OSD device driver
Request for a new char-device major number
[PATCH 02/16] scsi: OSD_TYPE
The OSD scsi type constant definition.
[PATCH 03/16] libosd: OSDv1 Headers
[PATCH 04/16] libosd: OSDv1 preliminary implementation
Most basic, but usable library module (libosd.ko) including Kbuild file.
[PATCH 05/16] osd_uld: OSD scsi ULD
[PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel
These patches add a scsi ULD for OSD type devices. Please see commit logs for details.
[PATCH 07/16] libosd: attributes Support
[PATCH 08/16] libosd: OSD Security processing stubs
[PATCH 09/16] libosd: Add Flush and List-objects support [PATCH 10/16] libosd: Not implemented commands
[PATCH 11/16] libosd: OSD version 2 Support
[PATCH 12/16] libosd: OSDv2 auto detection
[PATCH 13/16] libosd: SCSI/OSD Sense decoding support
Up to here this is a fairly complete body of work, to support both OSD1 and OSD2 targets. Main pieces that are still missing from the library at this point are: The OSD2 capabilities structure, do to lack of an OSD target that supports it. And the absence of any OSD-security methods other then NO_SECURITY. These will come in future versions.
[PATCH 14/16] osd: Documentation for OSD library
Some reading about OSD in general and further usability instructions. Please comment on anything missing from this document.
[PATCH 15/16] osd: Kconfig file for in-tree builds
[PATCH 16/16] scsi: Add osd library to build system
The in-tree compilation is only enabled at the end of the patchset. Run your favorite configure-tool to enable the library and osd_uld compilation. Default is off.
The patchset is however fully bisectable, and compilable from the beginning, (by applying these 2 patches first).
The open-osd team
Boaz Harrosh
git diff --stat -p -R 2abc3b5d42d4c16e57d8fdd2e3475402f10d468b 95256f25df7dc7e18f0e8652b6a0309913d4dabe
drivers/scsi/osd/Kbuild | 8 +++- drivers/scsi/osd/osd_initiator.c | 48 ++++++++++++++---------- drivers/scsi/osd/osd_ktests.c | 75 +++++++++++++++++++++++++++++--------- drivers/scsi/osd/osd_ktests.h | 4 +-- drivers/scsi/osd/osd_uld.c | 44 +++++++++++++++++++---- include/scsi/osd_initiator.h | 5 +++ 6 files changed, 134 insertions(+), 50 deletions(-)
drivers/scsi/osd/Kbuild +6 -2
@@ -32,7 +32,11 @@ ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1 # if we are built out-of-tree and the hosting kernel has OSD headers # then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing # this it will work. This might break in future kernels -KBUILD_CPPFLAGS := -I$(OSD_INC) $(KBUILD_CPPFLAGS) +LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE) + +# osd_ktests.ko is only built out of tree +# see git://git.open-osd.org open-osd for latest code +obj-m += osd_ktests.o endif
@@ -41,5 +45,5 @@ libosd-y := osd_initiator.o obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o # osd.ko - SCSI ULD and char-device -osd-y := osd_uld.o osd_ktests.o +osd-y := osd_uld.o obj-$(CONFIG_SCSI_OSD_ULD) += osd.o
drivers/scsi/osd/osd_initiator.c +28 -20
139 lines not on this page · raw message
drivers/scsi/osd/osd_ktests.c +57 -18
195 lines not on this page · raw message
drivers/scsi/osd/osd_ktests.h +1 -3
@@ -24,8 +24,6 @@enum {OSD_TEST_ALL =17 }; -#ifdef __KERNEL__ -extern int do_test_17 (struct osd_dev *od); -#endif /* __KERNEL__ */ +int do_test_17 (struct osd_dev *od,unsigned cmd,unsigned long arg);#endif /*ndef __OSD_KTESTS_H__*/
drivers/scsi/osd/osd_uld.c +37 -7
62 lines not on this page · raw message
include/scsi/osd_initiator.h +5 -0
@@ -58,6 +58,11 @@ struct osd_dev {struct osd_dev *osduld_path_lookup (const char *dev_name);/*Use IS_ERR/ERR_PTR*/ void osduld_put_device (struct osd_dev *od); +/* Add/remove test ioctls from external modules */ +typedef int (do_test_fn )(struct osd_dev *od,unsigned cmd,unsigned long arg); +int osduld_register_test (unsigned ioctl,do_test_fn *do_test); +void osduld_unregister_test (unsigned ioctl); +/* These are called by uld at probe time */ void osd_dev_init (struct osd_dev *od,struct scsi_device *scsi_device);void osd_dev_fini (struct osd_dev *od);
PATCH 1/16 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)
--- Documentation/devices.txt | 6 ++++++ include/linux/major.h | 1 + 2 files changed, 7 insertions(+), 0 deletions(-)
Documentation/devices.txt +6 -0
@@ -3145,6 +3145,12 @@ Your cooperation is appreciated. 1 = /dev/blockrom1 Second ROM card's translation layer interface ... +260 char OSD (Object-based-device) SCSI Device + 0 = /dev/osd0 First OSD Device + 1 = /dev/osd1 Second OSD Device + ... + 255 = /dev/osd255 256th OSD Device + **** ADDITIONAL /dev DIRECTORY ENTRIES This section details additional entries that should or may exist in
include/linux/major.h +1 -0
@@ -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
Signature · 1 line
1.6.0.1
PATCH 2/16 scsi: OSD_TYPE
In reply to Boaz Harrosh- Define the OSD_TYPE scsi device and let it show up in scans
--- drivers/scsi/scsi_scan.c | 1 + include/scsi/scsi.h | 1 + 2 files changed, 2 insertions(+), 0 deletions(-)
drivers/scsi/scsi_scan.c +1 -0
@@ -796,6 +796,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,case TYPE_ENCLOSURE :case TYPE_COMM :case TYPE_RAID : +case TYPE_OSD : sdev->writeable =1 ;break ;case TYPE_ROM :
include/scsi/scsi.h +1 -0
@@ -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 */
Signature · 1 line
1.6.0.1
PATCH 3/16 libosd: OSDv1 Headers
In reply to Boaz HarroshHeaders only patch.
osd_protocol.h
Contains a C-fied definition of the T10 OSD standardosd_types.h
Contains CPU order common used typesosd_initiator.h
API definition of the osd_initiator libraryosd_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]
--- 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
include/scsi/osd_initiator.h new file +332 -0
@@ -0,0 +1,332 @@ +/* +* osd_initiator.h - OSD initiator API definition +* +* Copyright (C) 2008 Panasas Inc. All rights reserved. +* +* Authors: +* Boaz Harrosh <[email protected]> +* Benny Halevy <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 +* +*/ +#ifndef __OSD_INITIATOR_H__ +#define __OSD_INITIATOR_H__ + +#include "osd_protocol.h" +#include "osd_types.h" + +#include <linux/blkdev.h> + +/* Note: "NI" in comments below means "Not Implemented yet" */ + +/* +* Object-based Storage Device. +* This object represents an OSD device. +* It is not a full linux device in any way. It is only +* a place to hang resources associated with a Linux +* request Q and some default properties. +*/ +struct osd_dev { +struct scsi_device *scsi_device; +unsigned def_timeout; +}; + +void osd_dev_init (struct osd_dev *od,struct scsi_device *scsi_device); +void osd_dev_fini (struct osd_dev *od); + +struct osd_request ; +typedef void (osd_req_done_fn )(struct osd_request *or,void *private); + +struct osd_request { +struct osd_cdb cdb; +struct osd_data_out_integrity_info out_data_integ; +struct osd_data_in_integrity_info in_data_integ; + +struct osd_dev *osd_dev; +struct request *request; + +struct _osd_req_data_segment { +void *buff; +unsigned alloc_size;/* 0 here means: don't call kfree */ +unsigned total_bytes; + } set_attr, enc_get_attr, get_attr; + +struct _osd_io_info { +struct bio *bio; +u64 total_bytes; +struct request *req; +struct _osd_req_data_segment *last_seg; +u8 *pad_buff; + } out, in; + +gfp_t alloc_flags; +unsigned timeout; +unsigned retries; +u8 sense[OSD_MAX_SENSE_LEN ]; +enum osd_attributes_mode attributes_mode; + +osd_req_done_fn *async_done; +void *async_private; +int async_error; +}; + +/* +* How to use the osd library: +* +* osd_start_request +* Allocates a request. +* +* osd_req_* +* Call one of, to encode the desired operation. +* +* osd_add_{get,set}_attr +* Optionally add attributes to the CDB, list or page mode. +* +* osd_finalize_request +* Computes final data out/in offsets and signs the request, +* making it ready for execution. +* +* osd_execute_request +* May be called to execute it through the block layer. Other wise submit +* the associated block request in some other way. +* +* After execution: +* osd_req_decode_sense +* Decodes sense information to verify execution results. +* +* osd_req_decode_get_attr +* Retrieve osd_add_get_attr_list() values if used. +* +* osd_end_request +* Must be called to deallocate the request. +*/ + +/** +* osd_start_request - Allocate and initialize an osd_request +* +* @osd_dev: OSD device that holds the scsi-device and default values +* that the request is associated with. +* @gfp: The allocation flags to use for request allocation, and all +* subsequent allocations. This will be stored at +* osd_request->alloc_flags, can be changed by user later +* +* Allocate osd_request and initialize all members to the +* default/initial state. +*/ +struct osd_request *osd_start_request (struct osd_dev *od,gfp_t gfp); + +enum osd_req_options { +OSD_REQ_FUA =0x08 ,/* Force Unit Access */ +OSD_REQ_DPO =0x10 ,/* Disable Page Out */ + +OSD_REQ_BYPASS_TIMESTAMPS =0x80 , +}; + +/** +* osd_finalize_request - Sign request and prepare request for execution +* +* @or: osd_request to prepare +* @options: combination of osd_req_options bit flags or 0. +* @cap: A Pointer to an OSD_CAP_LEN bytes buffer that is received from +* The security manager as capabilities for this cdb. +* @cap_key: The cryptographic key used to sign the cdb/data. Can be null +* if NOSEC is used. +* +* The actual request and bios are only allocated here, so are the get_attr +* buffers that will receive the returned attributes. Copy's @cap to cdb. +* Sign the cdb/data with @cap_key. +*/ +int osd_finalize_request (struct osd_request *or, +u8 options,const void *cap,const u8 *cap_key); + +/** +* osd_execute_request - Execute the request synchronously through block-layer +* +* @or: osd_request to Executed +* +* Calls blk_execute_rq to q the command and waits for completion. +*/ +int osd_execute_request (struct osd_request *or); + +/** +* osd_execute_request_async - Execute the request without waitting. +* +* @or: - osd_request to Executed +* @done: (Optional) - Called at end of execution +* @private: - Will be passed to @done function +* +* Calls blk_execute_rq_nowait to queue the command. When execution is done +* optionally calls @done with @private as parameter. @or->async_error will +* have the return code +*/ +int osd_execute_request_async (struct osd_request *or, +osd_req_done_fn *done,void *private); + +/** +* osd_end_request - return osd_request to free store +* +* @or: osd_request to free +* +* Deallocate all osd_request resources (struct req's, BIOs, buffers, etc.) +*/ +void osd_end_request (struct osd_request *or); + +/* +* CDB Encoding +* +* Note: call only one of the following methods. +*/ + +/* +* Device commands +*/ +void osd_req_set_master_seed_xchg (struct osd_request *or, ...);/* NI */ +void osd_req_set_master_key (struct osd_request *or, ...);/* NI */ + +void osd_req_format (struct osd_request *or,u64 tot_capacity); + +/* list all partitions +* @list header must be initialized to zero on first run. +* +* Call osd_is_obj_list_done() to find if we got the complete list. +*/ +int osd_req_list_dev_partitions (struct osd_request *or, +osd_id initial_id,struct osd_obj_id_list *list,unsigned nelem); + +void osd_req_flush_obsd (struct osd_request *or, +enum osd_options_flush_scope_values ); + +void osd_req_perform_scsi_command (struct osd_request *or, +const u8 *cdb, ...);/* NI */ +void osd_req_task_management (struct osd_request *or, ...);/* NI */ + +/* +* Partition commands +*/ +void osd_req_create_partition (struct osd_request *or,osd_id partition); +void osd_req_remove_partition (struct osd_request *or,osd_id partition); + +void osd_req_set_partition_key (struct osd_request *or, +osd_id partition,u8 new_key_id[OSD_CRYPTO_KEYID_SIZE ], +u8 seed[OSD_CRYPTO_SEED_SIZE ]);/* NI */ + +/* list all collections in the partition +* @list header must be init to zero on first run. +* +* Call osd_is_obj_list_done() to find if we got the complete list. +*/ +int osd_req_list_partition_collections (struct osd_request *or, +osd_id partition,osd_id initial_id,struct osd_obj_id_list *list, +unsigned nelem); + +/* list all objects in the partition +* @list header must be init to zero on first run. +* +* Call osd_is_obj_list_done() to find if we got the complete list. +*/ +int osd_req_list_partition_objects (struct osd_request *or, +osd_id partition,osd_id initial_id,struct osd_obj_id_list *list, +unsigned nelem); + +void osd_req_flush_partition (struct osd_request *or, +osd_id partition,enum osd_options_flush_scope_values ); + +/* +* Collection commands +*/ +void osd_req_create_collection (struct osd_request *or, +const struct osd_obj_id *);/* NI */ +void osd_req_remove_collection (struct osd_request *or, +const struct osd_obj_id *);/* NI */ + +/* list all objects in the collection */ +int osd_req_list_collection_objects (struct osd_request *or, +const struct osd_obj_id *,osd_id initial_id, +struct osd_obj_id_list *list,unsigned nelem); + +/* V2 only filtered list of objects in the collection */ +void osd_req_query (struct osd_request *or, ...);/* NI */ + +void osd_req_flush_collection (struct osd_request *or, +const struct osd_obj_id *,enum osd_options_flush_scope_values ); + +void osd_req_get_member_attrs (struct osd_request *or, ...);/* V2-only NI */ +void osd_req_set_member_attrs (struct osd_request *or, ...);/* V2-only NI */ + +/* +* Object commands +*/ +void osd_req_create_object (struct osd_request *or,struct osd_obj_id *); +void osd_req_remove_object (struct osd_request *or,struct osd_obj_id *); + +void osd_req_write (struct osd_request *or, +const struct osd_obj_id *,struct bio *data_out,u64 offset); +void osd_req_append (struct osd_request *or, +const struct osd_obj_id *,struct bio *data_out);/* NI */ +void osd_req_create_write (struct osd_request *or, +const struct osd_obj_id *,struct bio *data_out,u64 offset);/* NI */ +void osd_req_clear (struct osd_request *or, +const struct osd_obj_id *,u64 offset,u64 len);/* NI */ +void osd_req_punch (struct osd_request *or, +const struct osd_obj_id *,u64 offset,u64 len);/* V2-only NI */ + +void osd_req_flush_object (struct osd_request *or, +const struct osd_obj_id *,enum osd_options_flush_scope_values , +/*V2*/ u64 offset,/*V2*/ u64 len); + +void osd_req_read (struct osd_request *or, +const struct osd_obj_id *,struct bio *data_in,u64 offset); + +/* +* Root/Partition/Collection/Object Attributes commands +*/ + +/* get before set */ +void osd_req_get_attributes (struct osd_request *or,const struct osd_obj_id *); + +/* set before get */ +void osd_req_set_attributes (struct osd_request *or,const struct osd_obj_id *); + +/* +* Attributes appended to most commands +*/ + +/* Attributes List mode (or V2 CDB) */ +/* +* TODO: In ver2 if at finalize time only one attr was set and no gets, +* then the Attributes CDB mode is used automatically to save IO. +*/ + +/* set a list of attributes. */ +int osd_req_add_set_attr_list (struct osd_request *or, +const struct osd_attr *,unsigned nelem); + +/* get a list of attributes */ +int osd_req_add_get_attr_list (struct osd_request *or, +const struct osd_attr *,unsigned nelem); + +/* +* Attributes list decoding +* Must be called after osd_request.request was executed +* It is called in a loop to decode the returned get_attr +* (see osd_add_get_attr) +*/ +int osd_req_decode_get_attr_list (struct osd_request *or, +struct osd_attr *,int *nelem,void **iterator); + +/* Attributes Page mode */ + +/* +* Read an attribute page and optionally set one attribute +* +* Retrieves the attribute page directly to a user buffer. +* @attr_page_data shall stay valid until end of execution. +* See osd_attributes.h for common page structures +*/ +int osd_req_add_get_attr_page (struct osd_request *or, +u32 page_id,void *attr_page_data,unsigned max_page_len, +const struct osd_attr *set_one); + +#endif /* __OSD_LIB_H__ */
include/scsi/osd_protocol.h new file +497 -0
497 lines not on this page · raw message
include/scsi/osd_sec.h new file +45 -0
45 lines not on this page · raw message
include/scsi/osd_types.h new file +40 -0
@@ -0,0 +1,40 @@ +/* +* osd_types.h - Types and constants which are not part of the protocol. +* +* Copyright (C) 2008 Panasas Inc. All rights reserved. +* +* Authors: +* Boaz Harrosh <[email protected]> +* Benny Halevy <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 +* +* Contains types and constants that are implementation specific and are +* used by more than one part of the osd library. +* (Eg initiator/target/security_manager/...) +*/ +#ifndef __OSD_TYPES_H__ +#define __OSD_TYPES_H__ + +struct osd_systemid { +u8 data[OSD_SYSTEMID_LEN ]; +}; + +typedef u64 __bitwise osd_id ; + +struct osd_obj_id { +osd_id partition; +osd_id id; +}; + +static const struct __weak osd_obj_id osd_root_object = {0 ,0 }; + +struct osd_attr { +u32 attr_page; +u32 attr_id; +u16 len;/* byte count of operand */ +void *val_ptr;/* in network order */ +}; + +#endif /* ndef __OSD_TYPES_H__ */
Signature · 6 lines
1.6.0.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 4/16 libosd: OSDv1 preliminary implementation
In reply to Boaz HarroshImplementation 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
--- drivers/scsi/osd/Kbuild | 32 +++ drivers/scsi/osd/Makefile | 37 +++ drivers/scsi/osd/osd_debug.h | 30 +++ drivers/scsi/osd/osd_initiator.c | 448 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 547 insertions(+), 0 deletions(-) create mode 100644 drivers/scsi/osd/Kbuild create mode 100755 drivers/scsi/osd/Makefile create mode 100644 drivers/scsi/osd/osd_debug.h create mode 100644 drivers/scsi/osd/osd_initiator.c
drivers/scsi/osd/Kbuild new file +32 -0
@@ -0,0 +1,32 @@ +# +# Kbuild for the OSD modules +# +# Copyright (C) 2008 Panasas Inc. All rights reserved. +# +# Authors: +# Boaz Harrosh <[email protected]> +# Benny Halevy <[email protected]> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 +# + +ifneq ($(OSD_INC),) +# we are built out-of-tree Kconfigure everything as on + +CONFIG_SCSI_OSD_INITIATOR=m +ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE + +# Uncomment to turn debug on +# ccflags-y += -DCONFIG_SCSI_OSD_DEBUG + +# if we are built out-of-tree and the hosting kernel has OSD headers +# then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing +# this it will work. This might break in future kernels +LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE) + +endif + +# libosd.ko - osd-initiator library +libosd-y := osd_initiator.o +obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
drivers/scsi/osd/Makefile new file +37 -0
@@ -0,0 +1,37 @@ +# +# Makefile for the OSD modules (out of tree) +# +# Copyright (C) 2008 Panasas Inc. All rights reserved. +# +# Authors: +# Boaz Harrosh <[email protected]> +# Benny Halevy <[email protected]> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 +# +# This Makefile is used to call the kernel Makefile in case of an out-of-tree +# build. +# $KSRC should point to a Kernel source tree otherwise host's default is +# used. (eg. /lib/modules/`uname -r`/build) + +# include path for out-of-tree Headers +OSD_INC ?= `pwd`/../../../include + +# allow users to override these +# e.g. to compile for a kernel that you aren't currently running +KSRC ?= /lib/modules/$(shell uname -r)/build +KBUILD_OUTPUT ?= +ARCH ?= +V ?= 0 + +# this is the basic Kbuild out-of-tree invocation, with the M= option +KBUILD_BASE = +$(MAKE) -C $(KSRC) M=`pwd` KBUILD_OUTPUT=$(KBUILD_OUTPUT) ARCH=$(ARCH) V=$(V) + +all: libosd + +libosd: ; + $(KBUILD_BASE) OSD_INC=$(OSD_INC) modules + +clean: + $(KBUILD_BASE) clean
drivers/scsi/osd/osd_debug.h new file +30 -0
@@ -0,0 +1,30 @@ +/* +* osd_debug.h - Some kprintf macros +* +* Copyright (C) 2008 Panasas Inc. All rights reserved. +* +* Authors: +* Boaz Harrosh <[email protected]> +* Benny Halevy <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 +* +*/ +#ifndef __OSD_DEBUG_H__ +#define __OSD_DEBUG_H__ + +#define OSD_ERR(fmt, a...) printk(KERN_ERR "osd: " fmt, ##a) +#define OSD_INFO(fmt, a...) printk(KERN_NOTICE "osd: " fmt, ##a) + +#ifdef CONFIG_SCSI_OSD_DEBUG +#define OSD_DEBUG(fmt, a...) \ + printk(KERN_NOTICE "osd @%s:%d: " fmt, __func__, __LINE__, ##a) +#else +#define OSD_DEBUG(fmt, a...) do {} while (0) +#endif + +/* u64 has problems with printk this will cast it to unsigned long long */ +#define _LLU (x) (unsigned long long)(x) + +#endif /* ndef __OSD_DEBUG_H__ */
drivers/scsi/osd/osd_initiator.c new file +448 -0
448 lines not on this page · raw message
Signature · 1 line
1.6.0.1
PATCH 5/16 osd_uld: OSD scsi ULD
In reply to Boaz HarroshAdd 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).
--- drivers/scsi/osd/Kbuild | 7 + drivers/scsi/osd/osd_uld.c | 419 ++++++++++++++++++++++++++++++++++++++++++ include/scsi/osd_initiator.h | 6 + 3 files changed, 432 insertions(+), 0 deletions(-) create mode 100644 drivers/scsi/osd/osd_uld.c
drivers/scsi/osd/Kbuild +7 -0
@@ -17,6 +17,9 @@ ifneq ($(OSD_INC),) CONFIG_SCSI_OSD_INITIATOR=m ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE +CONFIG_SCSI_OSD_ULD=m +ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE + # Uncomment to turn debug on # ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
@@ -30,3 +33,7 @@ endif # libosd.ko - osd-initiator library libosd-y := osd_initiator.o obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o + +# osd.ko - SCSI ULD and char-device +osd-y := osd_uld.o +obj-$(CONFIG_SCSI_OSD_ULD) += osd.o
drivers/scsi/osd/osd_uld.c new file +419 -0
419 lines not on this page · raw message
include/scsi/osd_initiator.h +6 -0
@@ -33,6 +33,12 @@ struct osd_dev {unsigned def_timeout; }; +/* Add/remove test ioctls from external modules */ +typedef int (do_test_fn )(struct osd_dev *od,unsigned cmd,unsigned long arg); +int osduld_register_test (unsigned ioctl,do_test_fn *do_test); +void osduld_unregister_test (unsigned ioctl); + +/* These are called by uld at probe time */ void osd_dev_init (struct osd_dev *od,struct scsi_device *scsi_device);void osd_dev_fini (struct osd_dev *od);
Signature · 1 line
1.6.0.1
PATCH 6/16 osd_uld: API for retrieving osd devices from Kernel
In reply to Boaz HarroshKernel clients like exofs can retrieve struct osd_dev(s) by means of below API.
+ osduld_path_lookup() - given a path (e.g "/dev/osd0") locks and returns the corresponding struct osd_dev, which is then needed for subsequent libosd use.
+ osduld_put_device() - free up use of an osd_dev.
Devices can be shared by multiple clients. The osd_uld_device's life time is governed by an embedded kref structure.
The osd_uld_device holds an extra reference to both it's char-device and it's scsi_device, and will release these just before the final deallocation.
There are three possible lock sources of the osd_uld_device
1. First and for most is the probe() function called by scsi-ml upon a successful login into a target. Released in release() when logout.
2. Second by user-mode file handles opened on the char-dev.
3. Third is here by Kernel users.
All three locks must be removed before the osd_uld_device is freed.
The MODULE has three lock sources as well:
1. scsi-ml at probe() time, removed after release(). (login/logout)
2. The user-mode file handles open/close.
3. Import symbols by client modules like exofs.
TODO:
This API is not enough for the pNFS-objects LD. A more versatile API will be needed. Proposed API could be:
struct osd_dev *osduld_sysid_lookup(const char id[OSD_SYSTEMID_LEN]);
--- drivers/scsi/osd/osd_uld.c | 63 ++++++++++++++++++++++++++++++++++++++++++ include/scsi/osd_initiator.h | 4 ++ 2 files changed, 67 insertions(+), 0 deletions(-)
drivers/scsi/osd/osd_uld.c +63 -0
@@ -173,6 +173,69 @@ static const struct file_operations osd_fops = { .unlocked_ioctl = osd_uld_ioctl, }; +struct osd_dev *osduld_path_lookup (const char *path) +{ +struct nameidata nd; +struct inode *inode; +struct cdev *cdev; +struct osd_uld_device *uninitialized_var (oud ); +int error; + +if (!path || !*path) { +OSD_ERR ("Mount with !path || !*path\n" ); +return ERR_PTR (-EINVAL ); + } + + error =path_lookup (path,LOOKUP_FOLLOW , &nd); +if (error) { +OSD_ERR ("path_lookup of %s faild=>%d\n" , path, error); +return ERR_PTR (error); + } + + inode = nd.path.dentry->d_inode; + error = -EINVAL ;/* Not the right device e.g osd_uld_device */ +if (!S_ISCHR (inode->i_mode)) { +OSD_DEBUG ("!S_ISCHR()\n" ); + goto out; + } + + cdev = inode->i_cdev; +if (!cdev) { +OSD_ERR ("Before mounting an OSD Based filesystem\n" ); +OSD_ERR (" user-mode must open+close the %s device\n" , path); +OSD_ERR (" Example: bash: echo < %s\n" , path); + goto out; + } + +/* The Magic wand. Is it our char-dev */ +/* TODO: Support sg devices */ +if (cdev->owner !=THIS_MODULE ) { +OSD_ERR ("Error mounting %s - is not an OSD device\n" , path); + goto out; + } + + oud = container_of(cdev, struct osd_uld_device, cdev); + +__uld_get (oud); + error =0 ; + +out: +path_put (&nd.path); +return error ?ERR_PTR (error) : &oud->od; +} +EXPORT_SYMBOL (osduld_path_lookup); + +void osduld_put_device (struct osd_dev *od) +{ +if (od) { +struct osd_uld_device *oud =container_of (od, + struct osd_uld_device, od); + +__uld_put (oud); + } +} +EXPORT_SYMBOL (osduld_put_device); +/* * Scsi Device operations */
include/scsi/osd_initiator.h +4 -0
@@ -33,6 +33,10 @@ struct osd_dev {unsigned def_timeout; }; +/* Retrieve/return osd_dev(s) for use by Kernel clients */ +struct osd_dev *osduld_path_lookup (const char *dev_name);/*Use IS_ERR/ERR_PTR*/ +void osduld_put_device (struct osd_dev *od); +/* Add/remove test ioctls from external modules */ typedef int (do_test_fn )(struct osd_dev *od,unsigned cmd,unsigned long arg);int osduld_register_test (unsigned ioctl,do_test_fn *do_test);
Signature · 1 line
1.6.0.1
James Bottomley
maintainerRe: [PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel
Quoted 45 lines · Boaz Harrosh
Kernel clients like exofs can retrieve struct
osd_dev(s)by means of below API.+
osduld_path_lookup()- given a path (e.g "/dev/osd0") locks and returns the corresponding structosd_dev, which is then needed for subsequent libosd use.+
osduld_put_device()- free up use of anosd_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_deviceholds an extra reference to both it's char-device and it'sscsi_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 theprobe()function called by scsi-ml upon a successful login into a target. Released inrelease()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 theosd_uld_deviceis freed.The MODULE has three lock sources as well:
1. scsi-ml atprobe()time, removed afterrelease(). (login/logout)
2. The user-mode file handles open/close.
3. Import symbols by client modules like exofs.TODO:
This API is not enough for the pNFS-objects LD. A more versatile API will be needed. Proposed API could be:
structosd_dev*osduld_sysid_lookup(const char id[OSD_SYSTEMID_LEN]);Signed-off-by Boaz Harrosh <[email protected]>--- drivers/scsi/osd/osd_uld.c | 63 ++++++++++++++++++++++++++++++++++++++++++ include/scsi/osd_initiator.h | 4 ++ 2 files changed, 67 insertions(+), 0 deletions(-)drivers/scsi/osd/osd_uld.c +0
-0
drivers/scsi/osd/osd_uld.c static const struct file_operations osd_fops = { · line 176
Quoted 4 lines
drivers/scsi/osd/osd_uld.c +1
-0@@ -173,6 +173,69 @@ static const struct file_operations osd_fops = { .unlocked_ioctl = osd_uld_ioctl, }; +struct osd_dev *osduld_path_lookup (const char *path)
Is there no other way to do this? A kernel component opening another kernel component by device path is generally frowned upon.
The way it should work is to have a user space process initiate everything because it can see the full device space and cope with the problems that may occur on first open in user space.
Quoted 87 lines
drivers/scsi/osd/osd_uld.c +62
-0+{ +struct nameidata nd; +struct inode *inode; +struct cdev *cdev; +struct osd_uld_device *uninitialized_var (oud ); +int error; + +if (!path || !*path) { +OSD_ERR ("Mount with !path || !*path\n" ); +return ERR_PTR (-EINVAL ); + } + + error =path_lookup (path,LOOKUP_FOLLOW , &nd); +if (error) { +OSD_ERR ("path_lookup of %s faild=>%d\n" , path, error); +return ERR_PTR (error); + } + + inode = nd.path.dentry->d_inode; + error = -EINVAL ;/* Not the right device e.g osd_uld_device */ +if (!S_ISCHR (inode->i_mode)) { +OSD_DEBUG ("!S_ISCHR()\n" ); + goto out; + } + + cdev = inode->i_cdev; +if (!cdev) { +OSD_ERR ("Before mounting an OSD Based filesystem\n" ); +OSD_ERR (" user-mode must open+close the %s device\n" , path); +OSD_ERR (" Example: bash: echo < %s\n" , path); + goto out; + } + +/* The Magic wand. Is it our char-dev */ +/* TODO: Support sg devices */ +if (cdev->owner !=THIS_MODULE ) { +OSD_ERR ("Error mounting %s - is not an OSD device\n" , path); + goto out; + } + + oud = container_of(cdev, struct osd_uld_device, cdev); + +__uld_get (oud); + error =0 ; + +out: +path_put (&nd.path); +return error ?ERR_PTR (error) : &oud->od; +} +EXPORT_SYMBOL (osduld_path_lookup); + +void osduld_put_device (struct osd_dev *od) +{ +if (od) { +struct osd_uld_device *oud =container_of (od, + struct osd_uld_device, od); + +__uld_put (oud); + } +} +EXPORT_SYMBOL (osduld_put_device); +/* * Scsi Device operations */ include/scsi/osd_initiator.h +4
-0@@ -33,6 +33,10 @@ struct osd_dev {unsigned def_timeout; }; +/* Retrieve/return osd_dev(s) for use by Kernel clients */ +struct osd_dev *osduld_path_lookup (const char *dev_name);/*Use IS_ERR/ERR_PTR*/ +void osduld_put_device (struct osd_dev *od); +/* Add/remove test ioctls from external modules */ typedef int (do_test_fn )(struct osd_dev *od,unsigned cmd,unsigned long arg);int osduld_register_test (unsigned ioctl,do_test_fn *do_test);Signature · 6 lines
1.6.0.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 06/16] osd_uld: API for retrieving osd devices from Kernel
Quoted 49 lines · James Bottomley
Quoted 48 lines · Boaz Harrosh
Kernel clients like exofs can retrieve struct
osd_dev(s)by means of below API.+
osduld_path_lookup()- given a path (e.g "/dev/osd0") locks and returns the corresponding structosd_dev, which is then needed for subsequent libosd use.+
osduld_put_device()- free up use of anosd_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_deviceholds an extra reference to both it's char-device and it'sscsi_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 theprobe()function called by scsi-ml upon a successful login into a target. Released inrelease()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 theosd_uld_deviceis freed.The MODULE has three lock sources as well:
1. scsi-ml atprobe()time, removed afterrelease(). (login/logout)
2. The user-mode file handles open/close.
3. Import symbols by client modules like exofs.TODO:
This API is not enough for the pNFS-objects LD. A more versatile API will be needed. Proposed API could be:
structosd_dev*osduld_sysid_lookup(const char id[OSD_SYSTEMID_LEN]);Signed-off-by Boaz Harrosh <[email protected]>--- drivers/scsi/osd/osd_uld.c | 63 ++++++++++++++++++++++++++++++++++++++++++ include/scsi/osd_initiator.h | 4 ++ 2 files changed, 67 insertions(+), 0 deletions(-)drivers/scsi/osd/osd_uld.c +0
-0@@ -173,6 +173,69 @@ static const struct file_operations osd_fops = { .unlocked_ioctl = osd_uld_ioctl, };
Quoted 9 lines
drivers/scsi/osd/osd_uld.c static const struct file_operations osd_fops = { · line 176
Quoted 1 line
drivers/scsi/osd/osd_uld.c +1
-0+struct osd_dev *osduld_path_lookup (const char *path)Is there no other way to do this? A kernel component opening another kernel component by device path is generally frowned upon.
The way it should work is to have a user space process initiate everything because it can see the full device space and cope with the problems that may occur on first open in user space.
Thank you for asking, this is something I was pondering on for a long time.
I have based this work on the block-devices model and the way filesystems mount a block device. In fact I have started with lookup_bdev() as reference and only changed it slightly to match char-devices. I have looked in other parts of the kernel on what do the few "FSs over char-dev" do, (there are a few) and they all invent their own none-standard way of mount-options to denote a device to load. While the actual mount-path is unused/empty. I thought it is much more natural to the user of the mount command to just give the device path, just as if it is a block-device. The way I see it, which was triggered by a lot of what you said, an OSD device is just an advanced-API storage-device and all the rest of the stuff should be as natural as possible.
That said, I'm very open to suggestions. What would be a better/more standard way for an OSD based filesystem to look up it's devices, that could be easily denoted by the mount command?
[Please note that with above solution, contrary to all other solutions I've seen except block-dev of course, I do not keep any list of OSD devices anywhere. The vfs /dev/ directory does that for us. This, I would say, is a nice advantage no duplicate lists]
However I have a question. I'm CCing fsdevel maybe someone there could help. Please see below, at the exact code that fails.
Quoted 24 lines
Quoted 24 lines
drivers/scsi/osd/osd_uld.c +24
-0+{ +struct nameidata nd; +struct inode *inode; +struct cdev *cdev; +struct osd_uld_device *uninitialized_var (oud ); +int error; + +if (!path || !*path) { +OSD_ERR ("Mount with !path || !*path\n" ); +return ERR_PTR (-EINVAL ); + } + + error =path_lookup (path,LOOKUP_FOLLOW , &nd); +if (error) { +OSD_ERR ("path_lookup of %s faild=>%d\n" , path, error); +return ERR_PTR (error); + } + + inode = nd.path.dentry->d_inode; + error = -EINVAL ;/* Not the right device e.g osd_uld_device */ +if (!S_ISCHR (inode->i_mode)) { +OSD_DEBUG ("!S_ISCHR()\n" ); + goto out; + }
Quoted 8 lines
drivers/scsi/osd/osd_uld.c static const struct file_operations osd_fops = { · line 208
Quoted 8 lines
drivers/scsi/osd/osd_uld.c +8
-0+ + cdev = inode->i_cdev; +if (!cdev) { +OSD_ERR ("Before mounting an OSD Based filesystem\n" ); +OSD_ERR (" user-mode must open+close the %s device\n" , path); +OSD_ERR (" Example: bash: echo < %s\n" , path); + goto out; + }
Here at this point, as it says by the error message, if I do not open the device at least once in the life time of the char-device the check fails. The device-inode is only half baked. My mount script just does a fast open+close before it mounts exofs. Couple of questions:
* Is there something I can trigger from Kernel prior to the path_lookup() call that will force the inode binding to the char-device. Just like user-mode open does.
* How is lookup_bdev() different then what I do, in that it does not have that open/close problem?
Quoted 41 lines
Quoted 41 lines
drivers/scsi/osd/osd_uld.c +30
-0+ +/* The Magic wand. Is it our char-dev */ +/* TODO: Support sg devices */ +if (cdev->owner !=THIS_MODULE ) { +OSD_ERR ("Error mounting %s - is not an OSD device\n" , path); + goto out; + } + + oud = container_of(cdev, struct osd_uld_device, cdev); + +__uld_get (oud); + error =0 ; + +out: +path_put (&nd.path); +return error ?ERR_PTR (error) : &oud->od; +} +EXPORT_SYMBOL (osduld_path_lookup); + +void osduld_put_device (struct osd_dev *od) +{ +if (od) { +struct osd_uld_device *oud =container_of (od, + struct osd_uld_device, od); + +__uld_put (oud); + } +} +EXPORT_SYMBOL (osduld_put_device); +/* * Scsi Device operations */ include/scsi/osd_initiator.h +0
-0@@ -33,6 +33,10 @@ struct osd_dev {unsigned def_timeout; };
Quoted 8 lines
include/scsi/osd_initiator.h struct osd_dev { · line 42
Quoted 8 lines
include/scsi/osd_initiator.h +4
-0+/* Retrieve/return osd_dev(s) for use by Kernel clients */ +struct osd_dev *osduld_path_lookup (const char *dev_name);/*Use IS_ERR/ERR_PTR*/ +void osduld_put_device (struct osd_dev *od); +/* Add/remove test ioctls from external modules */ typedef int (do_test_fn )(struct osd_dev *od,unsigned cmd,unsigned long arg);int osduld_register_test (unsigned ioctl,do_test_fn *do_test);
Thanks for reviewing
Boaz
PATCH 7/16 libosd: attributes Support
In reply to Boaz HarroshSupport 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)
--- drivers/scsi/osd/osd_initiator.c | 579 ++++++++++++++++++++++++++++++++++++++ include/scsi/osd_attributes.h | 327 +++++++++++++++++++++ 2 files changed, 906 insertions(+), 0 deletions(-) create mode 100644 include/scsi/osd_attributes.h
drivers/scsi/osd/osd_initiator.c +579 -0
@@ -45,6 +45,10 @@#include "osd_debug.h" +#ifndef __unused +# define __unused __attribute__((unused)) +#endif +enum {OSD_REQ_RETRIES =1 };MODULE_AUTHOR ("Boaz Harrosh <[email protected]>" );
@@ -63,6 +67,50 @@ static unsigned _osd_req_cdb_len(struct osd_request *or)return OSDv1_TOTAL_CDB_LEN; } +static unsigned _osd_req_alist_elem_size (struct osd_request *or,unsigned len) +{ +return osdv1_attr_list_elem_size (len); +} + +static unsigned _osd_req_alist_size (struct osd_request *or,void *list_head) +{ +return osdv1_list_size (list_head); +} + +static unsigned _osd_req_sizeof_alist_header (struct osd_request *or) +{ +return sizeof (struct osdv1_attributes_list_header ); +} + +static void _osd_req_set_alist_type (struct osd_request *or, +void *list,int list_type) +{ +struct osdv1_attributes_list_header *attr_list = list; + +memset (attr_list,0 ,sizeof (*attr_list)); + attr_list->type = list_type; +} + +static bool _osd_req_is_alist_type (struct osd_request *or, +void *list,int list_type) +{ +if (!list) +return false; + +if (1 ) { +struct osdv1_attributes_list_header *attr_list = list; + +return attr_list->type == list_type; + } +} + +static osd_cdb_offset osd_req_encode_offset (struct osd_request *or, +u64 offset,unsigned *padding) +{ +return __osd_encode_offset (offset, padding, + OSDv1_OFFSET_MIN_SHIFT,OSD_OFFSET_MAX_SHIFT ); +} +void osd_dev_init (struct osd_dev *osdd,struct scsi_device *scsi_device) {memset (osdd,0 ,sizeof (*osdd));
@@ -125,10 +173,25 @@ static void _abort_unexecuted_bios(struct request *rq) } } +static void _osd_free_seg(struct osd_request *or __unused, +struct _osd_req_data_segment *seg) +{ +if (!seg->buff || !seg->alloc_size) +return ; + +kfree (seg->buff); + seg->buff =NULL ; + seg->alloc_size =0 ; +} +void osd_end_request (struct osd_request *or) {struct request *rq = or->request; +_osd_free_seg (or, &or->set_attr); +_osd_free_seg (or, &or->enc_get_attr); +_osd_free_seg (or, &or->get_attr); +if (rq) {if (rq->next_rq) {_abort_unexecuted_bios (rq->next_rq);
@@ -176,6 +239,54 @@ int osd_execute_request_async(struct osd_request *or, }EXPORT_SYMBOL (osd_execute_request_async); +u8 sg_out_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT]; +u8 sg_in_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT]; + +static int _osd_realloc_seg (struct osd_request *or, +struct _osd_req_data_segment *seg,unsigned max_bytes) +{ +void *buff; + +if (seg->alloc_size >= max_bytes) +return 0 ; + + buff =krealloc (seg->buff, max_bytes, or->alloc_flags); +if (!buff) { +OSD_ERR ("Failed to Realloc %d-bytes was-%d\n" , max_bytes, + seg->alloc_size); +return -ENOMEM ; + } + +memset (buff + seg->alloc_size,0 , max_bytes - seg->alloc_size); + seg->buff = buff; + seg->alloc_size = max_bytes; +return 0 ; +} + +static int _alloc_set_attr_list (struct osd_request *or, +const struct osd_attr *oa,unsigned nelem,unsigned add_bytes) +{ +unsigned total_bytes = add_bytes; + +for (; nelem; --nelem, ++oa) + total_bytes +=_osd_req_alist_elem_size (or, oa->len); + +OSD_DEBUG ("total_bytes=%d\n" , total_bytes); +return _osd_realloc_seg (or, &or->set_attr, total_bytes); +} + +static int _alloc_get_attr_desc (struct osd_request *or,unsigned max_bytes) +{ +OSD_DEBUG ("total_bytes=%d\n" , max_bytes); +return _osd_realloc_seg (or, &or->enc_get_attr, max_bytes); +} + +static int _alloc_get_attr_list (struct osd_request *or) +{ +OSD_DEBUG ("total_bytes=%d\n" , or->get_attr.total_bytes); +return _osd_realloc_seg (or, &or->get_attr, or->get_attr.total_bytes); +} +/* * Common to all OSD commands */
@@ -284,6 +395,410 @@ void osd_req_read(struct osd_request *or, }EXPORT_SYMBOL (osd_req_read); +void osd_req_get_attributes (struct osd_request *or, +const struct osd_obj_id *obj) +{ +_osd_req_encode_common (or,OSD_ACT_GET_ATTRIBUTES , obj,0 ,0 ); +} +EXPORT_SYMBOL (osd_req_get_attributes); + +void osd_req_set_attributes (struct osd_request *or, +const struct osd_obj_id *obj) +{ +_osd_req_encode_common (or,OSD_ACT_SET_ATTRIBUTES , obj,0 ,0 ); +} +EXPORT_SYMBOL (osd_req_set_attributes); + +/* +* Attributes List-mode +*/ + +int osd_req_add_set_attr_list (struct osd_request *or, +const struct osd_attr *oa,unsigned nelem) +{ +unsigned total_bytes = or->set_attr.total_bytes; +void *attr_last; +int ret; + +if (or->attributes_mode && + or->attributes_mode !=OSD_CDB_GET_SET_ATTR_LISTS ) { +WARN_ON (1 ); +return -EINVAL ; + } + or->attributes_mode =OSD_CDB_GET_SET_ATTR_LISTS ; + +if (!total_bytes) {/* first-time: allocate and put list header */ + total_bytes =_osd_req_sizeof_alist_header (or); + ret =_alloc_set_attr_list (or, oa, nelem, total_bytes); +if (ret) +return ret; +_osd_req_set_alist_type (or, or->set_attr.buff, +OSD_ATTR_LIST_SET_RETRIEVE ); + } + attr_last = or->set_attr.buff + total_bytes; + +for (; nelem; --nelem) { +struct osd_attributes_list_element *attr; +unsigned elem_size =_osd_req_alist_elem_size (or, oa->len); + + total_bytes += elem_size; +if (unlikely (or->set_attr.alloc_size < total_bytes)) { + or->set_attr.total_bytes = total_bytes - elem_size; + ret =_alloc_set_attr_list (or, oa, nelem, total_bytes); +if (ret) +return ret; + attr_last = + or->set_attr.buff + or->set_attr.total_bytes; + } + + attr = attr_last; + attr->attr_page =cpu_to_be32 (oa->attr_page); + attr->attr_id =cpu_to_be32 (oa->attr_id); + attr->attr_bytes =cpu_to_be16 (oa->len); +memcpy (attr->attr_val, oa->val_ptr, oa->len); + + attr_last += elem_size; + ++oa; + } + + or->set_attr.total_bytes = total_bytes; +return 0 ; +} +EXPORT_SYMBOL (osd_req_add_set_attr_list); + +static int _append_map_kern (struct request *req, +void *buff,unsigned len,gfp_t flags) +{ +struct bio *bio; +int ret; + + bio =bio_map_kern (req->q, buff, len, flags); +if (IS_ERR (bio)) { +OSD_ERR ("Failed bio_map_kern(%p, %d) => %ld\n" , buff, len, +PTR_ERR (bio)); +return PTR_ERR (bio); + } + ret =blk_rq_append_bio (req->q, req, bio); +if (ret) { +OSD_ERR ("Failed blk_rq_append_bio(%p) => %d\n" , bio, ret); +bio_put (bio); + } +return ret; +} + +static int _req_append_segment (struct osd_request *or, +unsigned padding,struct _osd_req_data_segment *seg, +struct _osd_req_data_segment *last_seg,struct _osd_io_info *io) +{ +void *pad_buff; +int ret; + +if (padding) { +/* check if we can just add it to last buffer */ +if (last_seg && + (padding <= last_seg->alloc_size - last_seg->total_bytes)) + pad_buff = last_seg->buff + last_seg->total_bytes; +else + pad_buff = io->pad_buff; + + ret =_append_map_kern (io->req, pad_buff, padding, + or->alloc_flags); +if (ret) +return ret; + io->total_bytes += padding; + } + + ret =_append_map_kern (io->req, seg->buff, seg->total_bytes, + or->alloc_flags); +if (ret) +return ret; + + io->total_bytes += seg->total_bytes; +OSD_DEBUG ("padding=%d buff=%p total_bytes=%d\n" , padding, seg->buff, + seg->total_bytes); +return 0 ; +} + +static int _osd_req_finalize_set_attr_list (struct osd_request *or) +{ +struct osd_cdb_head *cdbh =osd_cdb_head (&or->cdb); +unsigned padding; +int ret; + +if (!or->set_attr.total_bytes) { + cdbh->attrs_list.set_attr_offset =OSD_OFFSET_UNUSED ; +return 0 ; + } + + cdbh->attrs_list.set_attr_bytes =cpu_to_be32 (or->set_attr.total_bytes); + cdbh->attrs_list.set_attr_offset = +osd_req_encode_offset (or, or->out.total_bytes, &padding); + + ret =_req_append_segment (or, padding, &or->set_attr, + or->out.last_seg, &or->out); +if (ret) +return ret; + + or->out.last_seg = &or->set_attr; +return 0 ; +} + +int osd_req_add_get_attr_list (struct osd_request *or, +const struct osd_attr *oa,unsigned nelem) +{ +unsigned total_bytes = or->enc_get_attr.total_bytes; +void *attr_last; +int ret; + +if (or->attributes_mode && + or->attributes_mode !=OSD_CDB_GET_SET_ATTR_LISTS ) { +WARN_ON (1 ); +return -EINVAL ; + } + or->attributes_mode =OSD_CDB_GET_SET_ATTR_LISTS ; + +/* first time calc data-in list header size */ +if (!or->get_attr.total_bytes) + or->get_attr.total_bytes =_osd_req_sizeof_alist_header (or); + +/* calc data-out info */ +if (!total_bytes) {/* first-time: allocate and put list header */ +unsigned max_bytes; + + total_bytes =_osd_req_sizeof_alist_header (or); + max_bytes = total_bytes + + nelem *sizeof (struct osd_attributes_list_attrid ); + ret =_alloc_get_attr_desc (or, max_bytes); +if (ret) +return ret; + +_osd_req_set_alist_type (or, or->enc_get_attr.buff, +OSD_ATTR_LIST_GET ); + } + attr_last = or->enc_get_attr.buff + total_bytes; + +for (; nelem; --nelem) { +struct osd_attributes_list_attrid *attrid; +const unsigned cur_size =sizeof (*attrid); + + total_bytes += cur_size; +if (unlikely (or->enc_get_attr.alloc_size < total_bytes)) { + or->enc_get_attr.total_bytes = total_bytes - cur_size; + ret =_alloc_get_attr_desc (or, + total_bytes + nelem *sizeof (*attrid)); +if (ret) +return ret; + attr_last = or->enc_get_attr.buff + + or->enc_get_attr.total_bytes; + } + + attrid = attr_last; + attrid->attr_page =cpu_to_be32 (oa->attr_page); + attrid->attr_id =cpu_to_be32 (oa->attr_id); + + attr_last += cur_size; + +/* calc data-in size */ + or->get_attr.total_bytes += +_osd_req_alist_elem_size (or, oa->len); + ++oa; + } + + or->enc_get_attr.total_bytes = total_bytes; + +OSD_DEBUG ( +"get_attr.total_bytes=%u(%u) enc_get_attr.total_bytes=%u(%Zu)\n" , + or->get_attr.total_bytes, + or->get_attr.total_bytes -_osd_req_sizeof_alist_header (or), + or->enc_get_attr.total_bytes, + (or->enc_get_attr.total_bytes -_osd_req_sizeof_alist_header (or)) + /sizeof (struct osd_attributes_list_attrid )); + +return 0 ; +} +EXPORT_SYMBOL (osd_req_add_get_attr_list); + +static int _osd_req_finalize_get_attr_list (struct osd_request *or) +{ +struct osd_cdb_head *cdbh =osd_cdb_head (&or->cdb); +unsigned out_padding; +unsigned in_padding; +int ret; + +if (!or->enc_get_attr.total_bytes) { + cdbh->attrs_list.get_attr_desc_offset =OSD_OFFSET_UNUSED ; + cdbh->attrs_list.get_attr_offset =OSD_OFFSET_UNUSED ; +return 0 ; + } + + ret =_alloc_get_attr_list (or); +if (ret) +return ret; + +/* The out-going buffer info update */ +OSD_DEBUG ("out-going\n" ); + cdbh->attrs_list.get_attr_desc_bytes = +cpu_to_be32 (or->enc_get_attr.total_bytes); + + cdbh->attrs_list.get_attr_desc_offset = +osd_req_encode_offset (or, or->out.total_bytes, &out_padding); + + ret =_req_append_segment (or, out_padding, &or->enc_get_attr, + or->out.last_seg, &or->out); +if (ret) +return ret; + or->out.last_seg = &or->enc_get_attr; + +/* The incoming buffer info update */ +OSD_DEBUG ("in-coming\n" ); + cdbh->attrs_list.get_attr_alloc_length = +cpu_to_be32 (or->get_attr.total_bytes); + + cdbh->attrs_list.get_attr_offset = +osd_req_encode_offset (or, or->in.total_bytes, &in_padding); + + ret =_req_append_segment (or, in_padding, &or->get_attr,NULL , + &or->in); +if (ret) +return ret; + or->in.last_seg = &or->get_attr; + +return 0 ; +} + +int osd_req_decode_get_attr_list (struct osd_request *or, +struct osd_attr *oa,int *nelem,void **iterator) +{ +unsigned cur_bytes, returned_bytes; +int n; +const unsigned sizeof_attr_list =_osd_req_sizeof_alist_header (or); +void *cur_p; + +if (!_osd_req_is_alist_type (or, or->get_attr.buff, +OSD_ATTR_LIST_SET_RETRIEVE )) { + oa->attr_page =0 ; + oa->attr_id =0 ; + oa->val_ptr =NULL ; + oa->len =0 ; + *iterator =NULL ; +return 0 ; + } + +if (*iterator) { +BUG_ON ((*iterator < or->get_attr.buff) || + (or->get_attr.buff + or->get_attr.alloc_size < *iterator)); + cur_p = *iterator; + cur_bytes = (*iterator - or->get_attr.buff) - sizeof_attr_list; + returned_bytes = or->get_attr.total_bytes; + }else {/* first time decode the list header */ + cur_bytes = sizeof_attr_list; + returned_bytes =_osd_req_alist_size (or, or->get_attr.buff) + + sizeof_attr_list; + + cur_p = or->get_attr.buff + sizeof_attr_list; + +if (returned_bytes > or->get_attr.alloc_size) { +OSD_DEBUG ("target report: space was not big enough! " +"Allocate=%u Needed=%u\n" , + or->get_attr.alloc_size, + returned_bytes + sizeof_attr_list); + + returned_bytes = + or->get_attr.alloc_size - sizeof_attr_list; + } + or->get_attr.total_bytes = returned_bytes; + } + +for (n =0 ; (n < *nelem) && (cur_bytes < returned_bytes); ++n) { +struct osd_attributes_list_element *attr = cur_p; +unsigned inc; + + oa->len =be16_to_cpu (attr->attr_bytes); + inc =_osd_req_alist_elem_size (or, oa->len); +OSD_DEBUG ("oa->len=%d inc=%d cur_bytes=%d\n" , + oa->len, inc, cur_bytes); + cur_bytes += inc; +if (cur_bytes > returned_bytes) { +OSD_ERR ("BAD FOOD from target. list not valid!" +"c=%d r=%d n=%d\n" , + cur_bytes, returned_bytes, n); + oa->val_ptr =NULL ; +break ; + } + + oa->attr_page =be32_to_cpu (attr->attr_page); + oa->attr_id =be32_to_cpu (attr->attr_id); + oa->val_ptr = attr->attr_val; + + cur_p += inc; + ++oa; + } + + *iterator = (returned_bytes - cur_bytes) ? cur_p :NULL ; + *nelem = n; +return returned_bytes - cur_bytes; +} +EXPORT_SYMBOL (osd_req_decode_get_attr_list); + +/* +* Attributes Page-mode +*/ + +int osd_req_add_get_attr_page (struct osd_request *or, +u32 page_id,void *attar_page,unsigned max_page_len, +const struct osd_attr *set_one_attr) +{ +struct osd_cdb_head *cdbh =osd_cdb_head (&or->cdb); + +if (or->attributes_mode && + or->attributes_mode !=OSD_CDB_GET_ATTR_PAGE_SET_ONE ) { +WARN_ON (1 ); +return -EINVAL ; + } + or->attributes_mode =OSD_CDB_GET_ATTR_PAGE_SET_ONE ; + + or->get_attr.buff = attar_page; + or->get_attr.total_bytes = max_page_len; + + or->set_attr.buff = set_one_attr->val_ptr; + or->set_attr.total_bytes = set_one_attr->len; + + cdbh->attrs_page.get_attr_page =cpu_to_be32 (page_id); + cdbh->attrs_page.get_attr_alloc_length =cpu_to_be32 (max_page_len); +/* ocdb->attrs_page.get_attr_offset; */ + + cdbh->attrs_page.set_attr_page =cpu_to_be32 (set_one_attr->attr_page); + cdbh->attrs_page.set_attr_id =cpu_to_be32 (set_one_attr->attr_id); + cdbh->attrs_page.set_attr_length =cpu_to_be32 (set_one_attr->len); +/* ocdb->attrs_page.set_attr_offset; */ +return 0 ; +} +EXPORT_SYMBOL (osd_req_add_get_attr_page); + +static int _osd_req_finalize_attr_page (struct osd_request *or) +{ +struct osd_cdb_head *cdbh =osd_cdb_head (&or->cdb); +unsigned in_padding, out_padding; +int ret; + +/* returned page */ + cdbh->attrs_page.get_attr_offset = +osd_req_encode_offset (or, or->in.total_bytes, &in_padding); + + ret =_req_append_segment (or, in_padding, &or->get_attr,NULL , + &or->in); +if (ret) +return ret; + +/* set one value */ + cdbh->attrs_page.set_attr_offset = +osd_req_encode_offset (or, or->out.total_bytes, &out_padding); + + ret =_req_append_segment (or, out_padding, &or->enc_get_attr,NULL , + &or->out); +return ret; +} +/* * osd_finalize_request and helpers */
@@ -378,9 +893,31 @@ int osd_finalize_request(struct osd_request *or, _LLU(or->in.total_bytes), or->in.req->data_len); } + or->out.pad_buff = sg_out_pad_buffer; + or->in.pad_buff = sg_in_pad_buffer; +if (!or->attributes_mode) or->attributes_mode =OSD_CDB_GET_SET_ATTR_LISTS ; cdbh->command_specific_options |= or->attributes_mode; +if (or->attributes_mode ==OSD_CDB_GET_ATTR_PAGE_SET_ONE ) { + ret =_osd_req_finalize_attr_page (or); + }else { +/* TODO: I think that for the GET_ATTR command these 2 should +* be reversed to keep them in execution order (for embeded +* targets with low memory footprint) +*/ + ret =_osd_req_finalize_set_attr_list (or); +if (ret) { +OSD_DEBUG ("_osd_req_finalize_set_attr_list failed\n" ); +return ret; + } + + ret =_osd_req_finalize_get_attr_list (or); +if (ret) { +OSD_DEBUG ("_osd_req_finalize_get_attr_list failed\n" ); +return ret; + } + } or->request->cmd = or->cdb.buff; or->request->cmd_len =_osd_req_cdb_len (or);
@@ -446,3 +983,45 @@ void osd_set_caps(struct osd_cdb *cdb, const void *caps) {memcpy (&cdb->v1.caps, caps, OSDv1_CAP_LEN); } + +/* +* Declared in osd_protocol.h +* 4.12.5 Data-In and Data-Out buffer offsets +* byte offset = mantissa * (2^(exponent+8)) +* Returns the smallest allowed encoded offset that contains given @offset +* The actual encoded offset returned is @offset + *@padding. +*/ +osd_cdb_offset __osd_encode_offset ( +u64 offset,unsigned *padding,int min_shift,int max_shift) +{ +u64 try_offset =-1 , mod, align; +osd_cdb_offset be32_offset; +int shift; + + *padding =0 ; +if (!offset) +return 0 ; + +for (shift = min_shift; shift < max_shift; ++shift) { + try_offset = offset >> shift; +if (try_offset < (1 <<OSD_OFFSET_MAX_BITS )) +break ; + } + +BUG_ON (shift == max_shift); + + align =1 << shift; + mod = offset & (align -1 ); +if (mod) { + *padding = align - mod; + try_offset +=1 ; + } + + try_offset |= ((shift -8 ) &0xf ) <<28 ; + be32_offset =cpu_to_be32 ((u32 )try_offset); + +OSD_DEBUG ("offset=%llu mantissa=%llu exp=%d encoded=%x pad=%d\n" , +_LLU (offset),_LLU (try_offset &0x0FFFFFFF ), shift, + be32_offset, *padding); +return be32_offset; +}
include/scsi/osd_attributes.h new file +327 -0
327 lines not on this page · raw message
Signature · 1 line
1.6.0.1
PATCH 8/16 libosd: OSD Security processing stubs
In reply to Boaz HarroshLayout 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.
--- drivers/scsi/osd/osd_initiator.c | 86 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 86 insertions(+), 0 deletions(-)
drivers/scsi/osd/osd_initiator.c +86 -0
@@ -111,6 +111,14 @@ static osd_cdb_offset osd_req_encode_offset(struct osd_request *or, OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT); } +static struct osd_security_parameters * +_osd_req_sec_params (struct osd_request *or) +{ +struct osd_cdb *ocdb = &or->cdb; + +return &ocdb->v1.sec_params; +} +void osd_dev_init (struct osd_dev *osdd,struct scsi_device *scsi_device) {memset (osdd,0 ,sizeof (*osdd));
@@ -799,6 +807,64 @@ static int _osd_req_finalize_attr_page(struct osd_request *or)return ret; } +static int _osd_req_finalize_data_integrity (struct osd_request *or, +bool has_in,bool has_out,const u8 *cap_key) +{ +struct osd_security_parameters *sec_parms =_osd_req_sec_params (or); +int ret; + +if (!osd_is_sec_alldata (sec_parms)) +return 0 ; + +if (has_out) { +struct _osd_req_data_segment seg = { + .buff = &or->out_data_integ, + .total_bytes =sizeof (or->out_data_integ), + }; +unsigned pad; + + or->out_data_integ.data_bytes =cpu_to_be64 ( + or->out.bio ? or->out.bio->bi_size :0 ); + or->out_data_integ.set_attributes_bytes =cpu_to_be64 ( + or->set_attr.total_bytes); + or->out_data_integ.get_attributes_bytes =cpu_to_be64 ( + or->enc_get_attr.total_bytes); + + sec_parms->data_out_integrity_check_offset = +osd_req_encode_offset (or, or->out.total_bytes, &pad); + + ret =_req_append_segment (or, pad, &seg, or->out.last_seg, + &or->out); +if (ret) +return ret; + or->out.last_seg =NULL ; + +/* they are now all chained to request sign them all together */ +osd_sec_sign_data (&or->out_data_integ, or->out.req->bio, + cap_key); + } + +if (has_in) { +struct _osd_req_data_segment seg = { + .buff = &or->in_data_integ, + .total_bytes =sizeof (or->in_data_integ), + }; +unsigned pad; + + sec_parms->data_in_integrity_check_offset = +osd_req_encode_offset (or, or->in.total_bytes, &pad); + + ret =_req_append_segment (or, pad, &seg, or->in.last_seg, + &or->in); +if (ret) +return ret; + + or->in.last_seg =NULL ; + } + +return 0 ; +} +/* * osd_finalize_request and helpers */
@@ -919,6 +985,12 @@ int osd_finalize_request(struct osd_request *or, } } + ret =_osd_req_finalize_data_integrity (or, has_in, has_out, cap_key); +if (ret) +return ret; + +osd_sec_sign_cdb (&or->cdb, cap_key); + or->request->cmd = or->cdb.buff; or->request->cmd_len =_osd_req_cdb_len (or);
@@ -984,6 +1056,20 @@ void osd_set_caps(struct osd_cdb *cdb, const void *caps)memcpy (&cdb->v1.caps, caps, OSDv1_CAP_LEN); } +bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused) +{ +return false; +} + +void osd_sec_sign_cdb(struct osd_cdb *ocdb __unused, const u8 *cap_key __unused) +{ +} + +void osd_sec_sign_data(void *data_integ __unused, + struct bio *bio __unused, const u8 *cap_key __unused) +{ +} +/* * Declared in osd_protocol.h * 4.12.5 Data-In and Data-Out buffer offsets
Signature · 1 line
1.6.0.1
PATCH 9/16 libosd: Add Flush and List-objects support
In reply to Boaz HarroshAdd 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.
--- drivers/scsi/osd/osd_initiator.c | 124 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 124 insertions(+), 0 deletions(-)
drivers/scsi/osd/osd_initiator.c +124 -0
@@ -104,6 +104,16 @@ static bool _osd_req_is_alist_type(struct osd_request *or, } } +/* This is for List-objects not Attributes-Lists */ +static void _osd_req_encode_olist (struct osd_request *or, +struct osd_obj_id_list *list) +{ +struct osd_cdb_head *cdbh =osd_cdb_head (&or->cdb); + + cdbh->v1.list_identifier = list->list_identifier; + cdbh->v1.start_address = list->continuation_id; +} +static osd_cdb_offset osd_req_encode_offset (struct osd_request *or,u64 offset,unsigned *padding) {
@@ -340,6 +350,29 @@ void osd_req_format(struct osd_request *or, u64 tot_capacity) }EXPORT_SYMBOL (osd_req_format); +int osd_req_list_dev_partitions (struct osd_request *or, +osd_id initial_id,struct osd_obj_id_list *list,unsigned nelem) +{ +return osd_req_list_partition_objects (or,0 , initial_id, list, nelem); +} +EXPORT_SYMBOL (osd_req_list_dev_partitions); + +static void _osd_req_encode_flush (struct osd_request *or, +enum osd_options_flush_scope_values op) +{ +struct osd_cdb_head *ocdb =osd_cdb_head (&or->cdb); + + ocdb->command_specific_options = op; +} + +void osd_req_flush_obsd (struct osd_request *or, +enum osd_options_flush_scope_values op) +{ +_osd_req_encode_common (or,OSD_ACT_FLUSH_OSD , &osd_root_object,0 ,0 ); +_osd_req_encode_flush (or, op); +} +EXPORT_SYMBOL (osd_req_flush_obsd); +/* * Partition commands */
@@ -366,6 +399,88 @@ void osd_req_remove_partition(struct osd_request *or, osd_id partition) }EXPORT_SYMBOL (osd_req_remove_partition); +static int _osd_req_list_objects (struct osd_request *or, +__be16 action,const struct osd_obj_id *obj,osd_id initial_id, +struct osd_obj_id_list *list,unsigned nelem) +{ +struct request_queue *q = or->osd_dev->scsi_device->request_queue; +u64 len = nelem *sizeof (osd_id) +sizeof (*list); +struct bio *bio; + +_osd_req_encode_common (or, action, obj, (u64 )initial_id, len); + +if (list->list_identifier) +_osd_req_encode_olist (or, list); + +WARN_ON (or->in.bio); + bio =bio_map_kern (q, list, len, or->alloc_flags); +if (!bio) { +OSD_ERR ("!!! Failed to allocate list_objects BIO\n" ); +return -ENOMEM ; + } + + bio->bi_rw &= ~(1 <<BIO_RW ); + or->in.bio = bio; + or->in.total_bytes = bio->bi_size; +return 0 ; +} + +int osd_req_list_partition_collections (struct osd_request *or, +osd_id partition,osd_id initial_id,struct osd_obj_id_list *list, +unsigned nelem) +{ +struct osd_obj_id par = { + .partition = partition, + .id =0 , + }; + +return osd_req_list_collection_objects (or, &par, initial_id, list, + nelem); +} +EXPORT_SYMBOL (osd_req_list_partition_collections); + +int osd_req_list_partition_objects (struct osd_request *or, +osd_id partition,osd_id initial_id,struct osd_obj_id_list *list, +unsigned nelem) +{ +struct osd_obj_id par = { + .partition = partition, + .id =0 , + }; + +return _osd_req_list_objects (or,OSD_ACT_LIST , &par, initial_id, list, + nelem); +} +EXPORT_SYMBOL (osd_req_list_partition_objects); + +void osd_req_flush_partition (struct osd_request *or, +osd_id partition,enum osd_options_flush_scope_values op) +{ +_osd_req_encode_partition (or,OSD_ACT_FLUSH_PARTITION , partition); +_osd_req_encode_flush (or, op); +} +EXPORT_SYMBOL (osd_req_flush_partition); + +/* +* Collection commands +*/ +int osd_req_list_collection_objects (struct osd_request *or, +const struct osd_obj_id *obj,osd_id initial_id, +struct osd_obj_id_list *list,unsigned nelem) +{ +return _osd_req_list_objects (or,OSD_ACT_LIST_COLLECTION , obj, + initial_id, list, nelem); +} +EXPORT_SYMBOL (osd_req_list_collection_objects); + +void osd_req_flush_collection (struct osd_request *or, +const struct osd_obj_id *obj,enum osd_options_flush_scope_values op) +{ +_osd_req_encode_common (or,OSD_ACT_FLUSH_PARTITION , obj,0 ,0 ); +_osd_req_encode_flush (or, op); +} +EXPORT_SYMBOL (osd_req_flush_collection); +/* * Object commands */
@@ -392,6 +507,15 @@ void osd_req_write(struct osd_request *or, }EXPORT_SYMBOL (osd_req_write); +void osd_req_flush_object (struct osd_request *or, +const struct osd_obj_id *obj,enum osd_options_flush_scope_values op, +/*V2*/ u64 offset,/*V2*/ u64 len) +{ +_osd_req_encode_common (or,OSD_ACT_FLUSH , obj, offset, len); +_osd_req_encode_flush (or, op); +} +EXPORT_SYMBOL (osd_req_flush_object); +void osd_req_read (struct osd_request *or,const struct osd_obj_id *obj,struct bio *bio,u64 offset) {
Signature · 1 line
1.6.0.1
PATCH 10/16 libosd: Not implemented commands
In reply to Boaz HarroshSome commands declared in header are not yet implemented. Put them as stubs in .c file, just so they take their place in the file
--- drivers/scsi/osd/osd_initiator.c | 35 +++++++++++++++++++++++++++++++++++ 1 files changed, 35 insertions(+), 0 deletions(-)
drivers/scsi/osd/osd_initiator.c +35 -0
@@ -343,6 +343,9 @@ static void _osd_req_encode_common(struct osd_request *or,/* * Device commands */ +/*TODO: void osd_req_set_master_seed_xchg(struct osd_request *, ...); */ +/*TODO: void osd_req_set_master_key(struct osd_request *, ...); */ +void osd_req_format (struct osd_request *or,u64 tot_capacity) { _osd_req_encode_common(or, OSD_ACT_FORMAT_OSD, &osd_root_object, 0,
@@ -373,6 +376,10 @@ void osd_req_flush_obsd(struct osd_request *or, }EXPORT_SYMBOL (osd_req_flush_obsd); +/*TODO: void osd_req_perform_scsi_command(struct osd_request *, +const u8 *cdb, ...); */ +/*TODO: void osd_req_task_management(struct osd_request *, ...); */ +/* * Partition commands */
@@ -399,6 +406,10 @@ void osd_req_remove_partition(struct osd_request *or, osd_id partition) }EXPORT_SYMBOL (osd_req_remove_partition); +/*TODO: void osd_req_set_partition_key(struct osd_request *, +osd_id partition, u8 new_key_id[OSD_CRYPTO_KEYID_SIZE], +u8 seed[OSD_CRYPTO_SEED_SIZE]); */ +static int _osd_req_list_objects (struct osd_request *or,__be16 action,const struct osd_obj_id *obj,osd_id initial_id,struct osd_obj_id_list *list,unsigned nelem)
@@ -464,6 +475,11 @@ EXPORT_SYMBOL(osd_req_flush_partition);/* * Collection commands */ +/*TODO: void osd_req_create_collection(struct osd_request *, +const struct osd_obj_id *); */ +/*TODO: void osd_req_remove_collection(struct osd_request *, +const struct osd_obj_id *); */ +int osd_req_list_collection_objects (struct osd_request *or,const struct osd_obj_id *obj,osd_id initial_id,struct osd_obj_id_list *list,unsigned nelem)
@@ -473,6 +489,8 @@ int osd_req_list_collection_objects(struct osd_request *or, }EXPORT_SYMBOL (osd_req_list_collection_objects); +/*TODO: void query(struct osd_request *, ...); V2 */ +void osd_req_flush_collection (struct osd_request *or,const struct osd_obj_id *obj,enum osd_options_flush_scope_values op) {
@@ -481,6 +499,9 @@ void osd_req_flush_collection(struct osd_request *or, }EXPORT_SYMBOL (osd_req_flush_collection); +/*TODO: void get_member_attrs(struct osd_request *, ...); V2 */ +/*TODO: void set_member_attrs(struct osd_request *, ...); V2 */ +/* * Object commands */
@@ -496,6 +517,11 @@ void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *obj) }EXPORT_SYMBOL (osd_req_remove_object); + +/*TODO: void osd_req_create_multi(struct osd_request *or, +struct osd_obj_id *first, struct osd_obj_id_list *list, unsigned nelem); +*/ +void osd_req_write (struct osd_request *or,const struct osd_obj_id *obj,struct bio *bio,u64 offset) {
@@ -507,6 +533,15 @@ void osd_req_write(struct osd_request *or, }EXPORT_SYMBOL (osd_req_write); +/*TODO: void osd_req_append(struct osd_request *, +const struct osd_obj_id *, struct bio *data_out); */ +/*TODO: void osd_req_create_write(struct osd_request *, +const struct osd_obj_id *, struct bio *data_out, u64 offset); */ +/*TODO: void osd_req_clear(struct osd_request *, +const struct osd_obj_id *, u64 offset, u64 len); */ +/*TODO: void osd_req_punch(struct osd_request *, +const struct osd_obj_id *, u64 offset, u64 len); V2 */ +void osd_req_flush_object (struct osd_request *or,const struct osd_obj_id *obj,enum osd_options_flush_scope_values op,/*V2*/ u64 offset,/*V2*/ u64 len)
Signature · 1 line
1.6.0.1
PATCH 11/16 libosd: OSD version 2 Support
In reply to Boaz HarroshAdd 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.
--- drivers/scsi/osd/osd_initiator.c | 94 ++++++++++++++++++++++++++++++++------ include/scsi/osd_initiator.h | 39 ++++++++++++++++ include/scsi/osd_protocol.h | 90 ++++++++++++++++++++++++++++++++++-- 3 files changed, 205 insertions(+), 18 deletions(-)
drivers/scsi/osd/osd_initiator.c +80 -14
@@ -59,36 +59,50 @@ static inline void build_test(void) {/* structures were not packed */ BUILD_BUG_ON (sizeof (struct osd_capability ) !=OSD_CAP_LEN ); +BUILD_BUG_ON (sizeof (struct osdv2_cdb ) !=OSD_TOTAL_CDB_LEN );BUILD_BUG_ON (sizeof (struct osdv1_cdb ) != OSDv1_TOTAL_CDB_LEN); }static unsigned _osd_req_cdb_len (struct osd_request *or) { -return OSDv1_TOTAL_CDB_LEN; +return osd_req_is_ver1 (or) ? OSDv1_TOTAL_CDB_LEN :OSD_TOTAL_CDB_LEN ; }static unsigned _osd_req_alist_elem_size (struct osd_request *or,unsigned len) { -return osdv1_attr_list_elem_size (len); +return osd_req_is_ver1 (or) ? +osdv1_attr_list_elem_size (len) : +osdv2_attr_list_elem_size (len); }static unsigned _osd_req_alist_size (struct osd_request *or,void *list_head) { -return osdv1_list_size (list_head); +return osd_req_is_ver1 (or) ? +osdv1_list_size (list_head) : +osdv2_list_size (list_head); }static unsigned _osd_req_sizeof_alist_header (struct osd_request *or) { -return sizeof (struct osdv1_attributes_list_header ); +return osd_req_is_ver1 (or) ? +sizeof (struct osdv1_attributes_list_header ) : +sizeof (struct osdv2_attributes_list_header ); }static void _osd_req_set_alist_type (struct osd_request *or,void *list,int list_type) { -struct osdv1_attributes_list_header *attr_list = list; +if (osd_req_is_ver1 (or)) { +struct osdv1_attributes_list_header *attr_list = list; + +memset (attr_list,0 ,sizeof (*attr_list)); + attr_list->type = list_type; + }else { +struct osdv2_attributes_list_header *attr_list = list; -memset (attr_list,0 ,sizeof (*attr_list)); - attr_list->type = list_type; +memset (attr_list,0 ,sizeof (*attr_list)); + attr_list->type = list_type; + } } static bool _osd_req_is_alist_type(struct osd_request *or,
@@ -97,10 +111,14 @@ static bool _osd_req_is_alist_type(struct osd_request *or,if (!list)return false; -if (1 ) { +if (osd_req_is_ver1 (or)) {struct osdv1_attributes_list_header *attr_list = list;return attr_list->type == list_type; + }else { +struct osdv2_attributes_list_header *attr_list = list; + +return attr_list->type == list_type; } }
@@ -110,15 +128,22 @@ static void _osd_req_encode_olist(struct osd_request *or, {struct osd_cdb_head *cdbh =osd_cdb_head (&or->cdb); - cdbh->v1.list_identifier = list->list_identifier; - cdbh->v1.start_address = list->continuation_id; +if (osd_req_is_ver1 (or)) { + cdbh->v1.list_identifier = list->list_identifier; + cdbh->v1.start_address = list->continuation_id; + }else { + cdbh->v2.list_identifier = list->list_identifier; + cdbh->v2.start_address = list->continuation_id; + } }static osd_cdb_offset osd_req_encode_offset (struct osd_request *or,u64 offset,unsigned *padding) {return __osd_encode_offset (offset, padding, - OSDv1_OFFSET_MIN_SHIFT,OSD_OFFSET_MAX_SHIFT ); +osd_req_is_ver1 (or) ? + OSDv1_OFFSET_MIN_SHIFT :OSD_OFFSET_MIN_SHIFT , +OSD_OFFSET_MAX_SHIFT ); } static struct osd_security_parameters *
@@ -126,7 +151,10 @@ _osd_req_sec_params(struct osd_request *or) {struct osd_cdb *ocdb = &or->cdb; -return &ocdb->v1.sec_params; +if (osd_req_is_ver1 (or)) +return &ocdb->v1.sec_params; +else +return &ocdb->v2.sec_params; }void osd_dev_init (struct osd_dev *osdd,struct scsi_device *scsi_device)
@@ -134,6 +162,9 @@ void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)memset (osdd,0 ,sizeof (*osdd)); osdd->scsi_device = scsi_device; osdd->def_timeout =BLK_DEFAULT_SG_TIMEOUT ; +#ifdef OSD_VER1_SUPPORT + osdd->version =OSD_VER2 ; +#endif /* TODO: Allocate pools for osd_request attributes ... */ }EXPORT_SYMBOL (osd_dev_init);
@@ -334,10 +365,30 @@ static void _osdv1_req_encode_common(struct osd_request *or, ocdb->h.v1.start_address =cpu_to_be64 (offset); } +static void _osdv2_req_encode_common (struct osd_request *or, +__be16 act,const struct osd_obj_id *obj,u64 offset,u64 len) +{ +struct osdv2_cdb *ocdb = &or->cdb.v2; + +OSD_DEBUG ("OSDv2 execute opcode 0x%x\n" ,be16_to_cpu (act)); + + ocdb->h.varlen_cdb.opcode =VARIABLE_LENGTH_CMD ; + ocdb->h.varlen_cdb.additional_cdb_length =OSD_ADDITIONAL_CDB_LENGTH ; + ocdb->h.varlen_cdb.service_action = act; + + ocdb->h.partition =cpu_to_be64 (obj->partition); + ocdb->h.object =cpu_to_be64 (obj->id); + ocdb->h.v2.length =cpu_to_be64 (len); + ocdb->h.v2.start_address =cpu_to_be64 (offset); +} +static void _osd_req_encode_common (struct osd_request *or,__be16 act,const struct osd_obj_id *obj,u64 offset,u64 len) { -_osdv1_req_encode_common (or, act, obj, offset, len); +if (osd_req_is_ver1 (or)) +_osdv1_req_encode_common (or, act, obj, offset, len); +else +_osdv2_req_encode_common (or, act, obj, offset, len); }/*
@@ -546,6 +597,12 @@ void osd_req_flush_object(struct osd_request *or, const struct osd_obj_id *obj, enum osd_options_flush_scope_values op, /*V2*/ u64 offset, /*V2*/ u64 len) { + if (unlikely(osd_req_is_ver1(or) && (offset || len))) { + OSD_DEBUG("OSD Ver1 flush on specific range ignored\n"); + offset =0 ; + len =0 ; + } +_osd_req_encode_common (or,OSD_ACT_FLUSH , obj, offset, len);_osd_req_encode_flush (or, op); }
@@ -1169,6 +1226,10 @@ enum { OSD_SEC_CAP_V1_ALL_CAPS = OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT }; +enum {OSD_SEC_CAP_V2_ALL_CAPS = +OSD_SEC_CAP_V1_ALL_CAPS |OSD_SEC_CAP_QUERY |OSD_SEC_CAP_M_OBJECT +}; +void osd_sec_init_nosec_doall_caps (void *caps,const struct osd_obj_id *obj,bool is_collection,const bool is_v1) {
@@ -1210,9 +1271,14 @@ void osd_sec_init_nosec_doall_caps(void *caps, }EXPORT_SYMBOL (osd_sec_init_nosec_doall_caps); +/* FIXME: Extract version from caps pointer. +* Also Pete's target only supports caps from OSDv1 for now +*/ void osd_set_caps (struct osd_cdb *cdb,const void *caps) { -memcpy (&cdb->v1.caps, caps, OSDv1_CAP_LEN); +bool is_ver1 = true; +/* NOTE: They start at same address */ +memcpy (&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN :OSD_CAP_LEN ); } bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused)
include/scsi/osd_initiator.h +39 -0
@@ -21,6 +21,23 @@/* Note: "NI" in comments below means "Not Implemented yet" */ +/* Configure of code: +* #undef if you *don't* want OSD v1 support in runtime. +* If #defined the initiator will dynamically configure to encode OSD v1 +* CDB's if the target is detected to be OSD v1 only. +* OSD v2 only commands, options, and attributes will be ignored if target +* is v1 only. +* If #defined will result in bigger/slower code (OK Slower maybe not) +* Q: Should this be CONFIG_SCSI_OSD_VER1_SUPPORT and set from Kconfig? +*/ +#define OSD_VER1_SUPPORT y + +enum osd_std_version { +OSD_VER_NONE =0 , +OSD_VER1 =1 , +OSD_VER2 =2 , +}; +/* * Object-based Storage Device. * This object represents an OSD device.
@@ -31,6 +48,10 @@struct osd_dev {struct scsi_device *scsi_device;unsigned def_timeout; + +#ifdef OSD_VER1_SUPPORT +enum osd_std_version version; +#endif };/* Retrieve/return osd_dev(s) for use by Kernel clients */
@@ -46,6 +67,14 @@ void osduld_unregister_test(unsigned ioctl);void osd_dev_init (struct osd_dev *od,struct scsi_device *scsi_device);void osd_dev_fini (struct osd_dev *od); +/* we might want to use function vector in the future */ +static inline void osd_dev_set_ver (struct osd_dev *od,enum osd_std_version v) +{ +#ifdef OSD_VER1_SUPPORT + od->version = v; +#endif +} +struct osd_request ;typedef void (osd_req_done_fn )(struct osd_request *or,void *private);
@@ -82,6 +111,16 @@ struct osd_request {int async_error; }; +/* OSD Version control */ +static inline bool osd_req_is_ver1 (struct osd_request *or) +{ +#ifdef OSD_VER1_SUPPORT +return or->osd_dev->version ==OSD_VER1 ; +#else +return false; +#endif +} +/* * How to use the osd library: *
include/scsi/osd_protocol.h +86 -4
172 lines not on this page · raw message
Signature · 6 lines
1.6.0.1 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 12/16 libosd: OSDv2 auto detection
In reply to Boaz HarroshAuto 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.
--- 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(-)
drivers/scsi/osd/osd_initiator.c +125 -0
@@ -41,6 +41,7 @@#include <scsi/osd_initiator.h> #include <scsi/osd_sec.h> +#include <scsi/osd_attributes.h> #include <scsi/scsi_device.h> #include "osd_debug.h"
@@ -63,6 +64,130 @@ static inline void build_test(void)BUILD_BUG_ON (sizeof (struct osdv1_cdb ) != OSDv1_TOTAL_CDB_LEN); } +static const char *_osd_ver_desc (struct osd_request *or) +{ +return osd_req_is_ver1 (or) ?"OSD1" :"OSD2" ; +} + +#define ATTR_DEF_RI (id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len) + +static int _osd_print_system_info (struct osd_dev *od,void *caps) +{ +struct osd_request *or; +struct osd_attr get_attrs[] = { +ATTR_DEF_RI (OSD_ATTR_RI_VENDOR_IDENTIFICATION ,8 ), +ATTR_DEF_RI (OSD_ATTR_RI_PRODUCT_IDENTIFICATION ,16 ), +ATTR_DEF_RI (OSD_ATTR_RI_PRODUCT_MODEL ,32 ), +ATTR_DEF_RI (OSD_ATTR_RI_PRODUCT_REVISION_LEVEL ,4 ), +ATTR_DEF_RI (OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER ,64 /*variable*/ ), +ATTR_DEF_RI (OSD_ATTR_RI_OSD_NAME ,64 /*variable*/ ), +ATTR_DEF_RI (OSD_ATTR_RI_TOTAL_CAPACITY ,8 ), +ATTR_DEF_RI (OSD_ATTR_RI_USED_CAPACITY ,8 ), +ATTR_DEF_RI (OSD_ATTR_RI_NUMBER_OF_PARTITIONS ,8 ), +ATTR_DEF_RI (OSD_ATTR_RI_CLOCK ,6 ), +/* IBM-OSD-SIM Has a bug with this one put it last */ +ATTR_DEF_RI (OSD_ATTR_RI_OSD_SYSTEM_ID ,20 ), + }; +void *iter =NULL , *pFirst; +int nelem =ARRAY_SIZE (get_attrs), a =0 ; +int ret; + + or =osd_start_request (od,GFP_KERNEL ); +if (!or) +return -ENOMEM ; + +/* get attrs */ +osd_req_get_attributes (or, &osd_root_object); +osd_req_add_get_attr_list (or, get_attrs,ARRAY_SIZE (get_attrs)); + + ret =osd_finalize_request (or,0 , caps,NULL ); +if (ret) + goto out; + + ret =osd_execute_request (or); +if (ret) { +OSD_ERR ("Failed to detect %s => %d\n" ,_osd_ver_desc (or), ret); + goto out; + } + +osd_req_decode_get_attr_list (or, get_attrs, &nelem, &iter); + +OSD_INFO ("Detected %s device\n" , +_osd_ver_desc (or)); + + pFirst = get_attrs[a++].val_ptr; +OSD_INFO ("OSD_ATTR_RI_VENDOR_IDENTIFICATION [%s]\n" , + (char *)pFirst); + + pFirst = get_attrs[a++].val_ptr; +OSD_INFO ("OSD_ATTR_RI_PRODUCT_IDENTIFICATION [%s]\n" , + (char *)pFirst); + + pFirst = get_attrs[a++].val_ptr; +OSD_INFO ("OSD_ATTR_RI_PRODUCT_MODEL [%s]\n" , + (char *)pFirst); + + pFirst = get_attrs[a++].val_ptr; +OSD_INFO ("OSD_ATTR_RI_PRODUCT_REVISION_LEVEL [%u]\n" , +get_unaligned_be32 (pFirst)); + + pFirst = get_attrs[a++].val_ptr; +OSD_INFO ("OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER [%s]\n" , + (char *)pFirst); + + pFirst = get_attrs[a].val_ptr; +OSD_INFO ("OSD_ATTR_RI_OSD_NAME [%s]\n" , (char *)pFirst); + a++; + + pFirst = get_attrs[a++].val_ptr; +OSD_INFO ("OSD_ATTR_RI_TOTAL_CAPACITY [0x%llx]\n" , +_LLU (get_unaligned_be64 (pFirst))); + + pFirst = get_attrs[a++].val_ptr; +OSD_INFO ("OSD_ATTR_RI_USED_CAPACITY [0x%llx]\n" , +_LLU (get_unaligned_be64 (pFirst))); + + pFirst = get_attrs[a++].val_ptr; +OSD_INFO ("OSD_ATTR_RI_NUMBER_OF_PARTITIONS [%llu]\n" , +_LLU (get_unaligned_be64 (pFirst))); + +/* FIXME: Where are the time utilities */ + pFirst = get_attrs[a++].val_ptr; +OSD_INFO ("OSD_ATTR_RI_CLOCK [0x%02x%02x%02x%02x%02x%02x]\n" , + ((char *)pFirst)[0 ], ((char *)pFirst)[1 ], + ((char *)pFirst)[2 ], ((char *)pFirst)[3 ], + ((char *)pFirst)[4 ], ((char *)pFirst)[5 ]); + +if (a < nelem) {/* IBM-OSD-SIM bug, Might not have it */ +unsigned len = get_attrs[a].len; +char sid_dump[32 *4 +2 ];/* 2nibbles+space+ASCII */ + +hex_dump_to_buffer (get_attrs[a].val_ptr, len,32 ,1 , + sid_dump,sizeof (sid_dump), true); +OSD_INFO ("OSD_ATTR_RI_OSD_SYSTEM_ID(%d) [%s]\n" , len, sid_dump); + a++; + } +out: +osd_end_request (or); +return ret; +} + +int osd_auto_detect_ver (struct osd_dev *od,void *caps) +{ +int ret; + +/* Auto-detect the osd version */ + ret =_osd_print_system_info (od, caps); +if (ret) { +osd_dev_set_ver (od,OSD_VER1 ); +OSD_DEBUG ("converting to OSD1\n" ); + ret =_osd_print_system_info (od, caps); + } + +return ret; +} +EXPORT_SYMBOL (osd_auto_detect_ver); +static unsigned _osd_req_cdb_len (struct osd_request *or) {return osd_req_is_ver1 (or) ? OSDv1_TOTAL_CDB_LEN :OSD_TOTAL_CDB_LEN ;
drivers/scsi/osd/osd_uld.c +5 -0
@@ -243,6 +243,7 @@ EXPORT_SYMBOL(osduld_put_device);static int __detect_osd (struct osd_uld_device *oud) {struct scsi_device *scsi_device = oud->od.scsi_device; +char caps[OSD_CAP_LEN ];int error;/* sending a test_unit_ready as first command seems to be needed
@@ -254,6 +255,10 @@ static int __detect_osd(struct osd_uld_device *oud)if (error)OSD_ERR ("warning: scsi_test_unit_ready failed\n" ); +osd_sec_init_nosec_doall_caps (caps, &osd_root_object, false, true); +if (osd_auto_detect_ver (&oud->od, caps)) +return -ENODEV ; +return 0 ; }
include/scsi/osd_initiator.h +3 -0
@@ -67,6 +67,9 @@ void osduld_unregister_test(unsigned ioctl);void osd_dev_init (struct osd_dev *od,struct scsi_device *scsi_device);void osd_dev_fini (struct osd_dev *od); +/* some hi level device operations */ +int osd_auto_detect_ver (struct osd_dev *od,void *caps);/* GFP_KERNEL */ +/* we might want to use function vector in the future */ static inline void osd_dev_set_ver (struct osd_dev *od,enum osd_std_version v) {
Signature · 1 line
1.6.0.1
PATCH 13/16 libosd: SCSI/OSD Sense decoding support
In reply to Boaz HarroshImplementation of the osd_req_decode_sense() API. Can be called by library users to decode what failed in command executions.
Add SCSI_OSD_DPRINT_SENSE Kconfig variable. Possible values are:
0 - Do not print any errors to messages file <KERN_ERR> 1 - (Default) Print only decoded errors that are not recoverable.
Recoverable errors are those that the target has complied with the request but with a warning. For example read passed end of object will return zeros after the last valid byte.
2- Print all errors.
--- drivers/scsi/osd/Kbuild | 6 + drivers/scsi/osd/osd_initiator.c | 191 ++++++++++++++++++++++++++++ include/scsi/osd_initiator.h | 49 +++++++ include/scsi/osd_sense.h | 260 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 506 insertions(+), 0 deletions(-) create mode 100644 include/scsi/osd_sense.h
drivers/scsi/osd/Kbuild +6 -0
@@ -20,6 +20,12 @@ ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE CONFIG_SCSI_OSD_ULD=m ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE +# CONFIG_SCSI_OSD_DPRINT_SENSE = +# 0 - no print of errors +# 1 - print errors +# 2 - errors + warrnings +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1 + # Uncomment to turn debug on # ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
drivers/scsi/osd/osd_initiator.c +191 -0
203 lines not on this page · raw message
include/scsi/osd_initiator.h +49 -0
55 lines not on this page · raw message
include/scsi/osd_sense.h new file +260 -0
260 lines not on this page · raw message
Signature · 1 line
1.6.0.1
James Bottomley
maintainerRe: [PATCH 13/16] libosd: SCSI/OSD Sense decoding support
Quoted 25 lines · Boaz Harrosh
Implementation of the
osd_req_decode_sense()API. Can be called by library users to decode what failed in command executions.Add
SCSI_OSD_DPRINT_SENSEKconfigvariable. Possible values are:
0 - Do not print any errors to messages file <KERN_ERR> 1 - (Default) Print only decoded errors that are not recoverable.
Recoverable errors are those that the target has complied with the request but with a warning. For example read passed end of object will return zeros after the last valid byte.
2- Print all errors.Signed-off-by Boaz Harrosh <[email protected]>--- drivers/scsi/osd/Kbuild | 6 + drivers/scsi/osd/osd_initiator.c | 191 ++++++++++++++++++++++++++++ include/scsi/osd_initiator.h | 49 +++++++ include/scsi/osd_sense.h | 260 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 506 insertions(+), 0 deletions(-) create mode 100644 include/scsi/osd_sense.hdrivers/scsi/osd/Kbuild +0
-0
drivers/scsi/osd/Kbuild ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE · line 27
Quoted 8 lines
drivers/scsi/osd/Kbuild +5
-0@@ -20,6 +20,12 @@ ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE CONFIG_SCSI_OSD_ULD=m ccflags-y += -DCONFIG_SCSI_OSD_ULD -DCONFIG_SCSI_OSD_ULD_MODULE +# CONFIG_SCSI_OSD_DPRINT_SENSE = +# 0 - no print of errors +# 1 - print errors +# 2 - errors + warrnings +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1
Why are these all defines not Kconfig variables?
Quoted 434 lines
drivers/scsi/osd/Kbuild +0
-0# Uncomment to turn debug on # ccflags-y += -DCONFIG_SCSI_OSD_DEBUGdrivers/scsi/osd/osd_initiator.c +191
-0@@ -42,6 +42,8 @@#include <scsi/osd_initiator.h> #include <scsi/osd_sec.h> #include <scsi/osd_attributes.h> +#include <scsi/osd_sense.h> +#include <scsi/scsi_device.h> #include "osd_debug.h" @@ -1339,6 +1341,195 @@ int osd_finalize_request(struct osd_request *or, }EXPORT_SYMBOL (osd_finalize_request); +#define OSD_SENSE_PRINT1(fmt, a...) \ + do { \ + if (__cur_sense_need_output) \ + OSD_ERR(fmt, ##a); \ + } while (0) + +#define OSD_SENSE_PRINT2(fmt, a...) OSD_SENSE_PRINT1(" " fmt, ##a) + +int osd_req_decode_sense_full (struct osd_request *or, +struct osd_sense_info *osi,bool silent, + struct osd_obj_id *bad_obj_list __unused, int max_obj __unused, +struct osd_attr *bad_attr_list,int max_attr) +{ +int sense_len, original_sense_len; +struct osd_sense_info local_osi; +struct scsi_sense_descriptor_based *ssdb; +void *cur_descriptor; +#if (CONFIG_SCSI_OSD_DPRINT_SENSE ==0 ) +const bool __cur_sense_need_output = false; +#else +bool __cur_sense_need_output = !silent; +#endif + +if (!or->request->errors) +return 0 ; + + ssdb = or->request->sense; + sense_len = or->request->sense_len; +if ((sense_len < (int )sizeof (*ssdb) || !ssdb->sense_key)) { +OSD_ERR ("Block-layer returned error(0x%x) but " +"sense_len(%u) || key(%d) is empty\n" , + or->request->errors, sense_len, ssdb->sense_key); +return -EIO ; + } + +if ((ssdb->response_code !=0x72 ) && (ssdb->response_code !=0x73 )) { +OSD_ERR ("Unrecognized scsi sense: rcode=%x length=%d\n" , + ssdb->response_code, sense_len); +return -EIO ; + } + + osi = osi ? : &local_osi; +memset (osi,0 ,sizeof (*osi)); + osi->key = ssdb->sense_key; + osi->additional_code =be16_to_cpu (ssdb->additional_sense_code); + original_sense_len = ssdb->additional_sense_length +8 ; + +#if (CONFIG_SCSI_OSD_DPRINT_SENSE ==1 ) +if (__cur_sense_need_output) + __cur_sense_need_output = (osi->key > scsi_sk_recovered_error); +#endif +OSD_SENSE_PRINT1 ("Main Sense information key=0x%x length(%d, %d) " +"additional_code=0x%x\n" , + osi->key, original_sense_len, sense_len, + osi->additional_code); + +if (original_sense_len < sense_len) + sense_len = original_sense_len; + + cur_descriptor = ssdb->ssd; + sense_len -=sizeof (*ssdb); +while (sense_len >0 ) { +struct scsi_sense_descriptor *ssd = cur_descriptor; +int cur_len = ssd->additional_length +2 ; + + sense_len -= cur_len; + +if (sense_len <0 ) +break ;/* sense was truncated */ + +switch (ssd->descriptor_type) { +case scsi_sense_information: +case scsi_sense_command_specific_information: + { +struct scsi_sense_command_specific_data_descriptor + *sscd = cur_descriptor; + + osi->command_info = +get_unaligned_be64 (&sscd->information) ; +OSD_SENSE_PRINT2 ( +"command_specific_information 0x%llx \n" , +_LLU (osi->command_info)); +break ; + } +case scsi_sense_key_specific: + { +struct scsi_sense_key_specific_data_descriptor + *ssks = cur_descriptor; + + osi->sense_info =get_unaligned_be16 (&ssks->value); +OSD_SENSE_PRINT2 ( +"sense_key_specific_information %u" +"sksv_cd_bpv_bp (0x%x)\n" , + osi->sense_info, ssks->sksv_cd_bpv_bp); +break ; + } +case osd_sense_object_identification: + {/*FIXME: Keep first not last, Store in array*/ +struct osd_sense_identification_data_descriptor + *osidd = cur_descriptor; + + osi->not_initiated_command_functions = +le32_to_cpu (osidd->not_initiated_functions); + osi->completed_command_functions = +le32_to_cpu (osidd->completed_functions); + osi->obj.partition =be64_to_cpu (osidd->partition_id); + osi->obj.id =be64_to_cpu (osidd->object_id); +OSD_SENSE_PRINT2 ( +"object_identification pid=0x%llx oid=0x%llx\n" , +_LLU (osi->obj.partition),_LLU (osi->obj.id)); +OSD_SENSE_PRINT2 ( +"not_initiated_bits(%x) " +"completed_command_bits(%x)\n" , + osi->not_initiated_command_functions, + osi->completed_command_functions); +break ; + } +case osd_sense_response_integrity_check: + { +struct osd_sense_response_integrity_check_descriptor + *osricd = cur_descriptor; +const unsigned len = +sizeof (osricd->integrity_check_value); +char key_dump[len*4 +2 ];/* 2nibbles+space+ASCII */ + +hex_dump_to_buffer (osricd->integrity_check_value, len, +32 ,1 , key_dump,sizeof (key_dump), true); +OSD_SENSE_PRINT2 ("response_integrity [%s]\n" , key_dump); + } +case osd_sense_attribute_identification: + { +struct osd_sense_attributes_data_descriptor + *osadd = cur_descriptor; +int len =min (cur_len, sense_len); +int i =0 ; +struct osd_sense_attr *pattr = osadd->sense_attrs; + +while (len <0 ) { +u32 attr_page =be32_to_cpu (pattr->attr_page); +u32 attr_id =be32_to_cpu (pattr->attr_id); + +if (i++ ==0 ) { + osi->attr.attr_page = attr_page; + osi->attr.attr_id = attr_id; + } + +if (bad_attr_list && max_attr) { + bad_attr_list->attr_page = attr_page; + bad_attr_list->attr_id = attr_id; + bad_attr_list++; + max_attr--; + } +OSD_SENSE_PRINT2 ( +"osd_sense_attribute_identification" +"attr_page=0x%x attr_id=0x%x\n" , + attr_page, attr_id); + } + } +/*These are not legal for OSD*/ +case scsi_sense_field_replaceable_unit: +OSD_SENSE_PRINT2 ("scsi_sense_field_replaceable_unit\n" ); +break ; +case scsi_sense_stream_commands: +OSD_SENSE_PRINT2 ("scsi_sense_stream_commands\n" ); +break ; +case scsi_sense_block_commands: +OSD_SENSE_PRINT2 ("scsi_sense_block_commands\n" ); +break ; +case scsi_sense_ata_return: +OSD_SENSE_PRINT2 ("scsi_sense_ata_return\n" ); +break ; +default : +if (ssd->descriptor_type <= scsi_sense_Reserved_last) +OSD_SENSE_PRINT2 ( +"scsi_sense Reserved descriptor (0x%x)" , + ssd->descriptor_type); +else +OSD_SENSE_PRINT2 ( +"scsi_sense Vendor descriptor (0x%x)" , + ssd->descriptor_type); + } + + cur_descriptor += cur_len; + } + +return (osi->key > scsi_sk_recovered_error) ? -EIO :0 ; +} +EXPORT_SYMBOL (osd_req_decode_sense_full); +/* * Implementation of osd_sec.h API * TODO: Move to a separate osd_sec.c file at a later stage. include/scsi/osd_initiator.h +49
-0@@ -217,6 +217,55 @@ int osd_execute_request_async(struct osd_request *or, osd_req_done_fn *done, void *private);/** +* osd_req_decode_sense_full - Decode sense information after execution. +* +* @or: - osd_request to examine +* @osi - Recievs a more detailed error report information (optional). +* @silent - Do not print to dmsg (Even if enabled) +* @bad_obj_list - Some commands act on multiple objects. Failed objects will +* be recieved here (optional) +* @max_obj - Size of @bad_obj_list. +* @bad_attr_list - List of failing attributes (optional) +* @max_attr - Size of @bad_attr_list. +* +* After execution, sense + return code can be analyzed using this function. The +* return code is the final disposition on the error. So it is possible that a +* CHECK_CONDITION was returned from target but this will return NO_ERROR, for +* example on recovered errors. All parameters are optional if caller does +* not need any returned information. +* Note: This function will also dump the error to dmsg according to settings +* of the SCSI_OSD_DPRINT_SENSE Kconfig value. Set @silent if you know the +* command would routinely fail, to not spam the dmsg file. +*/ +struct osd_sense_info { +int key;/* one of enum scsi_sense_keys */ +int additional_code ;/* enum osd_additional_sense_codes */ +union {/* Sense specific information */ +u16 sense_info; +u16 cdb_field_offset;/* scsi_invalid_field_in_cdb */ + }; +union {/* Command specific information */ +u64 command_info; + }; + +u32 not_initiated_command_functions;/* osd_command_functions_bits */ +u32 completed_command_functions;/* osd_command_functions_bits */ +struct osd_obj_id obj; +struct osd_attr attr; +}; + +int osd_req_decode_sense_full (struct osd_request *or, +struct osd_sense_info *osi,bool silent, +struct osd_obj_id *bad_obj_list,int max_obj, +struct osd_attr *bad_attr_list,int max_attr); + +static inline int osd_req_decode_sense (struct osd_request *or, +struct osd_sense_info *osi) +{ +return osd_req_decode_sense_full (or, osi, false,NULL ,0 ,NULL ,0 ); +} + +/** * osd_end_request - return osd_request to free store * * @or: osd_request to free include/scsi/osd_sense.h new file +156
-0@@ -0,0 +1,260 @@ +/* +* osd_sense.h - OSD Related sense handling definitions. +* +* Copyright (C) 2008 Panasas Inc. All rights reserved. +* +* Authors: +* Boaz Harrosh <[email protected]> +* Benny Halevy <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 +* +* This file contains types and constants that are defined by the protocol +* Note: All names and symbols are taken from the OSD standard's text. +*/ +#ifndef __OSD_SENSE_H__ +#define __OSD_SENSE_H__ + +#include <scsi/osd_protocol.h> + +/* SPC3r23 4.5.6 Sense key and sense code definitions table 27 */ +enum scsi_sense_keys { + scsi_sk_no_sense =0x0 , + scsi_sk_recovered_error =0x1 , + scsi_sk_not_ready =0x2 , + scsi_sk_medium_error =0x3 , + scsi_sk_hardware_error =0x4 , + scsi_sk_illegal_request =0x5 , + scsi_sk_unit_attention =0x6 , + scsi_sk_data_protect =0x7 , + scsi_sk_blank_check =0x8 , + scsi_sk_vendor_specific =0x9 , + scsi_sk_copy_aborted =0xa , + scsi_sk_aborted_command =0xb , + scsi_sk_volume_overflow =0xd , + scsi_sk_miscompare =0xe , + scsi_sk_reserved =0xf , +}; + +/* SPC3r23 4.5.6 Sense key and sense code definitions table 28 */ +/* Note: only those which can be returned by an OSD target. Most of +* these errors are taken care of by the generic scsi layer. +*/ +enum osd_additional_sense_codes { + scsi_no_additional_sense_information =0x0000 , + scsi_operation_in_progress =0x0016 , + scsi_cleaning_requested =0x0017 , + scsi_lunr_cause_not_reportable =0x0400 , + scsi_logical_unit_is_in_process_of_becoming_ready =0x0401 , + scsi_lunr_initializing_command_required =0x0402 , + scsi_lunr_manual_intervention_required =0x0403 , + scsi_lunr_operation_in_progress =0x0407 , + scsi_lunr_selftest_in_progress =0x0409 , + scsi_luna_asymmetric_access_state_transition =0x040a , + scsi_luna_target_port_in_standby_state =0x040b , + scsi_luna_target_port_in_unavailable_state =0x040c , + scsi_lunr_notify_enable_spinup_required =0x0411 , + scsi_logical_unit_does_not_respond_to_selection =0x0500 , + scsi_logical_unit_communication_failure =0x0800 , + scsi_logical_unit_communication_timeout =0x0801 , + scsi_logical_unit_communication_parity_error =0x0802 , + scsi_error_log_overflow =0x0a00 , + scsi_warning =0x0b00 , + scsi_warning_specified_temperature_exceeded =0x0b01 , + scsi_warning_enclosure_degraded =0x0b02 , + scsi_write_error_unexpected_unsolicited_data =0x0c0c , + scsi_write_error_not_enough_unsolicited_data =0x0c0d , + scsi_invalid_information_unit =0x0e00 , + scsi_invalid_field_in_command_information_unit =0x0e03 , + scsi_read_error_failed_retransmission_request =0x1113 , + scsi_parameter_list_length_error =0x1a00 , + scsi_invalid_command_operation_code =0x2000 , + scsi_invalid_field_in_cdb =0x2400 , + osd_security_audit_value_frozen =0x2404 , + osd_security_working_key_frozen =0x2405 , + osd_nonce_not_unique =0x2406 , + osd_nonce_timestamp_out_of_range =0x2407 , + scsi_logical_unit_not_supported =0x2500 , + scsi_invalid_field_in_parameter_list =0x2600 , + scsi_parameter_not_supported =0x2601 , + scsi_parameter_value_invalid =0x2602 , + scsi_invalid_release_of_persistent_reservation =0x2604 , + osd_invalid_dataout_buffer_integrity_check_value =0x260f , + scsi_not_ready_to_ready_change_medium_may_have_changed =0x2800 , + scsi_power_on_reset_or_bus_device_reset_occurred =0x2900 , + scsi_power_on_occurred =0x2901 , + scsi_scsi_bus_reset_occurred =0x2902 , + scsi_bus_device_reset_function_occurred =0x2903 , + scsi_device_internal_reset =0x2904 , + scsi_transceiver_mode_changed_to_single_ended =0x2905 , + scsi_transceiver_mode_changed_to_lvd =0x2906 , + scsi_i_t_nexus_loss_occurred =0x2907 , + scsi_parameters_changed =0x2a00 , + scsi_mode_parameters_changed =0x2a01 , + scsi_asymmetric_access_state_changed =0x2a06 , + scsi_priority_changed =0x2a08 , + scsi_command_sequence_error =0x2c00 , + scsi_previous_busy_status =0x2c07 , + scsi_previous_task_set_full_status =0x2c08 , + scsi_previous_reservation_conflict_status =0x2c09 , + osd_partition_or_collection_contains_user_objects =0x2c0a , + scsi_commands_cleared_by_another_initiator =0x2f00 , + scsi_cleaning_failure =0x3007 , + scsi_enclosure_failure =0x3400 , + scsi_enclosure_services_failure =0x3500 , + scsi_unsupported_enclosure_function =0x3501 , + scsi_enclosure_services_unavailable =0x3502 , + scsi_enclosure_services_transfer_failure =0x3503 , + scsi_enclosure_services_transfer_refused =0x3504 , + scsi_enclosure_services_checksum_error =0x3505 , + scsi_rounded_parameter =0x3700 , + osd_read_past_end_of_user_object =0x3b17 , + scsi_logical_unit_has_not_self_configured_yet =0x3e00 , + scsi_logical_unit_failure =0x3e01 , + scsi_timeout_on_logical_unit =0x3e02 , + scsi_logical_unit_failed_selftest =0x3e03 , + scsi_logical_unit_unable_to_update_selftest_log =0x3e04 , + scsi_target_operating_conditions_have_changed =0x3f00 , + scsi_microcode_has_been_changed =0x3f01 , + scsi_inquiry_data_has_changed =0x3f03 , + scsi_echo_buffer_overwritten =0x3f0f , + scsi_diagnostic_failure_on_component_nn_first =0x4080 , + scsi_diagnostic_failure_on_component_nn_last =0x40ff , + scsi_message_error =0x4300 , + scsi_internal_target_failure =0x4400 , + scsi_select_or_reselect_failure =0x4500 , + scsi_scsi_parity_error =0x4700 , + scsi_data_phase_crc_error_detected =0x4701 , + scsi_scsi_parity_error_detected_during_st_data_phase =0x4702 , + scsi_asynchronous_information_protection_error_detected =0x4704 , + scsi_protocol_service_crc_error =0x4705 , + scsi_phy_test_function_in_progress =0x4706 , + scsi_invalid_message_error =0x4900 , + scsi_command_phase_error =0x4a00 , + scsi_data_phase_error =0x4b00 , + scsi_logical_unit_failed_self_configuration =0x4c00 , + scsi_overlapped_commands_attempted =0x4e00 , + osd_quota_error =0x5507 , + scsi_failure_prediction_threshold_exceeded =0x5d00 , + scsi_failure_prediction_threshold_exceeded_false =0x5dff , + scsi_voltage_fault =0x6500 , +}; + +enum scsi_descriptor_types { + scsi_sense_information =0x0 , + scsi_sense_command_specific_information =0x1 , + scsi_sense_key_specific =0x2 , + scsi_sense_field_replaceable_unit =0x3 , + scsi_sense_stream_commands =0x4 , + scsi_sense_block_commands =0x5 , + osd_sense_object_identification =0x6 , + osd_sense_response_integrity_check =0x7 , + osd_sense_attribute_identification =0x8 , + scsi_sense_ata_return =0x9 , + + scsi_sense_Reserved_first = 0x0A,
include/scsi/osd_sense.h line 166
Quoted 10 lines
include/scsi/osd_sense.h new file +10
-0+ scsi_sense_Reserved_last =0x7F , + scsi_sense_Vendor_specific_first =0x80 , + scsi_sense_Vendor_specific_last = 0xFF, +}; + +struct scsi_sense_descriptor {/* for picking into desc type */ +u8 descriptor_type;/* one of enum scsi_descriptor_types */ +u8 additional_length;/* n - 1 */ +u8 data[]; +} __packed;
Why is it necessary to do a complete duplication of all the sense header handling and print out in include/scsi/scsi_eh.h and drivers/scsi/constants.c ... can't these two frameworks be integrated?
James
Re: [PATCH 13/16] libosd: SCSI/OSD Sense decoding support
Quoted 10 lines · James Bottomley
Review
Quoted 6 lines · Boaz Harrosh
(quoted diff) +5
-0+# CONFIG_SCSI_OSD_DPRINT_SENSE = +# 0 - no print of errors +# 1 - print errors +# 2 - errors + warrnings +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1Why are these all defines not
Kconfigvariables?
They are a "Kconfig variables". What you see above is a section of the Kbuild file that's for the out-of-tree compilation. [ifneq ($(OSD_INC),)] For the out-of-tree compilation the Kbuild file defines everything as configured in.
<snip>
include/scsi/osd_sense.h +0 -0
Quoted 23 lines
Quoted 23 lines
new file mode 100644
index 0000000..ff9b33cinclude/scsi/osd_sense.h new file +17
-0@@ -0,0 +1,260 @@ +/* +* osd_sense.h - OSD Related sense handling definitions. +* +* Copyright (C) 2008 Panasas Inc. All rights reserved. +* +* Authors: +* Boaz Harrosh <[email protected]> +* Benny Halevy <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 +* +* This file contains types and constants that are defined by the protocol +* Note: All names and symbols are taken from the OSD standard's text. +*/ +#ifndef __OSD_SENSE_H__ +#define __OSD_SENSE_H__
<snip>
Quoted 7 lines
Quoted 7 lines
include/scsi/osd_sense.h new file +7
-0+ scsi_sense_Reserved_first =0x0A , + scsi_sense_Reserved_last =0x7F , + scsi_sense_Vendor_specific_first =0x80 , + scsi_sense_Vendor_specific_last = 0xFF, +}; + +struct scsi_sense_descriptor { /* for picking into desc type */
Quoted 9 lines
include/scsi/osd_sense.h
Quoted 4 lines
include/scsi/osd_sense.h new file +4
-0+u8 descriptor_type;/* one of enum scsi_descriptor_types */ +u8 additional_length;/* n - 1 */ +u8 data[]; +} __packed;Why is it necessary to do a complete duplication of all the sense header handling and print out in
include/scsi/scsi_eh.handdrivers/scsi/constants.c... can't these two frameworks be integrated?
I have tried.
Some of this stuff is new and exclusive to OSD so the file is needed. The rest is buried in constants.c while I need them in an header file. If it is accepted by you to take some of constants.c and put them in an header then, sure I can do that. Refactor some of above stuff and constants.c stuff into an scsi_sense.h file and use them at both places.
(I will send an RFC after things settle a bit)
Other then that, the source of the osd_req_decode_sense() is totally new to osd. An osd target returns very detailed, variable length, sense information that denotes exactly what field of the CDB and/or buffer-data failed it's checks as well as details on other failures and conditions. Also later we will support security signatures of sense data.
Quoted 2 lines
James
Thanks
Boaz
James Bottomley
maintainerRe: [PATCH 13/16] libosd: SCSI/OSD Sense decoding support
Quoted 12 lines · Boaz Harrosh
Quoted 10 lines · James Bottomley
Review
Quoted 6 lines · Boaz Harrosh
(quoted diff) +5
-0+# CONFIG_SCSI_OSD_DPRINT_SENSE = +# 0 - no print of errors +# 1 - print errors +# 2 - errors + warrnings +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1Why are these all defines not
Kconfigvariables?
Quoted 4 lines
They are a "
Kconfigvariables". What you see above is a section of theKbuildfile that's for the out-of-tree compilation. [ifneq ($(OSD_INC),)] For the out-of-tree compilation theKbuildfile defines everything as configured in.
OK, let me rephrase the question "what's a file designed for out of tree compiles doing in-tree?".
Quoted 43 lines
<snip>
include/scsi/osd_sense.h +0
-0Quoted 23 lines
Quoted 23 lines
new file mode 100644
index 0000000..ff9b33cinclude/scsi/osd_sense.h new file +17
-0@@ -0,0 +1,260 @@ +/* +* osd_sense.h - OSD Related sense handling definitions. +* +* Copyright (C) 2008 Panasas Inc. All rights reserved. +* +* Authors: +* Boaz Harrosh <[email protected]> +* Benny Halevy <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 +* +* This file contains types and constants that are defined by the protocol +* Note: All names and symbols are taken from the OSD standard's text. +*/ +#ifndef __OSD_SENSE_H__ +#define __OSD_SENSE_H__<snip>
Quoted 7 lines
Quoted 7 lines
include/scsi/osd_sense.h new file +7
-0+ scsi_sense_Reserved_first =0x0A , + scsi_sense_Reserved_last =0x7F , + scsi_sense_Vendor_specific_first =0x80 , + scsi_sense_Vendor_specific_last = 0xFF, +}; + +struct scsi_sense_descriptor { /* for picking into desc type */Quoted 9 lines
include/scsi/osd_sense.h
Quoted 4 lines
include/scsi/osd_sense.h new file +4
-0+u8 descriptor_type;/* one of enum scsi_descriptor_types */ +u8 additional_length;/* n - 1 */ +u8 data[]; +} __packed;Why is it necessary to do a complete duplication of all the sense header handling and print out in
include/scsi/scsi_eh.handdrivers/scsi/constants.c... can't these two frameworks be integrated?
Quoted 7 lines
I have tried.
Some of this stuff is new and exclusive to OSD so the file is needed. The rest is buried inconstants.cwhile I need them in an header file. If it is accepted by you to take some ofconstants.cand put them in an header then, sure I can do that. Refactor some of above stuff andconstants.cstuff into anscsi_sense.hfile and use them at both places.
(I will send an RFC after things settle a bit)
That's what I'd prefer to see, yes. The linux tradition is that if a particular piece of code, which was designed for use in X could be used in Y, we don't duplicate it for Y, we redesign it so it can be used in
both X and Y ... that's how we keep the kernel clean and neat. Of
course, if you're really lucky, the X user already figured out a more generic framework and it's a simple matter to reuse it. I'm afraid it's a bit more work in this case.
Quoted 5 lines
Other then that, the source of the
osd_req_decode_sense()is totally new to osd. An osd target returns very detailed, variable length, sense information that denotes exactly what field of the CDB and/or buffer-data failed it's checks as well as details on other failures and conditions. Also later we will support security signatures of sense data.
But this is all just an extension of the basic SAM defined sense format.
James
Re: [PATCH 13/16] libosd: SCSI/OSD Sense decoding support
Quoted 11 lines · James Bottomley
Quoted 10 lines · Boaz Harrosh
Quoted 9 lines · James Bottomley
Review
Quoted 6 lines · Boaz Harrosh
(quoted diff) +5
-0+# CONFIG_SCSI_OSD_DPRINT_SENSE = +# 0 - no print of errors +# 1 - print errors +# 2 - errors + warrnings +ccflags-y += -DCONFIG_SCSI_OSD_DPRINT_SENSE=1Why are these all defines not
Kconfigvariables?
Quoted 8 lines
Quoted 4 lines
They are a "
Kconfigvariables". What you see above is a section of theKbuildfile that's for the out-of-tree compilation. [ifneq ($(OSD_INC),)] For the out-of-tree compilation theKbuildfile defines everything as configured in.OK, let me rephrase the question "what's a file designed for out of tree compiles doing in-tree?".
Sorry for not explaining better.
The Kbuild file is an in-tree file for sure. It is what builds the drivers/scsi/osd directory. (The Makefile in that subdir is only for out-of-tree and is not included in the patchset)
Now places in the source-code and in Kbuild itself depend on Kconfig doing it's thing. But when the same-exact source is compiled out-of-tree, possibly against a Kernel that does not have OSD at all, the Kconfigure is emulated (above).
I have chosen to do that rather then keep two sets of files like other projects do. Because I have one master git-tree. The in-tree has the out-of-tree git as a remote. With an automatic script I rebase the out-of-tree patches onto the relevant in-tree branch. This way I have only one master repository.
All this is done by a small ifneq(,)/endif in Kbuild file. The rest is totally transparent to source-code or otherwise.
Please let me keep it. If not I will need to patch Kbuild from out-of-tree branches which is also in the in-tree branches. This will make it hard to maintain in future versions without causing merge conflicts. I would like to keep all individual files identical in the two views and keep the difference in separate files.
Thanks in advance
Quoted 49 lines
Quoted 41 lines
<snip>
include/scsi/osd_sense.h +0
-0Quoted 23 lines
Quoted 23 lines
new file mode 100644
index 0000000..ff9b33cinclude/scsi/osd_sense.h new file +17
-0@@ -0,0 +1,260 @@ +/* +* osd_sense.h - OSD Related sense handling definitions. +* +* Copyright (C) 2008 Panasas Inc. All rights reserved. +* +* Authors: +* Boaz Harrosh <[email protected]> +* Benny Halevy <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 +* +* This file contains types and constants that are defined by the protocol +* Note: All names and symbols are taken from the OSD standard's text. +*/ +#ifndef __OSD_SENSE_H__ +#define __OSD_SENSE_H__<snip>
Quoted 6 lines
Quoted 6 lines
include/scsi/osd_sense.h new file +6
-0+ scsi_sense_Reserved_first =0x0A , + scsi_sense_Reserved_last =0x7F , + scsi_sense_Vendor_specific_first =0x80 , + scsi_sense_Vendor_specific_last = 0xFF, +}; +Quoted 9 lines
include/scsi/osd_sense.h
Quoted 5 lines
include/scsi/osd_sense.h new file +5
-0+struct scsi_sense_descriptor {/* for picking into desc type */ +u8 descriptor_type;/* one of enum scsi_descriptor_types */ +u8 additional_length;/* n - 1 */ +u8 data[]; +} __packed;Why is it necessary to do a complete duplication of all the sense header handling and print out in
include/scsi/scsi_eh.handdrivers/scsi/constants.c... can't these two frameworks be integrated?Quoted 7 lines
I have tried.
Some of this stuff is new and exclusive to OSD so the file is needed. The rest is buried inconstants.cwhile I need them in an header file. If it is accepted by you to take some ofconstants.cand put them in an header then, sure I can do that. Refactor some of above stuff andconstants.cstuff into anscsi_sense.hfile and use them at both places.
(I will send an RFC after things settle a bit)
Quoted 8 lines
That's what I'd prefer to see, yes. The linux tradition is that if a particular piece of code, which was designed for use in X could be used in Y, we don't duplicate it for Y, we redesign it so it can be used in
both X and Y ... that's how we keep the kernel clean and neat. Of
course, if you're really lucky, the X user already figured out a more generic framework and it's a simple matter to reuse it. I'm afraid it's a bit more work in this case.
Yes, it's more work. And I don't yet have a clear picture on how to do it in a way that does not inject pointless code to the regular case where OSD is not used. Let me think about it for a small while. I promise to get to it ASAP.
Quoted 8 lines
Quoted 5 lines
Other then that, the source of the
osd_req_decode_sense()is totally new to osd. An osd target returns very detailed, variable length, sense information that denotes exactly what field of the CDB and/or buffer-data failed it's checks as well as details on other failures and conditions. Also later we will support security signatures of sense data.But this is all just an extension of the basic SAM defined sense format.
Well yes and no -
Other then in OSD, nowhere in scsi is there a variable length of sense information. That is: in osd you can return an array of bad attributes or an array of bad objects. Also there are OSD specific extensions that are defined in the osd T10 document only. I will try to divide the common work from the OSD extensions and submit the common part to generic layer but in a way that could be reused by both.
Please note that I'm not the first offender. There are other error handlers that duplicate some of what is done here for their specific transports / command-sets.
Quoted 3 lines
James
Thanks
Boaz
PATCH 14/16 osd: Documentation for OSD library
In reply to Boaz HarroshAdd osd.txt to Documentation/scsi/
--- Documentation/scsi/osd.txt | 198 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 198 insertions(+), 0 deletions(-) create mode 100644 Documentation/scsi/osd.txt
Documentation/scsi/osd.txt new file +198 -0
@@ -0,0 +1,198 @@ +The OSD Standard +================ +OSD (Object-Based Storage Device) is a T10 SCSI command set that is designed +to provide efficient operation of input/output logical units that manage the +allocation, placement, and accessing of variable-size data-storage containers, +called objects. Objects are intended to contain operating system and application +constructs. Each object has associated attributes attached to it, which are +integral part of the object and provide metadata about the object. The standard +defines some common obligatory attributes, but user attributes can be added as +needed. + +See: http://www.t10.org/ftp/t10/drafts/osd2/ for the latest draft for OSD 2 +or search the web for "OSD SCSI" + +OSD in the Linux Kernel +======================= +osd-initiator: + The main component of OSD in Kernel is the osd-initiator library. Its main +user is intended to be the pNFS-over-objects layout driver, which uses objects +as its back-end data storage. Other clients are the other osd parts listed below. + +osd-uld: + This is a SCSI ULD that registers for OSD type devices and provides a testing +platform, both for the in-kernel initiator as well as connected targets. It +currently has no useful user-mode API, though it could have if need be. + +exofs: + Is an OSD based Linux file system. It uses the osd-initiator and osd-uld, +to export a usable file system for users. +See Documentation/filesystems/exofs.txt for more details + +osd target: + There are no current plans for an OSD target implementation in kernel. For all +needs, a user-mode target that is based on the scsi tgt target framework is +available from Ohio Supercomputer Center (OSC) at: +http://www.open-osd.org/bin/view/Main/OscOsdProject +There are several other target implementations. See http://open-osd.org for more +links. + +Files and Folders +================= +This is the complete list of files included in this work: +include/scsi/ + osd_initiator.h Main API for the initiator library + osd_types.h Common OSD types + osd_sec.h Security Manager API + osd_protocol.h Wire definitions of the OSD standard protocol + osd_attributes.h Wire definitions of OSD attributes + +drivers/scsi/osd/ + osd_initiator.c OSD-Initiator library implementation + osd_uld.c The OSD scsi ULD + osd_ktest.{h,c} In-kernel test suite (called by osd_uld) + osd_debug.h Some printk macros + Makefile For both in-tree and out-of-tree compilation + Kconfig Enables inclusion of the different pieces + osd_test.c User-mode application to call the kernel tests + +The OSD-Initiator Library +========================= +osd_initiator is a low level implementation of an osd initiator encoder. +But even though, it should be intuitive and easy to use. Perhaps over time an +higher lever will form that automates some of the more common recipes. + +init/fini: +- osd_dev_init() associates a scsi_device with an osd_dev structure + and initializes some global pools. This should be done once per scsi_device + (OSD LUN). The osd_dev structure is needed for calling osd_start_request(). + +- osd_dev_fini() cleans up before a osd_dev/scsi_device destruction. + +OSD commands encoding, execution, and decoding of results: + +struct osd_request's is used to iteratively encode an OSD command and carry +its state throughout execution. Each request goes through these stages: + +a. osd_start_request() allocates the request. + +b. Any of the osd_req_* methods is used to encode a request of the specified + type. + +c. osd_req_add_{get,set}_attr_* may be called to add get/set attributes to the + CDB. "List" or "Page" mode can be used exclusively. The attribute-list API + can be called multiple times on the same request. However, only one + attribute-page can be read, as mandated by the OSD standard. + +d. osd_finalize_request() computes offsets into the data-in and data-out buffers + and signs the request using the provided capability key and integrity- + check parameters. + +e. osd_execute_request() may be called to execute the request via the block + layer and wait for its completion. The request can be executed + asynchronously by calling the block layer API directly. + +f. After execution, osd_req_decode_sense() can be called to decode the request's + sense information. + +g. osd_req_decode_get_attr() may be called to retrieve osd_add_get_attr_list() + values. + +h. osd_end_request() must be called to deallocate the request and any resource + associated with it. Note that osd_end_request cleans up the request at any + stage and it must always be called after a successful osd_start_request(). + +osd_request's structure: + +The OSD standard defines a complex structure of IO segments pointed to by +members in the CDB. Up to 3 segments can be deployed in the IN-Buffer and up to +4 in the OUT-Buffer. The ASCII illustration below depicts a secure-read with +associated get+set of attributes-lists. Other combinations very on the same +basic theme. From no-segments-used up to all-segments-used. + +|________OSD-CDB__________| +| | +|read_len (offset=0) -|---------\ +| | | +|get_attrs_list_length | | +|get_attrs_list_offset -|----\ | +| | | | +|retrieved_attrs_alloc_len| | | +|retrieved_attrs_offset -|----|----|-\ +| | | | | +|set_attrs_list_length | | | | +|set_attrs_list_offset -|-\ | | | +| | | | | | +|in_data_integ_offset -|-|--|----|-|-\ +|out_data_integ_offset -|-|--|--\ | | | +\_________________________/ | | | | | | + | | | | | | +|_______OUT-BUFFER________| | | | | | | +| Set attr list |</ | | | | | +| | | | | | | +|-------------------------| | | | | | +| Get attr descriptors |<---/ | | | | +| | | | | | +|-------------------------| | | | | +| Out-data integrity |<------/ | | | +| | | | | +\_________________________/ | | | + | | | +|________IN-BUFFER________| | | | +| In-Data read |<--------/ | | +| | | | +|-------------------------| | | +| Get attr list |<----------/ | +| | | +|-------------------------| | +| In-data integrity |<------------/ +| | +\_________________________/ + +A block device request can carry bidirectional payload by means of associating +a bidi_read request with a main write-request. Each in/out request is described +by a chain of BIOs associated with each request. +The CDB is of a SCSI VARLEN CDB format, as described by OSD standard. +The OSD standard also mandates alignment restrictions at start of each segment. + +In the code, in struct osd_request, there are two _osd_io_info structures to +describe the IN/OUT buffers above, two BIOs for the data payload and up to five +_osd_req_data_segment structures to hold the different segments allocation and +information. + +Important: We have chosen to disregard the assumption that a BIO-chain (and +the resulting sg-list) describes a linear memory buffer. Meaning only first and +last scatter chain can be incomplete and all the middle chains are of PAGE_SIZE. +For us, a scatter-gather-list, as its name implies and as used by the Networking +layer, is to describe a vector of buffers that will be transferred to/from the +wire. It works very well with current iSCSI transport. iSCSI is currently the +only deployed OSD transport. In the future we anticipate SAS and FC attached OSD +devices as well. + +The OSD Testing ULD +=================== +TODO: More user-mode control on tests. + +Authors, Mailing list +===================== +Please communicate with us on any deployment of osd, whether using this code +or not. + +Any problems, questions, bug reports, lonely OSD nights, please email: + OSD Dev List <[email protected]> + +More up-to-date information can be found on: +http://open-osd.org + +Boaz Harrosh <[email protected]> +Benny Halevy <[email protected]> + +References +========== +Weber, R., "SCSI Object-Based Storage Device Commands", +T10/1355-D ANSI/INCITS 400-2004, +http://www.t10.org/ftp/t10/drafts/osd/osd-r10.pdf + +Weber, R., "SCSI Object-Based Storage Device Commands -2 (OSD-2)" +T10/1729-D, Working Draft, rev. 3 +http://www.t10.org/ftp/t10/drafts/osd2/osd2r03.pdf
Signature · 1 line
1.6.0.1
PATCH 15/16 osd: Kconfig file for in-tree builds
In reply to Boaz HarroshKconfig file for the drivers/scsi/osd subdirectory. Adds the following config items:
config SCSI_OSD_INITIATOR
config SCSI_OSD_ULD
config SCSI_OSD_DPRINT_SENSE
config SCSI_OSD_DEBUG
--- drivers/scsi/osd/Kconfig | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 53 insertions(+), 0 deletions(-) create mode 100644 drivers/scsi/osd/Kconfig
drivers/scsi/osd/Kconfig new file +53 -0
@@ -0,0 +1,53 @@ +# +# Kernel configuration file for the OSD scsi protocol +# +# Copyright (C) 2008 Panasas Inc. All rights reserved. +# +# Authors: +# Boaz Harrosh <[email protected]> +# Benny Halevy <[email protected]> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public version 2 License as +# published by the Free Software Foundation +# +# FIXME: SCSI_OSD_INITIATOR should select CONFIG (HMAC) SHA1 somehow. +# How is it done properly? +# + +config SCSI_OSD_INITIATOR + tristate "OSD-Initiator library" + depends on SCSI + help + Enable the OSD-Initiator library (libosd.ko). + NOTE: You must also select CRYPTO_SHA1 + CRYPTO_HMAC and their + dependencies + +config SCSI_OSD_ULD + tristate "OSD Upper Level driver" + depends on SCSI_OSD_INITIATOR + help + Build a SCSI upper layer driver that exports /dev/osdX devices + to user-mode for testing and controlling OSD devices. It is also + needed by exofs, for mounting an OSD based file system. + +config SCSI_OSD_DPRINT_SENSE + int "(0-2) When sense is returned, DEBUG print all sense descriptors" + default 1 + depends on SCSI_OSD_INITIATOR + help + When a CHECK_CONDITION status is returned from a target, and a + sense-buffer is retrieved, turning this on will dump a full + sense-decoding message. Setting to 2 will also print recoverable + errors that might be regularly returned for some filesystem + operations. + +config SCSI_OSD_DEBUG + bool "Compile All OSD modules with lots of DEBUG prints" + default n + depends on SCSI_OSD_INITIATOR + help + OSD Code is populated with lots of OSD_DEBUG(..) printouts to + dmesg. Enable this if you found a bug and you want to help us + track the problem (see also MAINTAINERS). Setting this will also + force SCSI_OSD_DPRINT_SENSE=2.
Signature · 1 line
1.6.0.1
PATCH 16/16 scsi: Add osd library to build system
In reply to Boaz HarroshOSD 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
--- MAINTAINERS | 10 ++++++++++ drivers/scsi/Kconfig | 2 ++ drivers/scsi/Makefile | 2 ++ 3 files changed, 14 insertions(+), 0 deletions(-)
MAINTAINERS +10 -0
@@ -3260,6 +3260,16 @@ L: [email protected] W: http://www.nongnu.org/orinoco/ S: Maintained +OSD LIBRARY +P: Boaz Harrosh +M: [email protected] +P: Benny Halevy +M: [email protected] +L: [email protected] +W: http://open-osd.org +T: git://git.open-osd.org/open-osd.git +S: Maintained + P54 WIRELESS DRIVER P: Michael Wu M: [email protected]
drivers/scsi/Kconfig +2 -0
@@ -1806,4 +1806,6 @@ source "drivers/scsi/pcmcia/Kconfig" source "drivers/scsi/device_handler/Kconfig" +source "drivers/scsi/osd/Kconfig" + endmenu
drivers/scsi/Makefile +2 -0
@@ -137,6 +137,8 @@ obj-$(CONFIG_CHR_DEV_SG) += sg.o obj-$(CONFIG_CHR_DEV_SCH) += ch.o obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o +obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/ + # This goes last, so that "real" scsi devices probe earlier obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
Signature · 1 line
1.6.0.1