diff options
author | Christoph Hellwig <hch@infradead.org> | 2012-05-20 11:59:15 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-07-16 20:27:45 -0400 |
commit | 1fd032ee10d2816c947f5d5b9abda95e728f0a8f (patch) | |
tree | 2a76ad6b466160127dd41ba1d2f6fdb54f412bf2 /drivers/target/target_core_sbc.c | |
parent | d6e0175cf3f9737a760482d185bb73566bcc9331 (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.c | 239 |
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 | ||
40 | static 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 | |||
69 | static 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 | */ | ||
106 | static 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 | |||
152 | err: | ||
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 | */ | ||
163 | static 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 | |||
207 | static 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 | |||
220 | static int sbc_emulate_verify(struct se_cmd *cmd) | ||
221 | { | ||
222 | target_complete_cmd(cmd, GOOD); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
40 | static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors) | 226 | static 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 | ||
212 | int sbc_parse_cdb(struct se_cmd *cmd, unsigned int *size) | 398 | int 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 | ||
441 | out_unsupported_cdb: | 642 | out_unsupported_cdb: |