diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index f5b5735f76d5..0433ea6f27c9 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c | |||
@@ -1015,6 +1015,77 @@ int osd_req_read_sg(struct osd_request *or, | |||
1015 | } | 1015 | } |
1016 | EXPORT_SYMBOL(osd_req_read_sg); | 1016 | EXPORT_SYMBOL(osd_req_read_sg); |
1017 | 1017 | ||
1018 | /* SG-list write/read Kern API | ||
1019 | * | ||
1020 | * osd_req_{write,read}_sg_kern takes an array of @buff pointers and an array | ||
1021 | * of sg_entries. @numentries indicates how many pointers and sg_entries there | ||
1022 | * are. By requiring an array of buff pointers. This allows a caller to do a | ||
1023 | * single write/read and scatter into multiple buffers. | ||
1024 | * NOTE: Each buffer + len should not cross a page boundary. | ||
1025 | */ | ||
1026 | static struct bio *_create_sg_bios(struct osd_request *or, | ||
1027 | void **buff, const struct osd_sg_entry *sglist, unsigned numentries) | ||
1028 | { | ||
1029 | struct request_queue *q = osd_request_queue(or->osd_dev); | ||
1030 | struct bio *bio; | ||
1031 | unsigned i; | ||
1032 | |||
1033 | bio = bio_kmalloc(GFP_KERNEL, numentries); | ||
1034 | if (unlikely(!bio)) { | ||
1035 | OSD_DEBUG("Faild to allocate BIO size=%u\n", numentries); | ||
1036 | return ERR_PTR(-ENOMEM); | ||
1037 | } | ||
1038 | |||
1039 | for (i = 0; i < numentries; i++) { | ||
1040 | unsigned offset = offset_in_page(buff[i]); | ||
1041 | struct page *page = virt_to_page(buff[i]); | ||
1042 | unsigned len = sglist[i].len; | ||
1043 | unsigned added_len; | ||
1044 | |||
1045 | BUG_ON(offset + len > PAGE_SIZE); | ||
1046 | added_len = bio_add_pc_page(q, bio, page, len, offset); | ||
1047 | if (unlikely(len != added_len)) { | ||
1048 | OSD_DEBUG("bio_add_pc_page len(%d) != added_len(%d)\n", | ||
1049 | len, added_len); | ||
1050 | bio_put(bio); | ||
1051 | return ERR_PTR(-ENOMEM); | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1055 | return bio; | ||
1056 | } | ||
1057 | |||
1058 | int osd_req_write_sg_kern(struct osd_request *or, | ||
1059 | const struct osd_obj_id *obj, void **buff, | ||
1060 | const struct osd_sg_entry *sglist, unsigned numentries) | ||
1061 | { | ||
1062 | struct bio *bio = _create_sg_bios(or, buff, sglist, numentries); | ||
1063 | if (IS_ERR(bio)) | ||
1064 | return PTR_ERR(bio); | ||
1065 | |||
1066 | bio->bi_rw |= REQ_WRITE; | ||
1067 | osd_req_write_sg(or, obj, bio, sglist, numentries); | ||
1068 | |||
1069 | return 0; | ||
1070 | } | ||
1071 | EXPORT_SYMBOL(osd_req_write_sg_kern); | ||
1072 | |||
1073 | int osd_req_read_sg_kern(struct osd_request *or, | ||
1074 | const struct osd_obj_id *obj, void **buff, | ||
1075 | const struct osd_sg_entry *sglist, unsigned numentries) | ||
1076 | { | ||
1077 | struct bio *bio = _create_sg_bios(or, buff, sglist, numentries); | ||
1078 | if (IS_ERR(bio)) | ||
1079 | return PTR_ERR(bio); | ||
1080 | |||
1081 | osd_req_read_sg(or, obj, bio, sglist, numentries); | ||
1082 | |||
1083 | return 0; | ||
1084 | } | ||
1085 | EXPORT_SYMBOL(osd_req_read_sg_kern); | ||
1086 | |||
1087 | |||
1088 | |||
1018 | void osd_req_get_attributes(struct osd_request *or, | 1089 | void osd_req_get_attributes(struct osd_request *or, |
1019 | const struct osd_obj_id *obj) | 1090 | const struct osd_obj_id *obj) |
1020 | { | 1091 | { |