aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/target_core_sbc.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2012-05-20 11:59:15 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2012-07-16 20:27:45 -0400
commit1fd032ee10d2816c947f5d5b9abda95e728f0a8f (patch)
tree2a76ad6b466160127dd41ba1d2f6fdb54f412bf2 /drivers/target/target_core_sbc.c
parentd6e0175cf3f9737a760482d185bb73566bcc9331 (diff)
target: move code for CDB emulation
Move the existing code in target_core_cdb.c into the files for the command sets that the emulations implement. (roland + nab: Squash patch: Fix range calculation in WRITE SAME emulation when num blocks == 0s) Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_sbc.c')
-rw-r--r--drivers/target/target_core_sbc.c239
1 files changed, 220 insertions, 19 deletions
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 9d1ca381487..a5bd0c0eba0 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -37,6 +37,192 @@
37#include "target_core_ua.h" 37#include "target_core_ua.h"
38 38
39 39
40static int sbc_emulate_readcapacity(struct se_cmd *cmd)
41{
42 struct se_device *dev = cmd->se_dev;
43 unsigned char *buf;
44 unsigned long long blocks_long = dev->transport->get_blocks(dev);
45 u32 blocks;
46
47 if (blocks_long >= 0x00000000ffffffff)
48 blocks = 0xffffffff;
49 else
50 blocks = (u32)blocks_long;
51
52 buf = transport_kmap_data_sg(cmd);
53
54 buf[0] = (blocks >> 24) & 0xff;
55 buf[1] = (blocks >> 16) & 0xff;
56 buf[2] = (blocks >> 8) & 0xff;
57 buf[3] = blocks & 0xff;
58 buf[4] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
59 buf[5] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
60 buf[6] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
61 buf[7] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
62
63 transport_kunmap_data_sg(cmd);
64
65 target_complete_cmd(cmd, GOOD);
66 return 0;
67}
68
69static int sbc_emulate_readcapacity_16(struct se_cmd *cmd)
70{
71 struct se_device *dev = cmd->se_dev;
72 unsigned char *buf;
73 unsigned long long blocks = dev->transport->get_blocks(dev);
74
75 buf = transport_kmap_data_sg(cmd);
76
77 buf[0] = (blocks >> 56) & 0xff;
78 buf[1] = (blocks >> 48) & 0xff;
79 buf[2] = (blocks >> 40) & 0xff;
80 buf[3] = (blocks >> 32) & 0xff;
81 buf[4] = (blocks >> 24) & 0xff;
82 buf[5] = (blocks >> 16) & 0xff;
83 buf[6] = (blocks >> 8) & 0xff;
84 buf[7] = blocks & 0xff;
85 buf[8] = (dev->se_sub_dev->se_dev_attrib.block_size >> 24) & 0xff;
86 buf[9] = (dev->se_sub_dev->se_dev_attrib.block_size >> 16) & 0xff;
87 buf[10] = (dev->se_sub_dev->se_dev_attrib.block_size >> 8) & 0xff;
88 buf[11] = dev->se_sub_dev->se_dev_attrib.block_size & 0xff;
89 /*
90 * Set Thin Provisioning Enable bit following sbc3r22 in section
91 * READ CAPACITY (16) byte 14 if emulate_tpu or emulate_tpws is enabled.
92 */
93 if (dev->se_sub_dev->se_dev_attrib.emulate_tpu || dev->se_sub_dev->se_dev_attrib.emulate_tpws)
94 buf[14] = 0x80;
95
96 transport_kunmap_data_sg(cmd);
97
98 target_complete_cmd(cmd, GOOD);
99 return 0;
100}
101
102/*
103 * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
104 * Note this is not used for TCM/pSCSI passthrough
105 */
106static int sbc_emulate_unmap(struct se_cmd *cmd)
107{
108 struct se_device *dev = cmd->se_dev;
109 unsigned char *buf, *ptr = NULL;
110 unsigned char *cdb = &cmd->t_task_cdb[0];
111 sector_t lba;
112 unsigned int size = cmd->data_length, range;
113 int ret = 0, offset;
114 unsigned short dl, bd_dl;
115
116 if (!dev->transport->do_discard) {
117 pr_err("UNMAP emulation not supported for: %s\n",
118 dev->transport->name);
119 cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
120 return -ENOSYS;
121 }
122
123 /* First UNMAP block descriptor starts at 8 byte offset */
124 offset = 8;
125 size -= 8;
126 dl = get_unaligned_be16(&cdb[0]);
127 bd_dl = get_unaligned_be16(&cdb[2]);
128
129 buf = transport_kmap_data_sg(cmd);
130
131 ptr = &buf[offset];
132 pr_debug("UNMAP: Sub: %s Using dl: %hu bd_dl: %hu size: %hu"
133 " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
134
135 while (size) {
136 lba = get_unaligned_be64(&ptr[0]);
137 range = get_unaligned_be32(&ptr[8]);
138 pr_debug("UNMAP: Using lba: %llu and range: %u\n",
139 (unsigned long long)lba, range);
140
141 ret = dev->transport->do_discard(dev, lba, range);
142 if (ret < 0) {
143 pr_err("blkdev_issue_discard() failed: %d\n",
144 ret);
145 goto err;
146 }
147
148 ptr += 16;
149 size -= 16;
150 }
151
152err:
153 transport_kunmap_data_sg(cmd);
154 if (!ret)
155 target_complete_cmd(cmd, GOOD);
156 return ret;
157}
158
159/*
160 * Used for TCM/IBLOCK and TCM/FILEIO for block/blk-lib.c level discard support.
161 * Note this is not used for TCM/pSCSI passthrough
162 */
163static int sbc_emulate_write_same(struct se_cmd *cmd)
164{
165 struct se_device *dev = cmd->se_dev;
166 sector_t range;
167 sector_t lba = cmd->t_task_lba;
168 u32 num_blocks;
169 int ret;
170
171 if (!dev->transport->do_discard) {
172 pr_err("WRITE_SAME emulation not supported"
173 " for: %s\n", dev->transport->name);
174 cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
175 return -ENOSYS;
176 }
177
178 if (cmd->t_task_cdb[0] == WRITE_SAME)
179 num_blocks = get_unaligned_be16(&cmd->t_task_cdb[7]);
180 else if (cmd->t_task_cdb[0] == WRITE_SAME_16)
181 num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
182 else /* WRITE_SAME_32 via VARIABLE_LENGTH_CMD */
183 num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
184
185 /*
186 * Use the explicit range when non zero is supplied, otherwise calculate
187 * the remaining range based on ->get_blocks() - starting LBA.
188 */
189 if (num_blocks != 0)
190 range = num_blocks;
191 else
192 range = (dev->transport->get_blocks(dev) - lba) + 1;
193
194 pr_debug("WRITE_SAME UNMAP: LBA: %llu Range: %llu\n",
195 (unsigned long long)lba, (unsigned long long)range);
196
197 ret = dev->transport->do_discard(dev, lba, range);
198 if (ret < 0) {
199 pr_debug("blkdev_issue_discard() failed for WRITE_SAME\n");
200 return ret;
201 }
202
203 target_complete_cmd(cmd, GOOD);
204 return 0;
205}
206
207static int sbc_emulate_synchronize_cache(struct se_cmd *cmd)
208{
209 if (!cmd->se_dev->transport->do_sync_cache) {
210 pr_err("SYNCHRONIZE_CACHE emulation not supported"
211 " for: %s\n", cmd->se_dev->transport->name);
212 cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
213 return -ENOSYS;
214 }
215
216 cmd->se_dev->transport->do_sync_cache(cmd);
217 return 0;
218}
219
220static int sbc_emulate_verify(struct se_cmd *cmd)
221{
222 target_complete_cmd(cmd, GOOD);
223 return 0;
224}
225
40static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors) 226static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)
41{ 227{
42 return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors; 228 return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors;
@@ -209,11 +395,12 @@ out:
209 kfree(buf); 395 kfree(buf);
210} 396}
211 397
212int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) 398int sbc_parse_cdb(struct se_cmd *cmd)
213{ 399{
214 struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev; 400 struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
215 struct se_device *dev = cmd->se_dev; 401 struct se_device *dev = cmd->se_dev;
216 unsigned char *cdb = cmd->t_task_cdb; 402 unsigned char *cdb = cmd->t_task_cdb;
403 unsigned int size;
217 u32 sectors = 0; 404 u32 sectors = 0;
218 int ret; 405 int ret;
219 406
@@ -311,12 +498,12 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
311 goto out_invalid_cdb_field; 498 goto out_invalid_cdb_field;
312 } 499 }
313 500
314 *size = sbc_get_size(cmd, 1); 501 size = sbc_get_size(cmd, 1);
315 cmd->t_task_lba = get_unaligned_be64(&cdb[12]); 502 cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
316 503
317 if (sbc_write_same_supported(dev, &cdb[10]) < 0) 504 if (sbc_write_same_supported(dev, &cdb[10]) < 0)
318 goto out_unsupported_cdb; 505 goto out_unsupported_cdb;
319 cmd->execute_cmd = target_emulate_write_same; 506 cmd->execute_cmd = sbc_emulate_write_same;
320 break; 507 break;
321 default: 508 default:
322 pr_err("VARIABLE_LENGTH_CMD service action" 509 pr_err("VARIABLE_LENGTH_CMD service action"
@@ -326,20 +513,20 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
326 break; 513 break;
327 } 514 }
328 case READ_CAPACITY: 515 case READ_CAPACITY:
329 *size = READ_CAP_LEN; 516 size = READ_CAP_LEN;
330 cmd->execute_cmd = target_emulate_readcapacity; 517 cmd->execute_cmd = sbc_emulate_readcapacity;
331 break; 518 break;
332 case SERVICE_ACTION_IN: 519 case SERVICE_ACTION_IN:
333 switch (cmd->t_task_cdb[1] & 0x1f) { 520 switch (cmd->t_task_cdb[1] & 0x1f) {
334 case SAI_READ_CAPACITY_16: 521 case SAI_READ_CAPACITY_16:
335 cmd->execute_cmd = target_emulate_readcapacity_16; 522 cmd->execute_cmd = sbc_emulate_readcapacity_16;
336 break; 523 break;
337 default: 524 default:
338 pr_err("Unsupported SA: 0x%02x\n", 525 pr_err("Unsupported SA: 0x%02x\n",
339 cmd->t_task_cdb[1] & 0x1f); 526 cmd->t_task_cdb[1] & 0x1f);
340 goto out_invalid_cdb_field; 527 goto out_invalid_cdb_field;
341 } 528 }
342 *size = (cdb[10] << 24) | (cdb[11] << 16) | 529 size = (cdb[10] << 24) | (cdb[11] << 16) |
343 (cdb[12] << 8) | cdb[13]; 530 (cdb[12] << 8) | cdb[13];
344 break; 531 break;
345 case SYNCHRONIZE_CACHE: 532 case SYNCHRONIZE_CACHE:
@@ -355,7 +542,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
355 cmd->t_task_lba = transport_lba_64(cdb); 542 cmd->t_task_lba = transport_lba_64(cdb);
356 } 543 }
357 544
358 *size = sbc_get_size(cmd, sectors); 545 size = sbc_get_size(cmd, sectors);
359 546
360 /* 547 /*
361 * Check to ensure that LBA + Range does not exceed past end of 548 * Check to ensure that LBA + Range does not exceed past end of
@@ -365,11 +552,11 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
365 if (sbc_check_valid_sectors(cmd) < 0) 552 if (sbc_check_valid_sectors(cmd) < 0)
366 goto out_invalid_cdb_field; 553 goto out_invalid_cdb_field;
367 } 554 }
368 cmd->execute_cmd = target_emulate_synchronize_cache; 555 cmd->execute_cmd = sbc_emulate_synchronize_cache;
369 break; 556 break;
370 case UNMAP: 557 case UNMAP:
371 *size = get_unaligned_be16(&cdb[7]); 558 size = get_unaligned_be16(&cdb[7]);
372 cmd->execute_cmd = target_emulate_unmap; 559 cmd->execute_cmd = sbc_emulate_unmap;
373 break; 560 break;
374 case WRITE_SAME_16: 561 case WRITE_SAME_16:
375 sectors = transport_get_sectors_16(cdb); 562 sectors = transport_get_sectors_16(cdb);
@@ -378,12 +565,12 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
378 goto out_invalid_cdb_field; 565 goto out_invalid_cdb_field;
379 } 566 }
380 567
381 *size = sbc_get_size(cmd, 1); 568 size = sbc_get_size(cmd, 1);
382 cmd->t_task_lba = get_unaligned_be64(&cdb[2]); 569 cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
383 570
384 if (sbc_write_same_supported(dev, &cdb[1]) < 0) 571 if (sbc_write_same_supported(dev, &cdb[1]) < 0)
385 goto out_unsupported_cdb; 572 goto out_unsupported_cdb;
386 cmd->execute_cmd = target_emulate_write_same; 573 cmd->execute_cmd = sbc_emulate_write_same;
387 break; 574 break;
388 case WRITE_SAME: 575 case WRITE_SAME:
389 sectors = transport_get_sectors_10(cdb); 576 sectors = transport_get_sectors_10(cdb);
@@ -392,7 +579,7 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
392 goto out_invalid_cdb_field; 579 goto out_invalid_cdb_field;
393 } 580 }
394 581
395 *size = sbc_get_size(cmd, 1); 582 size = sbc_get_size(cmd, 1);
396 cmd->t_task_lba = get_unaligned_be32(&cdb[2]); 583 cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
397 584
398 /* 585 /*
@@ -401,14 +588,14 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
401 */ 588 */
402 if (sbc_write_same_supported(dev, &cdb[1]) < 0) 589 if (sbc_write_same_supported(dev, &cdb[1]) < 0)
403 goto out_unsupported_cdb; 590 goto out_unsupported_cdb;
404 cmd->execute_cmd = target_emulate_write_same; 591 cmd->execute_cmd = sbc_emulate_write_same;
405 break; 592 break;
406 case VERIFY: 593 case VERIFY:
407 *size = 0; 594 size = 0;
408 cmd->execute_cmd = target_emulate_noop; 595 cmd->execute_cmd = sbc_emulate_verify;
409 break; 596 break;
410 default: 597 default:
411 ret = spc_parse_cdb(cmd, size, false); 598 ret = spc_parse_cdb(cmd, &size);
412 if (ret) 599 if (ret)
413 return ret; 600 return ret;
414 } 601 }
@@ -418,6 +605,8 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
418 goto out_unsupported_cdb; 605 goto out_unsupported_cdb;
419 606
420 if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { 607 if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
608 unsigned long long end_lba;
609
421 if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) { 610 if (sectors > su_dev->se_dev_attrib.fabric_max_sectors) {
422 printk_ratelimited(KERN_ERR "SCSI OP %02xh with too" 611 printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
423 " big sectors %u exceeds fabric_max_sectors:" 612 " big sectors %u exceeds fabric_max_sectors:"
@@ -433,9 +622,21 @@ int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
433 goto out_invalid_cdb_field; 622 goto out_invalid_cdb_field;
434 } 623 }
435 624
436 *size = sbc_get_size(cmd, sectors); 625 end_lba = dev->transport->get_blocks(dev) + 1;
626 if (cmd->t_task_lba + sectors > end_lba) {
627 pr_err("cmd exceeds last lba %llu "
628 "(lba %llu, sectors %u)\n",
629 end_lba, cmd->t_task_lba, sectors);
630 goto out_invalid_cdb_field;
631 }
632
633 size = sbc_get_size(cmd, sectors);
437 } 634 }
438 635
636 ret = target_cmd_size_check(cmd, size);
637 if (ret < 0)
638 return ret;
639
439 return 0; 640 return 0;
440 641
441out_unsupported_cdb: 642out_unsupported_cdb: