blob: b982d767bf99280ab977447596129c9b9c82e727 [file] [log] [blame]
Boaz Harrosh02941a52009-01-25 16:55:30 +02001/*
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
Boaz Harrosh4ef1a3d2009-01-25 16:59:50 +020048#ifndef __unused
49# define __unused __attribute__((unused))
50#endif
51
Boaz Harrosh02941a52009-01-25 16:55:30 +020052enum { OSD_REQ_RETRIES = 1 };
53
54MODULE_AUTHOR("Boaz Harrosh <bharrosh@panasas.com>");
55MODULE_DESCRIPTION("open-osd initiator library libosd.ko");
56MODULE_LICENSE("GPL");
57
58static inline void build_test(void)
59{
60 /* structures were not packed */
61 BUILD_BUG_ON(sizeof(struct osd_capability) != OSD_CAP_LEN);
62 BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN);
63}
64
65static unsigned _osd_req_cdb_len(struct osd_request *or)
66{
67 return OSDv1_TOTAL_CDB_LEN;
68}
69
Boaz Harrosh4ef1a3d2009-01-25 16:59:50 +020070static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len)
71{
72 return osdv1_attr_list_elem_size(len);
73}
74
75static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head)
76{
77 return osdv1_list_size(list_head);
78}
79
80static unsigned _osd_req_sizeof_alist_header(struct osd_request *or)
81{
82 return sizeof(struct osdv1_attributes_list_header);
83}
84
85static void _osd_req_set_alist_type(struct osd_request *or,
86 void *list, int list_type)
87{
88 struct osdv1_attributes_list_header *attr_list = list;
89
90 memset(attr_list, 0, sizeof(*attr_list));
91 attr_list->type = list_type;
92}
93
94static bool _osd_req_is_alist_type(struct osd_request *or,
95 void *list, int list_type)
96{
97 if (!list)
98 return false;
99
100 if (1) {
101 struct osdv1_attributes_list_header *attr_list = list;
102
103 return attr_list->type == list_type;
104 }
105}
106
107static osd_cdb_offset osd_req_encode_offset(struct osd_request *or,
108 u64 offset, unsigned *padding)
109{
110 return __osd_encode_offset(offset, padding,
111 OSDv1_OFFSET_MIN_SHIFT, OSD_OFFSET_MAX_SHIFT);
112}
113
Boaz Harrosh02941a52009-01-25 16:55:30 +0200114void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device)
115{
116 memset(osdd, 0, sizeof(*osdd));
117 osdd->scsi_device = scsi_device;
118 osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT;
119 /* TODO: Allocate pools for osd_request attributes ... */
120}
121EXPORT_SYMBOL(osd_dev_init);
122
123void osd_dev_fini(struct osd_dev *osdd)
124{
125 /* TODO: De-allocate pools */
126
127 osdd->scsi_device = NULL;
128}
129EXPORT_SYMBOL(osd_dev_fini);
130
131static struct osd_request *_osd_request_alloc(gfp_t gfp)
132{
133 struct osd_request *or;
134
135 /* TODO: Use mempool with one saved request */
136 or = kzalloc(sizeof(*or), gfp);
137 return or;
138}
139
140static void _osd_request_free(struct osd_request *or)
141{
142 kfree(or);
143}
144
145struct osd_request *osd_start_request(struct osd_dev *dev, gfp_t gfp)
146{
147 struct osd_request *or;
148
149 or = _osd_request_alloc(gfp);
150 if (!or)
151 return NULL;
152
153 or->osd_dev = dev;
154 or->alloc_flags = gfp;
155 or->timeout = dev->def_timeout;
156 or->retries = OSD_REQ_RETRIES;
157
158 return or;
159}
160EXPORT_SYMBOL(osd_start_request);
161
162/*
163 * If osd_finalize_request() was called but the request was not executed through
164 * the block layer, then we must release BIOs.
165 */
166static void _abort_unexecuted_bios(struct request *rq)
167{
168 struct bio *bio;
169
170 while ((bio = rq->bio) != NULL) {
171 rq->bio = bio->bi_next;
172 bio_endio(bio, 0);
173 }
174}
175
Boaz Harrosh4ef1a3d2009-01-25 16:59:50 +0200176static void _osd_free_seg(struct osd_request *or __unused,
177 struct _osd_req_data_segment *seg)
178{
179 if (!seg->buff || !seg->alloc_size)
180 return;
181
182 kfree(seg->buff);
183 seg->buff = NULL;
184 seg->alloc_size = 0;
185}
186
Boaz Harrosh02941a52009-01-25 16:55:30 +0200187void osd_end_request(struct osd_request *or)
188{
189 struct request *rq = or->request;
190
Boaz Harrosh4ef1a3d2009-01-25 16:59:50 +0200191 _osd_free_seg(or, &or->set_attr);
192 _osd_free_seg(or, &or->enc_get_attr);
193 _osd_free_seg(or, &or->get_attr);
194
Boaz Harrosh02941a52009-01-25 16:55:30 +0200195 if (rq) {
196 if (rq->next_rq) {
197 _abort_unexecuted_bios(rq->next_rq);
198 blk_put_request(rq->next_rq);
199 }
200
201 _abort_unexecuted_bios(rq);
202 blk_put_request(rq);
203 }
204 _osd_request_free(or);
205}
206EXPORT_SYMBOL(osd_end_request);
207
208int osd_execute_request(struct osd_request *or)
209{
210 return blk_execute_rq(or->request->q, NULL, or->request, 0);
211}
212EXPORT_SYMBOL(osd_execute_request);
213
214static void osd_request_async_done(struct request *req, int error)
215{
216 struct osd_request *or = req->end_io_data;
217
218 or->async_error = error;
219
220 if (error)
221 OSD_DEBUG("osd_request_async_done error recieved %d\n", error);
222
223 if (or->async_done)
224 or->async_done(or, or->async_private);
225 else
226 osd_end_request(or);
227}
228
229int osd_execute_request_async(struct osd_request *or,
230 osd_req_done_fn *done, void *private)
231{
232 or->request->end_io_data = or;
233 or->async_private = private;
234 or->async_done = done;
235
236 blk_execute_rq_nowait(or->request->q, NULL, or->request, 0,
237 osd_request_async_done);
238 return 0;
239}
240EXPORT_SYMBOL(osd_execute_request_async);
241
Boaz Harrosh4ef1a3d2009-01-25 16:59:50 +0200242u8 sg_out_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
243u8 sg_in_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT];
244
245static int _osd_realloc_seg(struct osd_request *or,
246 struct _osd_req_data_segment *seg, unsigned max_bytes)
247{
248 void *buff;
249
250 if (seg->alloc_size >= max_bytes)
251 return 0;
252
253 buff = krealloc(seg->buff, max_bytes, or->alloc_flags);
254 if (!buff) {
255 OSD_ERR("Failed to Realloc %d-bytes was-%d\n", max_bytes,
256 seg->alloc_size);
257 return -ENOMEM;
258 }
259
260 memset(buff + seg->alloc_size, 0, max_bytes - seg->alloc_size);
261 seg->buff = buff;
262 seg->alloc_size = max_bytes;
263 return 0;
264}
265
266static int _alloc_set_attr_list(struct osd_request *or,
267 const struct osd_attr *oa, unsigned nelem, unsigned add_bytes)
268{
269 unsigned total_bytes = add_bytes;
270
271 for (; nelem; --nelem, ++oa)
272 total_bytes += _osd_req_alist_elem_size(or, oa->len);
273
274 OSD_DEBUG("total_bytes=%d\n", total_bytes);
275 return _osd_realloc_seg(or, &or->set_attr, total_bytes);
276}
277
278static int _alloc_get_attr_desc(struct osd_request *or, unsigned max_bytes)
279{
280 OSD_DEBUG("total_bytes=%d\n", max_bytes);
281 return _osd_realloc_seg(or, &or->enc_get_attr, max_bytes);
282}
283
284static int _alloc_get_attr_list(struct osd_request *or)
285{
286 OSD_DEBUG("total_bytes=%d\n", or->get_attr.total_bytes);
287 return _osd_realloc_seg(or, &or->get_attr, or->get_attr.total_bytes);
288}
289
Boaz Harrosh02941a52009-01-25 16:55:30 +0200290/*
291 * Common to all OSD commands
292 */
293
294static void _osdv1_req_encode_common(struct osd_request *or,
295 __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
296{
297 struct osdv1_cdb *ocdb = &or->cdb.v1;
298
299 /*
300 * For speed, the commands
301 * OSD_ACT_PERFORM_SCSI_COMMAND , V1 0x8F7E, V2 0x8F7C
302 * OSD_ACT_SCSI_TASK_MANAGEMENT , V1 0x8F7F, V2 0x8F7D
303 * are not supported here. Should pass zero and set after the call
304 */
305 act &= cpu_to_be16(~0x0080); /* V1 action code */
306
307 OSD_DEBUG("OSDv1 execute opcode 0x%x\n", be16_to_cpu(act));
308
309 ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD;
310 ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH;
311 ocdb->h.varlen_cdb.service_action = act;
312
313 ocdb->h.partition = cpu_to_be64(obj->partition);
314 ocdb->h.object = cpu_to_be64(obj->id);
315 ocdb->h.v1.length = cpu_to_be64(len);
316 ocdb->h.v1.start_address = cpu_to_be64(offset);
317}
318
319static void _osd_req_encode_common(struct osd_request *or,
320 __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len)
321{
322 _osdv1_req_encode_common(or, act, obj, offset, len);
323}
324
325/*
326 * Device commands
327 */
328void osd_req_format(struct osd_request *or, u64 tot_capacity)
329{
330 _osd_req_encode_common(or, OSD_ACT_FORMAT_OSD, &osd_root_object, 0,
331 tot_capacity);
332}
333EXPORT_SYMBOL(osd_req_format);
334
335/*
336 * Partition commands
337 */
338static void _osd_req_encode_partition(struct osd_request *or,
339 __be16 act, osd_id partition)
340{
341 struct osd_obj_id par = {
342 .partition = partition,
343 .id = 0,
344 };
345
346 _osd_req_encode_common(or, act, &par, 0, 0);
347}
348
349void osd_req_create_partition(struct osd_request *or, osd_id partition)
350{
351 _osd_req_encode_partition(or, OSD_ACT_CREATE_PARTITION, partition);
352}
353EXPORT_SYMBOL(osd_req_create_partition);
354
355void osd_req_remove_partition(struct osd_request *or, osd_id partition)
356{
357 _osd_req_encode_partition(or, OSD_ACT_REMOVE_PARTITION, partition);
358}
359EXPORT_SYMBOL(osd_req_remove_partition);
360
361/*
362 * Object commands
363 */
364void osd_req_create_object(struct osd_request *or, struct osd_obj_id *obj)
365{
366 _osd_req_encode_common(or, OSD_ACT_CREATE, obj, 0, 0);
367}
368EXPORT_SYMBOL(osd_req_create_object);
369
370void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *obj)
371{
372 _osd_req_encode_common(or, OSD_ACT_REMOVE, obj, 0, 0);
373}
374EXPORT_SYMBOL(osd_req_remove_object);
375
376void osd_req_write(struct osd_request *or,
377 const struct osd_obj_id *obj, struct bio *bio, u64 offset)
378{
379 _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, bio->bi_size);
380 WARN_ON(or->out.bio || or->out.total_bytes);
381 bio->bi_rw |= (1 << BIO_RW);
382 or->out.bio = bio;
383 or->out.total_bytes = bio->bi_size;
384}
385EXPORT_SYMBOL(osd_req_write);
386
387void osd_req_read(struct osd_request *or,
388 const struct osd_obj_id *obj, struct bio *bio, u64 offset)
389{
390 _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, bio->bi_size);
391 WARN_ON(or->in.bio || or->in.total_bytes);
392 bio->bi_rw &= ~(1 << BIO_RW);
393 or->in.bio = bio;
394 or->in.total_bytes = bio->bi_size;
395}
396EXPORT_SYMBOL(osd_req_read);
397
Boaz Harrosh4ef1a3d2009-01-25 16:59:50 +0200398void osd_req_get_attributes(struct osd_request *or,
399 const struct osd_obj_id *obj)
400{
401 _osd_req_encode_common(or, OSD_ACT_GET_ATTRIBUTES, obj, 0, 0);
402}
403EXPORT_SYMBOL(osd_req_get_attributes);
404
405void osd_req_set_attributes(struct osd_request *or,
406 const struct osd_obj_id *obj)
407{
408 _osd_req_encode_common(or, OSD_ACT_SET_ATTRIBUTES, obj, 0, 0);
409}
410EXPORT_SYMBOL(osd_req_set_attributes);
411
412/*
413 * Attributes List-mode
414 */
415
416int osd_req_add_set_attr_list(struct osd_request *or,
417 const struct osd_attr *oa, unsigned nelem)
418{
419 unsigned total_bytes = or->set_attr.total_bytes;
420 void *attr_last;
421 int ret;
422
423 if (or->attributes_mode &&
424 or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
425 WARN_ON(1);
426 return -EINVAL;
427 }
428 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
429
430 if (!total_bytes) { /* first-time: allocate and put list header */
431 total_bytes = _osd_req_sizeof_alist_header(or);
432 ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
433 if (ret)
434 return ret;
435 _osd_req_set_alist_type(or, or->set_attr.buff,
436 OSD_ATTR_LIST_SET_RETRIEVE);
437 }
438 attr_last = or->set_attr.buff + total_bytes;
439
440 for (; nelem; --nelem) {
441 struct osd_attributes_list_element *attr;
442 unsigned elem_size = _osd_req_alist_elem_size(or, oa->len);
443
444 total_bytes += elem_size;
445 if (unlikely(or->set_attr.alloc_size < total_bytes)) {
446 or->set_attr.total_bytes = total_bytes - elem_size;
447 ret = _alloc_set_attr_list(or, oa, nelem, total_bytes);
448 if (ret)
449 return ret;
450 attr_last =
451 or->set_attr.buff + or->set_attr.total_bytes;
452 }
453
454 attr = attr_last;
455 attr->attr_page = cpu_to_be32(oa->attr_page);
456 attr->attr_id = cpu_to_be32(oa->attr_id);
457 attr->attr_bytes = cpu_to_be16(oa->len);
458 memcpy(attr->attr_val, oa->val_ptr, oa->len);
459
460 attr_last += elem_size;
461 ++oa;
462 }
463
464 or->set_attr.total_bytes = total_bytes;
465 return 0;
466}
467EXPORT_SYMBOL(osd_req_add_set_attr_list);
468
469static int _append_map_kern(struct request *req,
470 void *buff, unsigned len, gfp_t flags)
471{
472 struct bio *bio;
473 int ret;
474
475 bio = bio_map_kern(req->q, buff, len, flags);
476 if (IS_ERR(bio)) {
477 OSD_ERR("Failed bio_map_kern(%p, %d) => %ld\n", buff, len,
478 PTR_ERR(bio));
479 return PTR_ERR(bio);
480 }
481 ret = blk_rq_append_bio(req->q, req, bio);
482 if (ret) {
483 OSD_ERR("Failed blk_rq_append_bio(%p) => %d\n", bio, ret);
484 bio_put(bio);
485 }
486 return ret;
487}
488
489static int _req_append_segment(struct osd_request *or,
490 unsigned padding, struct _osd_req_data_segment *seg,
491 struct _osd_req_data_segment *last_seg, struct _osd_io_info *io)
492{
493 void *pad_buff;
494 int ret;
495
496 if (padding) {
497 /* check if we can just add it to last buffer */
498 if (last_seg &&
499 (padding <= last_seg->alloc_size - last_seg->total_bytes))
500 pad_buff = last_seg->buff + last_seg->total_bytes;
501 else
502 pad_buff = io->pad_buff;
503
504 ret = _append_map_kern(io->req, pad_buff, padding,
505 or->alloc_flags);
506 if (ret)
507 return ret;
508 io->total_bytes += padding;
509 }
510
511 ret = _append_map_kern(io->req, seg->buff, seg->total_bytes,
512 or->alloc_flags);
513 if (ret)
514 return ret;
515
516 io->total_bytes += seg->total_bytes;
517 OSD_DEBUG("padding=%d buff=%p total_bytes=%d\n", padding, seg->buff,
518 seg->total_bytes);
519 return 0;
520}
521
522static int _osd_req_finalize_set_attr_list(struct osd_request *or)
523{
524 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
525 unsigned padding;
526 int ret;
527
528 if (!or->set_attr.total_bytes) {
529 cdbh->attrs_list.set_attr_offset = OSD_OFFSET_UNUSED;
530 return 0;
531 }
532
533 cdbh->attrs_list.set_attr_bytes = cpu_to_be32(or->set_attr.total_bytes);
534 cdbh->attrs_list.set_attr_offset =
535 osd_req_encode_offset(or, or->out.total_bytes, &padding);
536
537 ret = _req_append_segment(or, padding, &or->set_attr,
538 or->out.last_seg, &or->out);
539 if (ret)
540 return ret;
541
542 or->out.last_seg = &or->set_attr;
543 return 0;
544}
545
546int osd_req_add_get_attr_list(struct osd_request *or,
547 const struct osd_attr *oa, unsigned nelem)
548{
549 unsigned total_bytes = or->enc_get_attr.total_bytes;
550 void *attr_last;
551 int ret;
552
553 if (or->attributes_mode &&
554 or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) {
555 WARN_ON(1);
556 return -EINVAL;
557 }
558 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
559
560 /* first time calc data-in list header size */
561 if (!or->get_attr.total_bytes)
562 or->get_attr.total_bytes = _osd_req_sizeof_alist_header(or);
563
564 /* calc data-out info */
565 if (!total_bytes) { /* first-time: allocate and put list header */
566 unsigned max_bytes;
567
568 total_bytes = _osd_req_sizeof_alist_header(or);
569 max_bytes = total_bytes +
570 nelem * sizeof(struct osd_attributes_list_attrid);
571 ret = _alloc_get_attr_desc(or, max_bytes);
572 if (ret)
573 return ret;
574
575 _osd_req_set_alist_type(or, or->enc_get_attr.buff,
576 OSD_ATTR_LIST_GET);
577 }
578 attr_last = or->enc_get_attr.buff + total_bytes;
579
580 for (; nelem; --nelem) {
581 struct osd_attributes_list_attrid *attrid;
582 const unsigned cur_size = sizeof(*attrid);
583
584 total_bytes += cur_size;
585 if (unlikely(or->enc_get_attr.alloc_size < total_bytes)) {
586 or->enc_get_attr.total_bytes = total_bytes - cur_size;
587 ret = _alloc_get_attr_desc(or,
588 total_bytes + nelem * sizeof(*attrid));
589 if (ret)
590 return ret;
591 attr_last = or->enc_get_attr.buff +
592 or->enc_get_attr.total_bytes;
593 }
594
595 attrid = attr_last;
596 attrid->attr_page = cpu_to_be32(oa->attr_page);
597 attrid->attr_id = cpu_to_be32(oa->attr_id);
598
599 attr_last += cur_size;
600
601 /* calc data-in size */
602 or->get_attr.total_bytes +=
603 _osd_req_alist_elem_size(or, oa->len);
604 ++oa;
605 }
606
607 or->enc_get_attr.total_bytes = total_bytes;
608
609 OSD_DEBUG(
610 "get_attr.total_bytes=%u(%u) enc_get_attr.total_bytes=%u(%Zu)\n",
611 or->get_attr.total_bytes,
612 or->get_attr.total_bytes - _osd_req_sizeof_alist_header(or),
613 or->enc_get_attr.total_bytes,
614 (or->enc_get_attr.total_bytes - _osd_req_sizeof_alist_header(or))
615 / sizeof(struct osd_attributes_list_attrid));
616
617 return 0;
618}
619EXPORT_SYMBOL(osd_req_add_get_attr_list);
620
621static int _osd_req_finalize_get_attr_list(struct osd_request *or)
622{
623 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
624 unsigned out_padding;
625 unsigned in_padding;
626 int ret;
627
628 if (!or->enc_get_attr.total_bytes) {
629 cdbh->attrs_list.get_attr_desc_offset = OSD_OFFSET_UNUSED;
630 cdbh->attrs_list.get_attr_offset = OSD_OFFSET_UNUSED;
631 return 0;
632 }
633
634 ret = _alloc_get_attr_list(or);
635 if (ret)
636 return ret;
637
638 /* The out-going buffer info update */
639 OSD_DEBUG("out-going\n");
640 cdbh->attrs_list.get_attr_desc_bytes =
641 cpu_to_be32(or->enc_get_attr.total_bytes);
642
643 cdbh->attrs_list.get_attr_desc_offset =
644 osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
645
646 ret = _req_append_segment(or, out_padding, &or->enc_get_attr,
647 or->out.last_seg, &or->out);
648 if (ret)
649 return ret;
650 or->out.last_seg = &or->enc_get_attr;
651
652 /* The incoming buffer info update */
653 OSD_DEBUG("in-coming\n");
654 cdbh->attrs_list.get_attr_alloc_length =
655 cpu_to_be32(or->get_attr.total_bytes);
656
657 cdbh->attrs_list.get_attr_offset =
658 osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
659
660 ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
661 &or->in);
662 if (ret)
663 return ret;
664 or->in.last_seg = &or->get_attr;
665
666 return 0;
667}
668
669int osd_req_decode_get_attr_list(struct osd_request *or,
670 struct osd_attr *oa, int *nelem, void **iterator)
671{
672 unsigned cur_bytes, returned_bytes;
673 int n;
674 const unsigned sizeof_attr_list = _osd_req_sizeof_alist_header(or);
675 void *cur_p;
676
677 if (!_osd_req_is_alist_type(or, or->get_attr.buff,
678 OSD_ATTR_LIST_SET_RETRIEVE)) {
679 oa->attr_page = 0;
680 oa->attr_id = 0;
681 oa->val_ptr = NULL;
682 oa->len = 0;
683 *iterator = NULL;
684 return 0;
685 }
686
687 if (*iterator) {
688 BUG_ON((*iterator < or->get_attr.buff) ||
689 (or->get_attr.buff + or->get_attr.alloc_size < *iterator));
690 cur_p = *iterator;
691 cur_bytes = (*iterator - or->get_attr.buff) - sizeof_attr_list;
692 returned_bytes = or->get_attr.total_bytes;
693 } else { /* first time decode the list header */
694 cur_bytes = sizeof_attr_list;
695 returned_bytes = _osd_req_alist_size(or, or->get_attr.buff) +
696 sizeof_attr_list;
697
698 cur_p = or->get_attr.buff + sizeof_attr_list;
699
700 if (returned_bytes > or->get_attr.alloc_size) {
701 OSD_DEBUG("target report: space was not big enough! "
702 "Allocate=%u Needed=%u\n",
703 or->get_attr.alloc_size,
704 returned_bytes + sizeof_attr_list);
705
706 returned_bytes =
707 or->get_attr.alloc_size - sizeof_attr_list;
708 }
709 or->get_attr.total_bytes = returned_bytes;
710 }
711
712 for (n = 0; (n < *nelem) && (cur_bytes < returned_bytes); ++n) {
713 struct osd_attributes_list_element *attr = cur_p;
714 unsigned inc;
715
716 oa->len = be16_to_cpu(attr->attr_bytes);
717 inc = _osd_req_alist_elem_size(or, oa->len);
718 OSD_DEBUG("oa->len=%d inc=%d cur_bytes=%d\n",
719 oa->len, inc, cur_bytes);
720 cur_bytes += inc;
721 if (cur_bytes > returned_bytes) {
722 OSD_ERR("BAD FOOD from target. list not valid!"
723 "c=%d r=%d n=%d\n",
724 cur_bytes, returned_bytes, n);
725 oa->val_ptr = NULL;
726 break;
727 }
728
729 oa->attr_page = be32_to_cpu(attr->attr_page);
730 oa->attr_id = be32_to_cpu(attr->attr_id);
731 oa->val_ptr = attr->attr_val;
732
733 cur_p += inc;
734 ++oa;
735 }
736
737 *iterator = (returned_bytes - cur_bytes) ? cur_p : NULL;
738 *nelem = n;
739 return returned_bytes - cur_bytes;
740}
741EXPORT_SYMBOL(osd_req_decode_get_attr_list);
742
743/*
744 * Attributes Page-mode
745 */
746
747int osd_req_add_get_attr_page(struct osd_request *or,
748 u32 page_id, void *attar_page, unsigned max_page_len,
749 const struct osd_attr *set_one_attr)
750{
751 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
752
753 if (or->attributes_mode &&
754 or->attributes_mode != OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
755 WARN_ON(1);
756 return -EINVAL;
757 }
758 or->attributes_mode = OSD_CDB_GET_ATTR_PAGE_SET_ONE;
759
760 or->get_attr.buff = attar_page;
761 or->get_attr.total_bytes = max_page_len;
762
763 or->set_attr.buff = set_one_attr->val_ptr;
764 or->set_attr.total_bytes = set_one_attr->len;
765
766 cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id);
767 cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len);
768 /* ocdb->attrs_page.get_attr_offset; */
769
770 cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page);
771 cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id);
772 cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len);
773 /* ocdb->attrs_page.set_attr_offset; */
774 return 0;
775}
776EXPORT_SYMBOL(osd_req_add_get_attr_page);
777
778static int _osd_req_finalize_attr_page(struct osd_request *or)
779{
780 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
781 unsigned in_padding, out_padding;
782 int ret;
783
784 /* returned page */
785 cdbh->attrs_page.get_attr_offset =
786 osd_req_encode_offset(or, or->in.total_bytes, &in_padding);
787
788 ret = _req_append_segment(or, in_padding, &or->get_attr, NULL,
789 &or->in);
790 if (ret)
791 return ret;
792
793 /* set one value */
794 cdbh->attrs_page.set_attr_offset =
795 osd_req_encode_offset(or, or->out.total_bytes, &out_padding);
796
797 ret = _req_append_segment(or, out_padding, &or->enc_get_attr, NULL,
798 &or->out);
799 return ret;
800}
801
Boaz Harrosh02941a52009-01-25 16:55:30 +0200802/*
803 * osd_finalize_request and helpers
804 */
805
806static int _init_blk_request(struct osd_request *or,
807 bool has_in, bool has_out)
808{
809 gfp_t flags = or->alloc_flags;
810 struct scsi_device *scsi_device = or->osd_dev->scsi_device;
811 struct request_queue *q = scsi_device->request_queue;
812 struct request *req;
813 int ret = -ENOMEM;
814
815 req = blk_get_request(q, has_out, flags);
816 if (!req)
817 goto out;
818
819 or->request = req;
820 req->cmd_type = REQ_TYPE_BLOCK_PC;
821 req->timeout = or->timeout;
822 req->retries = or->retries;
823 req->sense = or->sense;
824 req->sense_len = 0;
825
826 if (has_out) {
827 or->out.req = req;
828 if (has_in) {
829 /* allocate bidi request */
830 req = blk_get_request(q, READ, flags);
831 if (!req) {
832 OSD_DEBUG("blk_get_request for bidi failed\n");
833 goto out;
834 }
835 req->cmd_type = REQ_TYPE_BLOCK_PC;
836 or->in.req = or->request->next_rq = req;
837 }
838 } else if (has_in)
839 or->in.req = req;
840
841 ret = 0;
842out:
843 OSD_DEBUG("or=%p has_in=%d has_out=%d => %d, %p\n",
844 or, has_in, has_out, ret, or->request);
845 return ret;
846}
847
848int osd_finalize_request(struct osd_request *or,
849 u8 options, const void *cap, const u8 *cap_key)
850{
851 struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb);
852 bool has_in, has_out;
853 int ret;
854
855 if (options & OSD_REQ_FUA)
856 cdbh->options |= OSD_CDB_FUA;
857
858 if (options & OSD_REQ_DPO)
859 cdbh->options |= OSD_CDB_DPO;
860
861 if (options & OSD_REQ_BYPASS_TIMESTAMPS)
862 cdbh->timestamp_control = OSD_CDB_BYPASS_TIMESTAMPS;
863
864 osd_set_caps(&or->cdb, cap);
865
866 has_in = or->in.bio || or->get_attr.total_bytes;
867 has_out = or->out.bio || or->set_attr.total_bytes ||
868 or->enc_get_attr.total_bytes;
869
870 ret = _init_blk_request(or, has_in, has_out);
871 if (ret) {
872 OSD_DEBUG("_init_blk_request failed\n");
873 return ret;
874 }
875
876 if (or->out.bio) {
877 ret = blk_rq_append_bio(or->request->q, or->out.req,
878 or->out.bio);
879 if (ret) {
880 OSD_DEBUG("blk_rq_append_bio out failed\n");
881 return ret;
882 }
883 OSD_DEBUG("out bytes=%llu (bytes_req=%u)\n",
884 _LLU(or->out.total_bytes), or->out.req->data_len);
885 }
886 if (or->in.bio) {
887 ret = blk_rq_append_bio(or->request->q, or->in.req, or->in.bio);
888 if (ret) {
889 OSD_DEBUG("blk_rq_append_bio in failed\n");
890 return ret;
891 }
892 OSD_DEBUG("in bytes=%llu (bytes_req=%u)\n",
893 _LLU(or->in.total_bytes), or->in.req->data_len);
894 }
895
Boaz Harrosh4ef1a3d2009-01-25 16:59:50 +0200896 or->out.pad_buff = sg_out_pad_buffer;
897 or->in.pad_buff = sg_in_pad_buffer;
898
Boaz Harrosh02941a52009-01-25 16:55:30 +0200899 if (!or->attributes_mode)
900 or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS;
901 cdbh->command_specific_options |= or->attributes_mode;
Boaz Harrosh4ef1a3d2009-01-25 16:59:50 +0200902 if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) {
903 ret = _osd_req_finalize_attr_page(or);
904 } else {
905 /* TODO: I think that for the GET_ATTR command these 2 should
906 * be reversed to keep them in execution order (for embeded
907 * targets with low memory footprint)
908 */
909 ret = _osd_req_finalize_set_attr_list(or);
910 if (ret) {
911 OSD_DEBUG("_osd_req_finalize_set_attr_list failed\n");
912 return ret;
913 }
914
915 ret = _osd_req_finalize_get_attr_list(or);
916 if (ret) {
917 OSD_DEBUG("_osd_req_finalize_get_attr_list failed\n");
918 return ret;
919 }
920 }
Boaz Harrosh02941a52009-01-25 16:55:30 +0200921
922 or->request->cmd = or->cdb.buff;
923 or->request->cmd_len = _osd_req_cdb_len(or);
924
925 return 0;
926}
927EXPORT_SYMBOL(osd_finalize_request);
928
929/*
930 * Implementation of osd_sec.h API
931 * TODO: Move to a separate osd_sec.c file at a later stage.
932 */
933
934enum { OSD_SEC_CAP_V1_ALL_CAPS =
935 OSD_SEC_CAP_APPEND | OSD_SEC_CAP_OBJ_MGMT | OSD_SEC_CAP_REMOVE |
936 OSD_SEC_CAP_CREATE | OSD_SEC_CAP_SET_ATTR | OSD_SEC_CAP_GET_ATTR |
937 OSD_SEC_CAP_WRITE | OSD_SEC_CAP_READ | OSD_SEC_CAP_POL_SEC |
938 OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT
939};
940
941void osd_sec_init_nosec_doall_caps(void *caps,
942 const struct osd_obj_id *obj, bool is_collection, const bool is_v1)
943{
944 struct osd_capability *cap = caps;
945 u8 type;
946 u8 descriptor_type;
947
948 if (likely(obj->id)) {
949 if (unlikely(is_collection)) {
950 type = OSD_SEC_OBJ_COLLECTION;
951 descriptor_type = is_v1 ? OSD_SEC_OBJ_DESC_OBJ :
952 OSD_SEC_OBJ_DESC_COL;
953 } else {
954 type = OSD_SEC_OBJ_USER;
955 descriptor_type = OSD_SEC_OBJ_DESC_OBJ;
956 }
957 WARN_ON(!obj->partition);
958 } else {
959 type = obj->partition ? OSD_SEC_OBJ_PARTITION :
960 OSD_SEC_OBJ_ROOT;
961 descriptor_type = OSD_SEC_OBJ_DESC_PAR;
962 }
963
964 memset(cap, 0, sizeof(*cap));
965
966 cap->h.format = OSD_SEC_CAP_FORMAT_VER1;
967 cap->h.integrity_algorithm__key_version = 0; /* MAKE_BYTE(0, 0); */
968 cap->h.security_method = OSD_SEC_NOSEC;
969/* cap->expiration_time;
970 cap->AUDIT[30-10];
971 cap->discriminator[42-30];
972 cap->object_created_time; */
973 cap->h.object_type = type;
974 osd_sec_set_caps(&cap->h, OSD_SEC_CAP_V1_ALL_CAPS);
975 cap->h.object_descriptor_type = descriptor_type;
976 cap->od.obj_desc.policy_access_tag = 0;
977 cap->od.obj_desc.allowed_partition_id = cpu_to_be64(obj->partition);
978 cap->od.obj_desc.allowed_object_id = cpu_to_be64(obj->id);
979}
980EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps);
981
982void osd_set_caps(struct osd_cdb *cdb, const void *caps)
983{
984 memcpy(&cdb->v1.caps, caps, OSDv1_CAP_LEN);
985}
Boaz Harrosh4ef1a3d2009-01-25 16:59:50 +0200986
987/*
988 * Declared in osd_protocol.h
989 * 4.12.5 Data-In and Data-Out buffer offsets
990 * byte offset = mantissa * (2^(exponent+8))
991 * Returns the smallest allowed encoded offset that contains given @offset
992 * The actual encoded offset returned is @offset + *@padding.
993 */
994osd_cdb_offset __osd_encode_offset(
995 u64 offset, unsigned *padding, int min_shift, int max_shift)
996{
997 u64 try_offset = -1, mod, align;
998 osd_cdb_offset be32_offset;
999 int shift;
1000
1001 *padding = 0;
1002 if (!offset)
1003 return 0;
1004
1005 for (shift = min_shift; shift < max_shift; ++shift) {
1006 try_offset = offset >> shift;
1007 if (try_offset < (1 << OSD_OFFSET_MAX_BITS))
1008 break;
1009 }
1010
1011 BUG_ON(shift == max_shift);
1012
1013 align = 1 << shift;
1014 mod = offset & (align - 1);
1015 if (mod) {
1016 *padding = align - mod;
1017 try_offset += 1;
1018 }
1019
1020 try_offset |= ((shift - 8) & 0xf) << 28;
1021 be32_offset = cpu_to_be32((u32)try_offset);
1022
1023 OSD_DEBUG("offset=%llu mantissa=%llu exp=%d encoded=%x pad=%d\n",
1024 _LLU(offset), _LLU(try_offset & 0x0FFFFFFF), shift,
1025 be32_offset, *padding);
1026 return be32_offset;
1027}