diff options
Diffstat (limited to 'drivers/target/target_core_rd.c')
-rw-r--r-- | drivers/target/target_core_rd.c | 252 |
1 files changed, 207 insertions, 45 deletions
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 4ffe5f2ec0e9..66a5aba5a0d9 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c | |||
@@ -78,23 +78,14 @@ static void rd_detach_hba(struct se_hba *hba) | |||
78 | hba->hba_ptr = NULL; | 78 | hba->hba_ptr = NULL; |
79 | } | 79 | } |
80 | 80 | ||
81 | /* rd_release_device_space(): | 81 | static u32 rd_release_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *sg_table, |
82 | * | 82 | u32 sg_table_count) |
83 | * | ||
84 | */ | ||
85 | static void rd_release_device_space(struct rd_dev *rd_dev) | ||
86 | { | 83 | { |
87 | u32 i, j, page_count = 0, sg_per_table; | ||
88 | struct rd_dev_sg_table *sg_table; | ||
89 | struct page *pg; | 84 | struct page *pg; |
90 | struct scatterlist *sg; | 85 | struct scatterlist *sg; |
86 | u32 i, j, page_count = 0, sg_per_table; | ||
91 | 87 | ||
92 | if (!rd_dev->sg_table_array || !rd_dev->sg_table_count) | 88 | for (i = 0; i < sg_table_count; i++) { |
93 | return; | ||
94 | |||
95 | sg_table = rd_dev->sg_table_array; | ||
96 | |||
97 | for (i = 0; i < rd_dev->sg_table_count; i++) { | ||
98 | sg = sg_table[i].sg_table; | 89 | sg = sg_table[i].sg_table; |
99 | sg_per_table = sg_table[i].rd_sg_count; | 90 | sg_per_table = sg_table[i].rd_sg_count; |
100 | 91 | ||
@@ -105,16 +96,28 @@ static void rd_release_device_space(struct rd_dev *rd_dev) | |||
105 | page_count++; | 96 | page_count++; |
106 | } | 97 | } |
107 | } | 98 | } |
108 | |||
109 | kfree(sg); | 99 | kfree(sg); |
110 | } | 100 | } |
111 | 101 | ||
102 | kfree(sg_table); | ||
103 | return page_count; | ||
104 | } | ||
105 | |||
106 | static void rd_release_device_space(struct rd_dev *rd_dev) | ||
107 | { | ||
108 | u32 page_count; | ||
109 | |||
110 | if (!rd_dev->sg_table_array || !rd_dev->sg_table_count) | ||
111 | return; | ||
112 | |||
113 | page_count = rd_release_sgl_table(rd_dev, rd_dev->sg_table_array, | ||
114 | rd_dev->sg_table_count); | ||
115 | |||
112 | pr_debug("CORE_RD[%u] - Released device space for Ramdisk" | 116 | pr_debug("CORE_RD[%u] - Released device space for Ramdisk" |
113 | " Device ID: %u, pages %u in %u tables total bytes %lu\n", | 117 | " Device ID: %u, pages %u in %u tables total bytes %lu\n", |
114 | rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count, | 118 | rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count, |
115 | rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE); | 119 | rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE); |
116 | 120 | ||
117 | kfree(sg_table); | ||
118 | rd_dev->sg_table_array = NULL; | 121 | rd_dev->sg_table_array = NULL; |
119 | rd_dev->sg_table_count = 0; | 122 | rd_dev->sg_table_count = 0; |
120 | } | 123 | } |
@@ -124,38 +127,15 @@ static void rd_release_device_space(struct rd_dev *rd_dev) | |||
124 | * | 127 | * |
125 | * | 128 | * |
126 | */ | 129 | */ |
127 | static int rd_build_device_space(struct rd_dev *rd_dev) | 130 | static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *sg_table, |
131 | u32 total_sg_needed, unsigned char init_payload) | ||
128 | { | 132 | { |
129 | u32 i = 0, j, page_offset = 0, sg_per_table, sg_tables, total_sg_needed; | 133 | u32 i = 0, j, page_offset = 0, sg_per_table; |
130 | u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE / | 134 | u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE / |
131 | sizeof(struct scatterlist)); | 135 | sizeof(struct scatterlist)); |
132 | struct rd_dev_sg_table *sg_table; | ||
133 | struct page *pg; | 136 | struct page *pg; |
134 | struct scatterlist *sg; | 137 | struct scatterlist *sg; |
135 | 138 | unsigned char *p; | |
136 | if (rd_dev->rd_page_count <= 0) { | ||
137 | pr_err("Illegal page count: %u for Ramdisk device\n", | ||
138 | rd_dev->rd_page_count); | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | |||
142 | /* Don't need backing pages for NULLIO */ | ||
143 | if (rd_dev->rd_flags & RDF_NULLIO) | ||
144 | return 0; | ||
145 | |||
146 | total_sg_needed = rd_dev->rd_page_count; | ||
147 | |||
148 | sg_tables = (total_sg_needed / max_sg_per_table) + 1; | ||
149 | |||
150 | sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL); | ||
151 | if (!sg_table) { | ||
152 | pr_err("Unable to allocate memory for Ramdisk" | ||
153 | " scatterlist tables\n"); | ||
154 | return -ENOMEM; | ||
155 | } | ||
156 | |||
157 | rd_dev->sg_table_array = sg_table; | ||
158 | rd_dev->sg_table_count = sg_tables; | ||
159 | 139 | ||
160 | while (total_sg_needed) { | 140 | while (total_sg_needed) { |
161 | sg_per_table = (total_sg_needed > max_sg_per_table) ? | 141 | sg_per_table = (total_sg_needed > max_sg_per_table) ? |
@@ -186,16 +166,114 @@ static int rd_build_device_space(struct rd_dev *rd_dev) | |||
186 | } | 166 | } |
187 | sg_assign_page(&sg[j], pg); | 167 | sg_assign_page(&sg[j], pg); |
188 | sg[j].length = PAGE_SIZE; | 168 | sg[j].length = PAGE_SIZE; |
169 | |||
170 | p = kmap(pg); | ||
171 | memset(p, init_payload, PAGE_SIZE); | ||
172 | kunmap(pg); | ||
189 | } | 173 | } |
190 | 174 | ||
191 | page_offset += sg_per_table; | 175 | page_offset += sg_per_table; |
192 | total_sg_needed -= sg_per_table; | 176 | total_sg_needed -= sg_per_table; |
193 | } | 177 | } |
194 | 178 | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int rd_build_device_space(struct rd_dev *rd_dev) | ||
183 | { | ||
184 | struct rd_dev_sg_table *sg_table; | ||
185 | u32 sg_tables, total_sg_needed; | ||
186 | u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE / | ||
187 | sizeof(struct scatterlist)); | ||
188 | int rc; | ||
189 | |||
190 | if (rd_dev->rd_page_count <= 0) { | ||
191 | pr_err("Illegal page count: %u for Ramdisk device\n", | ||
192 | rd_dev->rd_page_count); | ||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | /* Don't need backing pages for NULLIO */ | ||
197 | if (rd_dev->rd_flags & RDF_NULLIO) | ||
198 | return 0; | ||
199 | |||
200 | total_sg_needed = rd_dev->rd_page_count; | ||
201 | |||
202 | sg_tables = (total_sg_needed / max_sg_per_table) + 1; | ||
203 | |||
204 | sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL); | ||
205 | if (!sg_table) { | ||
206 | pr_err("Unable to allocate memory for Ramdisk" | ||
207 | " scatterlist tables\n"); | ||
208 | return -ENOMEM; | ||
209 | } | ||
210 | |||
211 | rd_dev->sg_table_array = sg_table; | ||
212 | rd_dev->sg_table_count = sg_tables; | ||
213 | |||
214 | rc = rd_allocate_sgl_table(rd_dev, sg_table, total_sg_needed, 0x00); | ||
215 | if (rc) | ||
216 | return rc; | ||
217 | |||
195 | pr_debug("CORE_RD[%u] - Built Ramdisk Device ID: %u space of" | 218 | pr_debug("CORE_RD[%u] - Built Ramdisk Device ID: %u space of" |
196 | " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id, | 219 | " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id, |
197 | rd_dev->rd_dev_id, rd_dev->rd_page_count, | 220 | rd_dev->rd_dev_id, rd_dev->rd_page_count, |
198 | rd_dev->sg_table_count); | 221 | rd_dev->sg_table_count); |
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static void rd_release_prot_space(struct rd_dev *rd_dev) | ||
227 | { | ||
228 | u32 page_count; | ||
229 | |||
230 | if (!rd_dev->sg_prot_array || !rd_dev->sg_prot_count) | ||
231 | return; | ||
232 | |||
233 | page_count = rd_release_sgl_table(rd_dev, rd_dev->sg_prot_array, | ||
234 | rd_dev->sg_prot_count); | ||
235 | |||
236 | pr_debug("CORE_RD[%u] - Released protection space for Ramdisk" | ||
237 | " Device ID: %u, pages %u in %u tables total bytes %lu\n", | ||
238 | rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count, | ||
239 | rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE); | ||
240 | |||
241 | rd_dev->sg_prot_array = NULL; | ||
242 | rd_dev->sg_prot_count = 0; | ||
243 | } | ||
244 | |||
245 | static int rd_build_prot_space(struct rd_dev *rd_dev, int prot_length) | ||
246 | { | ||
247 | struct rd_dev_sg_table *sg_table; | ||
248 | u32 total_sg_needed, sg_tables; | ||
249 | u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE / | ||
250 | sizeof(struct scatterlist)); | ||
251 | int rc; | ||
252 | |||
253 | if (rd_dev->rd_flags & RDF_NULLIO) | ||
254 | return 0; | ||
255 | |||
256 | total_sg_needed = rd_dev->rd_page_count / prot_length; | ||
257 | |||
258 | sg_tables = (total_sg_needed / max_sg_per_table) + 1; | ||
259 | |||
260 | sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL); | ||
261 | if (!sg_table) { | ||
262 | pr_err("Unable to allocate memory for Ramdisk protection" | ||
263 | " scatterlist tables\n"); | ||
264 | return -ENOMEM; | ||
265 | } | ||
266 | |||
267 | rd_dev->sg_prot_array = sg_table; | ||
268 | rd_dev->sg_prot_count = sg_tables; | ||
269 | |||
270 | rc = rd_allocate_sgl_table(rd_dev, sg_table, total_sg_needed, 0xff); | ||
271 | if (rc) | ||
272 | return rc; | ||
273 | |||
274 | pr_debug("CORE_RD[%u] - Built Ramdisk Device ID: %u prot space of" | ||
275 | " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id, | ||
276 | rd_dev->rd_dev_id, total_sg_needed, rd_dev->sg_prot_count); | ||
199 | 277 | ||
200 | return 0; | 278 | return 0; |
201 | } | 279 | } |
@@ -278,6 +356,26 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) | |||
278 | return NULL; | 356 | return NULL; |
279 | } | 357 | } |
280 | 358 | ||
359 | static struct rd_dev_sg_table *rd_get_prot_table(struct rd_dev *rd_dev, u32 page) | ||
360 | { | ||
361 | struct rd_dev_sg_table *sg_table; | ||
362 | u32 i, sg_per_table = (RD_MAX_ALLOCATION_SIZE / | ||
363 | sizeof(struct scatterlist)); | ||
364 | |||
365 | i = page / sg_per_table; | ||
366 | if (i < rd_dev->sg_prot_count) { | ||
367 | sg_table = &rd_dev->sg_prot_array[i]; | ||
368 | if ((sg_table->page_start_offset <= page) && | ||
369 | (sg_table->page_end_offset >= page)) | ||
370 | return sg_table; | ||
371 | } | ||
372 | |||
373 | pr_err("Unable to locate struct prot rd_dev_sg_table for page: %u\n", | ||
374 | page); | ||
375 | |||
376 | return NULL; | ||
377 | } | ||
378 | |||
281 | static sense_reason_t | 379 | static sense_reason_t |
282 | rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | 380 | rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, |
283 | enum dma_data_direction data_direction) | 381 | enum dma_data_direction data_direction) |
@@ -292,6 +390,7 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
292 | u32 rd_page; | 390 | u32 rd_page; |
293 | u32 src_len; | 391 | u32 src_len; |
294 | u64 tmp; | 392 | u64 tmp; |
393 | sense_reason_t rc; | ||
295 | 394 | ||
296 | if (dev->rd_flags & RDF_NULLIO) { | 395 | if (dev->rd_flags & RDF_NULLIO) { |
297 | target_complete_cmd(cmd, SAM_STAT_GOOD); | 396 | target_complete_cmd(cmd, SAM_STAT_GOOD); |
@@ -314,6 +413,28 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
314 | data_direction == DMA_FROM_DEVICE ? "Read" : "Write", | 413 | data_direction == DMA_FROM_DEVICE ? "Read" : "Write", |
315 | cmd->t_task_lba, rd_size, rd_page, rd_offset); | 414 | cmd->t_task_lba, rd_size, rd_page, rd_offset); |
316 | 415 | ||
416 | if (cmd->prot_type && data_direction == DMA_TO_DEVICE) { | ||
417 | struct rd_dev_sg_table *prot_table; | ||
418 | struct scatterlist *prot_sg; | ||
419 | u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size; | ||
420 | u32 prot_offset, prot_page; | ||
421 | |||
422 | tmp = cmd->t_task_lba * se_dev->prot_length; | ||
423 | prot_offset = do_div(tmp, PAGE_SIZE); | ||
424 | prot_page = tmp; | ||
425 | |||
426 | prot_table = rd_get_prot_table(dev, prot_page); | ||
427 | if (!prot_table) | ||
428 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
429 | |||
430 | prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset]; | ||
431 | |||
432 | rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, 0, | ||
433 | prot_sg, prot_offset); | ||
434 | if (rc) | ||
435 | return rc; | ||
436 | } | ||
437 | |||
317 | src_len = PAGE_SIZE - rd_offset; | 438 | src_len = PAGE_SIZE - rd_offset; |
318 | sg_miter_start(&m, sgl, sgl_nents, | 439 | sg_miter_start(&m, sgl, sgl_nents, |
319 | data_direction == DMA_FROM_DEVICE ? | 440 | data_direction == DMA_FROM_DEVICE ? |
@@ -375,6 +496,28 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
375 | } | 496 | } |
376 | sg_miter_stop(&m); | 497 | sg_miter_stop(&m); |
377 | 498 | ||
499 | if (cmd->prot_type && data_direction == DMA_FROM_DEVICE) { | ||
500 | struct rd_dev_sg_table *prot_table; | ||
501 | struct scatterlist *prot_sg; | ||
502 | u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size; | ||
503 | u32 prot_offset, prot_page; | ||
504 | |||
505 | tmp = cmd->t_task_lba * se_dev->prot_length; | ||
506 | prot_offset = do_div(tmp, PAGE_SIZE); | ||
507 | prot_page = tmp; | ||
508 | |||
509 | prot_table = rd_get_prot_table(dev, prot_page); | ||
510 | if (!prot_table) | ||
511 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
512 | |||
513 | prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset]; | ||
514 | |||
515 | rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0, | ||
516 | prot_sg, prot_offset); | ||
517 | if (rc) | ||
518 | return rc; | ||
519 | } | ||
520 | |||
378 | target_complete_cmd(cmd, SAM_STAT_GOOD); | 521 | target_complete_cmd(cmd, SAM_STAT_GOOD); |
379 | return 0; | 522 | return 0; |
380 | } | 523 | } |
@@ -456,6 +599,23 @@ static sector_t rd_get_blocks(struct se_device *dev) | |||
456 | return blocks_long; | 599 | return blocks_long; |
457 | } | 600 | } |
458 | 601 | ||
602 | static int rd_init_prot(struct se_device *dev) | ||
603 | { | ||
604 | struct rd_dev *rd_dev = RD_DEV(dev); | ||
605 | |||
606 | if (!dev->dev_attrib.pi_prot_type) | ||
607 | return 0; | ||
608 | |||
609 | return rd_build_prot_space(rd_dev, dev->prot_length); | ||
610 | } | ||
611 | |||
612 | static void rd_free_prot(struct se_device *dev) | ||
613 | { | ||
614 | struct rd_dev *rd_dev = RD_DEV(dev); | ||
615 | |||
616 | rd_release_prot_space(rd_dev); | ||
617 | } | ||
618 | |||
459 | static struct sbc_ops rd_sbc_ops = { | 619 | static struct sbc_ops rd_sbc_ops = { |
460 | .execute_rw = rd_execute_rw, | 620 | .execute_rw = rd_execute_rw, |
461 | }; | 621 | }; |
@@ -481,6 +641,8 @@ static struct se_subsystem_api rd_mcp_template = { | |||
481 | .show_configfs_dev_params = rd_show_configfs_dev_params, | 641 | .show_configfs_dev_params = rd_show_configfs_dev_params, |
482 | .get_device_type = sbc_get_device_type, | 642 | .get_device_type = sbc_get_device_type, |
483 | .get_blocks = rd_get_blocks, | 643 | .get_blocks = rd_get_blocks, |
644 | .init_prot = rd_init_prot, | ||
645 | .free_prot = rd_free_prot, | ||
484 | }; | 646 | }; |
485 | 647 | ||
486 | int __init rd_module_init(void) | 648 | int __init rd_module_init(void) |