aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/osd
diff options
context:
space:
mode:
authorBoaz Harrosh <bharrosh@panasas.com>2009-01-25 09:55:30 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-03-12 13:58:06 -0400
commit02941a530ef736210b4cf8b24dd34c238d5d5a40 (patch)
treef4ac1f663392cbc107e618dd28caa65f27d608ae /drivers/scsi/osd
parentde258bf5e63863f42e0f9a7c5ffd29916a41e399 (diff)
[SCSI] libosd: OSDv1 preliminary implementation
Implementation of the most basic OSD functionality and infrastructure. Mainly Format, Create/Remove Partition, Create/Remove Object, and read/write. - Add Makefile and Kbuild to compile libosd.ko - osd_initiator.c Implementation file for osd_initiator.h and osd_sec.h APIs - osd_debug.h - Some kprintf macro definitions Signed-off-by: Boaz Harrosh <bharrosh@panasas.com> Reviewed-by: Benny Halevy <bhalevy@panasas.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/osd')
-rw-r--r--drivers/scsi/osd/Kbuild32
-rwxr-xr-xdrivers/scsi/osd/Makefile37
-rw-r--r--drivers/scsi/osd/osd_debug.h30
-rw-r--r--drivers/scsi/osd/osd_initiator.c448
4 files changed, 547 insertions, 0 deletions
diff --git a/drivers/scsi/osd/Kbuild b/drivers/scsi/osd/Kbuild
new file mode 100644
index 000000000000..a95e0251005c
--- /dev/null
+++ b/drivers/scsi/osd/Kbuild
@@ -0,0 +1,32 @@
1#
2# Kbuild for the OSD modules
3#
4# Copyright (C) 2008 Panasas Inc. All rights reserved.
5#
6# Authors:
7# Boaz Harrosh <bharrosh@panasas.com>
8# Benny Halevy <bhalevy@panasas.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2
12#
13
14ifneq ($(OSD_INC),)
15# we are built out-of-tree Kconfigure everything as on
16
17CONFIG_SCSI_OSD_INITIATOR=m
18ccflags-y += -DCONFIG_SCSI_OSD_INITIATOR -DCONFIG_SCSI_OSD_INITIATOR_MODULE
19
20# Uncomment to turn debug on
21# ccflags-y += -DCONFIG_SCSI_OSD_DEBUG
22
23# if we are built out-of-tree and the hosting kernel has OSD headers
24# then "ccflags-y +=" will not pick the out-off-tree headers. Only by doing
25# this it will work. This might break in future kernels
26LINUXINCLUDE := -I$(OSD_INC) $(LINUXINCLUDE)
27
28endif
29
30# libosd.ko - osd-initiator library
31libosd-y := osd_initiator.o
32obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o
diff --git a/drivers/scsi/osd/Makefile b/drivers/scsi/osd/Makefile
new file mode 100755
index 000000000000..d905344f83ba
--- /dev/null
+++ b/drivers/scsi/osd/Makefile
@@ -0,0 +1,37 @@
1#
2# Makefile for the OSD modules (out of tree)
3#
4# Copyright (C) 2008 Panasas Inc. All rights reserved.
5#
6# Authors:
7# Boaz Harrosh <bharrosh@panasas.com>
8# Benny Halevy <bhalevy@panasas.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2
12#
13# This Makefile is used to call the kernel Makefile in case of an out-of-tree
14# build.
15# $KSRC should point to a Kernel source tree otherwise host's default is
16# used. (eg. /lib/modules/`uname -r`/build)
17
18# include path for out-of-tree Headers
19OSD_INC ?= `pwd`/../../../include
20
21# allow users to override these
22# e.g. to compile for a kernel that you aren't currently running
23KSRC ?= /lib/modules/$(shell uname -r)/build
24KBUILD_OUTPUT ?=
25ARCH ?=
26V ?= 0
27
28# this is the basic Kbuild out-of-tree invocation, with the M= option
29KBUILD_BASE = +$(MAKE) -C $(KSRC) M=`pwd` KBUILD_OUTPUT=$(KBUILD_OUTPUT) ARCH=$(ARCH) V=$(V)
30
31all: libosd
32
33libosd: ;
34 $(KBUILD_BASE) OSD_INC=$(OSD_INC) modules
35
36clean:
37 $(KBUILD_BASE) clean
diff --git a/drivers/scsi/osd/osd_debug.h b/drivers/scsi/osd/osd_debug.h
new file mode 100644
index 000000000000..579e491f11df
--- /dev/null
+++ b/drivers/scsi/osd/osd_debug.h
@@ -0,0 +1,30 @@
1/*
2 * osd_debug.h - Some kprintf macros
3 *
4 * Copyright (C) 2008 Panasas Inc. All rights reserved.
5 *
6 * Authors:
7 * Boaz Harrosh <bharrosh@panasas.com>
8 * Benny Halevy <bhalevy@panasas.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 *
13 */
14#ifndef __OSD_DEBUG_H__
15#define __OSD_DEBUG_H__
16
17#define OSD_ERR(fmt, a...) printk(KERN_ERR "osd: " fmt, ##a)
18#define OSD_INFO(fmt, a...) printk(KERN_NOTICE "osd: " fmt, ##a)
19
20#ifdef CONFIG_SCSI_OSD_DEBUG
21#define OSD_DEBUG(fmt, a...) \
22 printk(KERN_NOTICE "osd @%s:%d: " fmt, __func__, __LINE__, ##a)
23#else
24#define OSD_DEBUG(fmt, a...) do {} while (0)
25#endif
26
27/* u64 has problems with printk this will cast it to unsigned long long */
28#define _LLU(x) (unsigned long long)(x)
29
30#endif /* ndef __OSD_DEBUG_H__ */
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
new file mode 100644
index 000000000000..0e6d906f1113
--- /dev/null
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -0,0 +1,448 @@
1/*
2 * osd_initiator - Main body of the osd initiator library.
3 *
4 * Note: The file does not contain the advanced security functionality which
5 * is only needed by the security_manager's initiators.
6 *
7 * Copyright (C) 2008 Panasas Inc. All rights reserved.
8 *
9 * Authors:
10 * Boaz Harrosh <bharrosh@panasas.com>
11 * Benny Halevy <bhalevy@panasas.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. Neither the name of the Panasas company nor the names of its
26 * contributors may be used to endorse or promote products derived
27 * from this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
30 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
32 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
36 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
42#include <scsi/osd_initiator.h>
43#include <scsi/osd_sec.h>
44#include <scsi/scsi_device.h>
45
46#include "osd_debug.h"
47
48enum { OSD_REQ_RETRIES = 1 };
49
50MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
51MODULE_DESCRIPTION("open-osd initiator library libosd.ko");
52MODULE_LICENSE("GPL");
53
54static inline void build_test(void)
55{
56 /* structures were not packed */
57 BUILD_BUG_ON(sizeof(struct osd_capability) != OSD_CAP_LEN);
58 BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN);
59}
60
61static unsigned _osd_req_cdb_len(struct osd_request *or)
62{
63 return OSDv1_TOTAL_CDB_LEN;
64}
65
66void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)
67{
68 memset(osdd, 0, sizeof(*osdd));
69 osdd->scsi_device = scsi_device;
70 osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT;
71 /* TODO: Allocate pools for osd_request attributes ... */
72}
73EXPORT_SYMBOL(osd_dev_init);
74
75void osd_dev_fini(struct osd_dev *osdd)
76{
77 /* TODO: De-allocate pools */
78
79 osdd->scsi_device = NULL;
80}
81EXPORT_SYMBOL(osd_dev_fini);
82
83static struct osd_request *_osd_request_alloc(gfp_t gfp)
84{
85 struct osd_request *or;
86
87 /* TODO: Use mempool with one saved request */
88 or = kzalloc(sizeof(*or), gfp);
89 return or;
90}
91
92static void _osd_request_free(struct osd_request *or)
93{
94 kfree(or);
95}
96
97struct osd_request *osd_start_request(struct osd_dev *dev, gfp_t gfp)
98{
99 struct osd_request *or;
100
101 or = _osd_request_alloc(gfp);
102 if (!or)
103 return NULL;
104
105 or->osd_dev = dev;
106 or->alloc_flags = gfp;
107 or->timeout = dev->def_timeout;
108 or->retries = OSD_REQ_RETRIES;
109
110 return or;
111}
112EXPORT_SYMBOL(osd_start_request);
113
114/*
115 * If osd_finalize_request() was called but the request was not executed through
116 * the block layer, then we must release BIOs.
117 */
118static void _abort_unexecuted_bios(struct request *rq)
119{
120 struct bio *bio;
121
122 while ((bio = rq->bio) != NULL) {
123 rq->bio = bio->bi_next;
124 bio_endio(bio, 0);
125 }
126}
127
128void osd_end_request(struct osd_request *or)
129{
130 struct request *rq = or->request;
131
132 if (rq) {
133 if (rq->next_rq) {
134 _abort_unexecuted_bios(rq->next_rq);
135 blk_put_request(rq->next_rq);
136 }
137
138 _abort_unexecuted_bios(rq);
139 blk_put_request(rq);
140 }
141 _osd_request_free(or);
142}
143EXPORT_SYMBOL(osd_end_request);
144
145int osd_execute_request(struct osd_request *or)
146{
147 return blk_execute_rq(or->request->q, NULL, or->request, 0);
148}
149EXPORT_SYMBOL(osd_execute_request);
150
151static void osd_request_async_done(struct request *req, int error)
152{
153 struct osd_request *or = req->end_io_data;
154
155 or->async_error = error;
156
157 if (error)
158 OSD_DEBUG("osd_request_async_done error recieved %d\n", error);
159
160 if (or->async_done)
161 or->async_done(or, or->async_private);
162 else
163 osd_end_request(or);
164}
165
166int osd_execute_request_async(struct osd_request *or,
167 osd_req_done_fn *done, void *private)
168{
169 or->request->end_io_data = or;
170 or->async_private = private;
171 or->async_done = done;
172
173 blk_execute_rq_nowait(or->request->q, NULL, or->request, 0,
174 osd_request_async_done);
175 return 0;
176}
177EXPORT_SYMBOL(osd_execute_request_async);
178
179/*
180 * Common to all OSD commands
181 */
182
183static void _osdv1_req_encode_common(struct osd_request *or,
184 __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
185{
186 struct osdv1_cdb *ocdb = &or->cdb.v1;
187
188 /*
189 * For speed, the commands
190 * OSD_ACT_PERFORM_SCSI_COMMAND , V1 0x8F7E, V2 0x8F7C
191 * OSD_ACT_SCSI_TASK_MANAGEMENT , V1 0x8F7F, V2 0x8F7D
192 * are not supported here. Should pass zero and set after the call
193 */
194 act &= cpu_to_be16(~0x0080); /* V1 action code */
195
196 OSD_DEBUG("OSDv1 execute opcode 0x%x\n", be16_to_cpu(act));
197
198 ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD;
199 ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH;
200 ocdb->h.varlen_cdb.service_action = act;
201
202 ocdb->h.partition = cpu_to_be64(obj->partition);
203 ocdb->h.object = cpu_to_be64(obj->id);
204 ocdb->h.v1.length = cpu_to_be64(len);
205 ocdb->h.v1.start_address = cpu_to_be64(offset);
206}
207
208static void _osd_req_encode_common(struct osd_request *or,
209 __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
210{
211 _osdv1_req_encode_common(or, act, obj, offset, len);
212}
213
214/*
215 * Device commands
216 */
217void osd_req_format(struct osd_request *or, u64 tot_capacity)
218{
219 _osd_req_encode_common(or, OSD_ACT_FORMAT_OSD, &osd_root_object, 0,
220 tot_capacity);
221}
222EXPORT_SYMBOL(osd_req_format);
223
224/*
225 * Partition commands
226 */
227static void _osd_req_encode_partition(struct osd_request *or,
228 __be16 act, osd_id partition)
229{
230 struct osd_obj_id par = {
231 .partition = partition,
232 .id = 0,
233 };
234
235 _osd_req_encode_common(or, act, &par, 0, 0);
236}
237
238void osd_req_create_partition(struct osd_request *or, osd_id partition)
239{
240 _osd_req_encode_partition(or, OSD_ACT_CREATE_PARTITION, partition);
241}
242EXPORT_SYMBOL(osd_req_create_partition);
243
244void osd_req_remove_partition(struct osd_request *or, osd_id partition)
245{
246 _osd_req_encode_partition(or, OSD_ACT_REMOVE_PARTITION, partition);
247}
248EXPORT_SYMBOL(osd_req_remove_partition);
249
250/*
251 * Object commands
252 */
253void osd_req_create_object(struct osd_request *or, struct osd_obj_id *obj)
254{
255 _osd_req_encode_common(or, OSD_ACT_CREATE, obj, 0, 0);
256}
257EXPORT_SYMBOL(osd_req_create_object);
258
259void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *obj)
260{
261 _osd_req_encode_common(or, OSD_ACT_REMOVE, obj, 0, 0);
262}
263EXPORT_SYMBOL(osd_req_remove_object);
264
265void osd_req_write(struct osd_request *or,
266 const struct osd_obj_id *obj, struct bio *bio, u64 offset)
267{
268 _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, bio->bi_size);
269 WARN_ON(or->out.bio || or->out.total_bytes);
270 bio->bi_rw |= (1 << BIO_RW);
271 or->out.bio = bio;
272 or->out.total_bytes = bio->bi_size;
273}
274EXPORT_SYMBOL(osd_req_write);
275
276void osd_req_read(struct osd_request *or,
277 const struct osd_obj_id *obj, struct bio *bio, u64 offset)
278{
279 _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, bio->bi_size);
280 WARN_ON(or->in.bio || or->in.total_bytes);
281 bio->bi_rw &= ~(1 << BIO_RW);
282 or->in.bio = bio;
283 or->in.total_bytes = bio->bi_size;
284}
285EXPORT_SYMBOL(osd_req_read);
286
287/*
288 * osd_finalize_request and helpers
289 */
290
291static int _init_blk_request(struct osd_request *or,
292 bool has_in, bool has_out)
293{
294 gfp_t flags = or->alloc_flags;
295 struct scsi_device *scsi_device = or->osd_dev->scsi_device;
296 struct request_queue *q = scsi_device->request_queue;
297 struct request *req;
298 int ret = -ENOMEM;
299
300 req = blk_get_request(q, has_out, flags);
301 if (!req)
302 goto out;
303
304 or->request = req;
305 req->cmd_type = REQ_TYPE_BLOCK_PC;
306 req->timeout = or->timeout;
307 req->retries = or->retries;
308 req->sense = or->sense;
309 req->sense_len = 0;
310
311 if (has_out) {
312 or->out.req = req;
313 if (has_in) {
314 /* allocate bidi request */
315 req = blk_get_request(q, READ, flags);
316 if (!req) {
317 OSD_DEBUG("blk_get_request for bidi failed\n");
318 goto out;
319 }
320 req->cmd_type = REQ_TYPE_BLOCK_PC;
321 or->in.req = or->request->next_rq = req;
322 }
323 } else if (has_in)
324 or->in.req = req;
325
326 ret = 0;
327out:
328 OSD_DEBUG("or=%p has_in=%d has_out=%d => %d, %p\n",
329 or, has_in, has_out, ret, or->request);
330 return ret;
331}
332
333int osd_finalize_request(struct osd_request *or,
334 u8 options, const void *cap, const u8 *cap_key)
335{
336 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
337 bool has_in, has_out;
338 int ret;
339
340 if (options & OSD_REQ_FUA)
341 cdbh->options |= OSD_CDB_FUA;
342
343 if (options & OSD_REQ_DPO)
344 cdbh->options |= OSD_CDB_DPO;
345
346 if (options & OSD_REQ_BYPASS_TIMESTAMPS)
347 cdbh->timestamp_control = OSD_CDB_BYPASS_TIMESTAMPS;
348
349 osd_set_caps(&or->cdb, cap);
350
351 has_in = or->in.bio || or->get_attr.total_bytes;
352 has_out = or->out.bio || or->set_attr.total_bytes ||
353 or->enc_get_attr.total_bytes;
354
355 ret = _init_blk_request(or, has_in, has_out);
356 if (ret) {
357 OSD_DEBUG("_init_blk_request failed\n");
358 return ret;
359 }
360
361 if (or->out.bio) {
362 ret = blk_rq_append_bio(or->request->q, or->out.req,
363 or->out.bio);
364 if (ret) {
365 OSD_DEBUG("blk_rq_append_bio out failed\n");
366 return ret;
367 }
368 OSD_DEBUG("out bytes=%llu (bytes_req=%u)\n",
369 _LLU(or->out.total_bytes), or->out.req->data_len);
370 }
371 if (or->in.bio) {
372 ret = blk_rq_append_bio(or->request->q, or->in.req, or->in.bio);
373 if (ret) {
374 OSD_DEBUG("blk_rq_append_bio in failed\n");
375 return ret;
376 }
377 OSD_DEBUG("in bytes=%llu (bytes_req=%u)\n",
378 _LLU(or->in.total_bytes), or->in.req->data_len);
379 }
380
381 if (!or->attributes_mode)
382 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
383 cdbh->command_specific_options |= or->attributes_mode;
384
385 or->request->cmd = or->cdb.buff;
386 or->request->cmd_len = _osd_req_cdb_len(or);
387
388 return 0;
389}
390EXPORT_SYMBOL(osd_finalize_request);
391
392/*
393 * Implementation of osd_sec.h API
394 * TODO: Move to a separate osd_sec.c file at a later stage.
395 */
396
397enum { OSD_SEC_CAP_V1_ALL_CAPS =
398 OSD_SEC_CAP_APPEND | OSD_SEC_CAP_OBJ_MGMT | OSD_SEC_CAP_REMOVE |
399 OSD_SEC_CAP_CREATE | OSD_SEC_CAP_SET_ATTR | OSD_SEC_CAP_GET_ATTR |
400 OSD_SEC_CAP_WRITE | OSD_SEC_CAP_READ | OSD_SEC_CAP_POL_SEC |
401 OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT
402};
403
404void osd_sec_init_nosec_doall_caps(void *caps,
405 const struct osd_obj_id *obj, bool is_collection, const bool is_v1)
406{
407 struct osd_capability *cap = caps;
408 u8 type;
409 u8 descriptor_type;
410
411 if (likely(obj->id)) {
412 if (unlikely(is_collection)) {
413 type = OSD_SEC_OBJ_COLLECTION;
414 descriptor_type = is_v1 ? OSD_SEC_OBJ_DESC_OBJ :
415 OSD_SEC_OBJ_DESC_COL;
416 } else {
417 type = OSD_SEC_OBJ_USER;
418 descriptor_type = OSD_SEC_OBJ_DESC_OBJ;
419 }
420 WARN_ON(!obj->partition);
421 } else {
422 type = obj->partition ? OSD_SEC_OBJ_PARTITION :
423 OSD_SEC_OBJ_ROOT;
424 descriptor_type = OSD_SEC_OBJ_DESC_PAR;
425 }
426
427 memset(cap, 0, sizeof(*cap));
428
429 cap->h.format = OSD_SEC_CAP_FORMAT_VER1;
430 cap->h.integrity_algorithm__key_version = 0; /* MAKE_BYTE(0, 0); */
431 cap->h.security_method = OSD_SEC_NOSEC;
432/* cap->expiration_time;
433 cap->AUDIT[30-10];
434 cap->discriminator[42-30];
435 cap->object_created_time; */
436 cap->h.object_type = type;
437 osd_sec_set_caps(&cap->h, OSD_SEC_CAP_V1_ALL_CAPS);
438 cap->h.object_descriptor_type = descriptor_type;
439 cap->od.obj_desc.policy_access_tag = 0;
440 cap->od.obj_desc.allowed_partition_id = cpu_to_be64(obj->partition);
441 cap->od.obj_desc.allowed_object_id = cpu_to_be64(obj->id);
442}
443EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps);
444
445void osd_set_caps(struct osd_cdb *cdb, const void *caps)
446{
447 memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN);
448}