Blame view
drivers/target/target_core_iblock.c
20.9 KB
c66ac9db8 [SCSI] target: Ad... |
1 2 3 4 5 6 |
/******************************************************************************* * Filename: target_core_iblock.c * * This file contains the Storage Engine <-> Linux BlockIO transport * specific functions. * |
4c76251e8 target: Update co... |
7 |
* (c) Copyright 2003-2013 Datera, Inc. |
c66ac9db8 [SCSI] target: Ad... |
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
* * Nicholas A. Bellinger <nab@kernel.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ******************************************************************************/ |
c66ac9db8 [SCSI] target: Ad... |
26 27 28 29 30 31 32 |
#include <linux/string.h> #include <linux/parser.h> #include <linux/timer.h> #include <linux/fs.h> #include <linux/blkdev.h> #include <linux/slab.h> #include <linux/spinlock.h> |
c66ac9db8 [SCSI] target: Ad... |
33 34 35 |
#include <linux/bio.h> #include <linux/genhd.h> #include <linux/file.h> |
827509e38 drivers/target: A... |
36 |
#include <linux/module.h> |
ba9299925 target: Minimize ... |
37 |
#include <scsi/scsi_proto.h> |
14150a6bb target: move unma... |
38 |
#include <asm/unaligned.h> |
c66ac9db8 [SCSI] target: Ad... |
39 40 |
#include <target/target_core_base.h> |
c4795fb20 target: header re... |
41 |
#include <target/target_core_backend.h> |
c66ac9db8 [SCSI] target: Ad... |
42 43 |
#include "target_core_iblock.h" |
d5b4a21b3 target: increase ... |
44 45 |
#define IBLOCK_MAX_BIO_PER_TASK 32 /* max # of bios to submit at a time */ #define IBLOCK_BIO_POOL_SIZE 128 |
0fd97ccf4 target: kill stru... |
46 47 48 49 |
static inline struct iblock_dev *IBLOCK_DEV(struct se_device *dev) { return container_of(dev, struct iblock_dev, dev); } |
c66ac9db8 [SCSI] target: Ad... |
50 51 |
static int iblock_attach_hba(struct se_hba *hba, u32 host_id) { |
6708bb27b target: Follow up... |
52 |
pr_debug("CORE_HBA[%d] - TCM iBlock HBA Driver %s on" |
c66ac9db8 [SCSI] target: Ad... |
53 54 |
" Generic Target Core Stack %s ", hba->hba_id, |
ce8dd25d0 target: consolida... |
55 |
IBLOCK_VERSION, TARGET_CORE_VERSION); |
c66ac9db8 [SCSI] target: Ad... |
56 57 58 59 60 |
return 0; } static void iblock_detach_hba(struct se_hba *hba) { |
c66ac9db8 [SCSI] target: Ad... |
61 |
} |
0fd97ccf4 target: kill stru... |
62 |
static struct se_device *iblock_alloc_device(struct se_hba *hba, const char *name) |
c66ac9db8 [SCSI] target: Ad... |
63 64 |
{ struct iblock_dev *ib_dev = NULL; |
c66ac9db8 [SCSI] target: Ad... |
65 66 |
ib_dev = kzalloc(sizeof(struct iblock_dev), GFP_KERNEL); |
6708bb27b target: Follow up... |
67 68 69 |
if (!ib_dev) { pr_err("Unable to allocate struct iblock_dev "); |
c66ac9db8 [SCSI] target: Ad... |
70 71 |
return NULL; } |
c66ac9db8 [SCSI] target: Ad... |
72 |
|
6708bb27b target: Follow up... |
73 74 |
pr_debug( "IBLOCK: Allocated ib_dev for %s ", name); |
c66ac9db8 [SCSI] target: Ad... |
75 |
|
0fd97ccf4 target: kill stru... |
76 |
return &ib_dev->dev; |
c66ac9db8 [SCSI] target: Ad... |
77 |
} |
0fd97ccf4 target: kill stru... |
78 |
static int iblock_configure_device(struct se_device *dev) |
c66ac9db8 [SCSI] target: Ad... |
79 |
{ |
0fd97ccf4 target: kill stru... |
80 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); |
c66ac9db8 [SCSI] target: Ad... |
81 |
struct request_queue *q; |
0fd97ccf4 target: kill stru... |
82 |
struct block_device *bd = NULL; |
ecebbf6cc target/iblock: Ad... |
83 |
struct blk_integrity *bi; |
44bfd0185 target/iblock: Ad... |
84 |
fmode_t mode; |
0fd97ccf4 target: kill stru... |
85 |
int ret = -ENOMEM; |
c66ac9db8 [SCSI] target: Ad... |
86 |
|
0fd97ccf4 target: kill stru... |
87 88 89 90 |
if (!(ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH)) { pr_err("Missing udev_path= parameters for IBLOCK "); return -EINVAL; |
c66ac9db8 [SCSI] target: Ad... |
91 |
} |
d5b4a21b3 target: increase ... |
92 93 |
ib_dev->ibd_bio_set = bioset_create(IBLOCK_BIO_POOL_SIZE, 0); |
6708bb27b target: Follow up... |
94 |
if (!ib_dev->ibd_bio_set) { |
0fd97ccf4 target: kill stru... |
95 96 97 |
pr_err("IBLOCK: Unable to create bioset "); goto out; |
c66ac9db8 [SCSI] target: Ad... |
98 |
} |
0fd97ccf4 target: kill stru... |
99 |
|
6708bb27b target: Follow up... |
100 101 |
pr_debug( "IBLOCK: Claiming struct block_device: %s ", |
c66ac9db8 [SCSI] target: Ad... |
102 |
ib_dev->ibd_udev_path); |
44bfd0185 target/iblock: Ad... |
103 104 105 |
mode = FMODE_READ|FMODE_EXCL; if (!ib_dev->ibd_readonly) mode |= FMODE_WRITE; |
eeeb95222 target: Propigate... |
106 107 |
else dev->dev_flags |= DF_READ_ONLY; |
44bfd0185 target/iblock: Ad... |
108 109 |
bd = blkdev_get_by_path(ib_dev->ibd_udev_path, mode, ib_dev); |
613640e4e [SCSI] target: Co... |
110 111 |
if (IS_ERR(bd)) { ret = PTR_ERR(bd); |
0fd97ccf4 target: kill stru... |
112 |
goto out_free_bioset; |
613640e4e [SCSI] target: Co... |
113 |
} |
c66ac9db8 [SCSI] target: Ad... |
114 |
ib_dev->ibd_bd = bd; |
0fd97ccf4 target: kill stru... |
115 116 117 |
q = bdev_get_queue(bd); dev->dev_attrib.hw_block_size = bdev_logical_block_size(bd); |
046ba6428 target: Drop arbi... |
118 |
dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q); |
0fd97ccf4 target: kill stru... |
119 |
dev->dev_attrib.hw_queue_depth = q->nr_requests; |
c66ac9db8 [SCSI] target: Ad... |
120 |
|
8a9ebe717 target: Fix WRITE... |
121 122 |
if (target_configure_unmap_from_queue(&dev->dev_attrib, q, dev->dev_attrib.hw_block_size)) |
6708bb27b target: Follow up... |
123 |
pr_debug("IBLOCK: BLOCK Discard support available," |
8a9ebe717 target: Fix WRITE... |
124 125 |
" disabled by default "); |
f6970ad31 target/iblock: Ad... |
126 127 128 129 130 |
/* * Enable write same emulation for IBLOCK and use 0xFFFF as * the smaller WRITE_SAME(10) only has a two-byte block count. */ dev->dev_attrib.max_write_same_len = 0xFFFF; |
c66ac9db8 [SCSI] target: Ad... |
131 |
|
e22a7f075 target: Implement... |
132 |
if (blk_queue_nonrot(q)) |
0fd97ccf4 target: kill stru... |
133 |
dev->dev_attrib.is_nonrot = 1; |
d0c8b259f target/iblock: Us... |
134 |
|
ecebbf6cc target/iblock: Ad... |
135 136 137 |
bi = bdev_get_integrity(bd); if (bi) { struct bio_set *bs = ib_dev->ibd_bio_set; |
0f8087ecd block: Consolidat... |
138 139 |
if (!strcmp(bi->profile->name, "T10-DIF-TYPE3-IP") || !strcmp(bi->profile->name, "T10-DIF-TYPE1-IP")) { |
ecebbf6cc target/iblock: Ad... |
140 |
pr_err("IBLOCK export of blk_integrity: %s not" |
0f8087ecd block: Consolidat... |
141 142 |
" supported ", bi->profile->name); |
ecebbf6cc target/iblock: Ad... |
143 144 145 |
ret = -ENOSYS; goto out_blkdev_put; } |
0f8087ecd block: Consolidat... |
146 |
if (!strcmp(bi->profile->name, "T10-DIF-TYPE3-CRC")) { |
ecebbf6cc target/iblock: Ad... |
147 |
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE3_PROT; |
0f8087ecd block: Consolidat... |
148 |
} else if (!strcmp(bi->profile->name, "T10-DIF-TYPE1-CRC")) { |
ecebbf6cc target/iblock: Ad... |
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE1_PROT; } if (dev->dev_attrib.pi_prot_type) { if (bioset_integrity_create(bs, IBLOCK_BIO_POOL_SIZE) < 0) { pr_err("Unable to allocate bioset for PI "); ret = -ENOMEM; goto out_blkdev_put; } pr_debug("IBLOCK setup BIP bs->bio_integrity_pool: %p ", bs->bio_integrity_pool); } dev->dev_attrib.hw_pi_prot_type = dev->dev_attrib.pi_prot_type; } |
0fd97ccf4 target: kill stru... |
165 |
return 0; |
c66ac9db8 [SCSI] target: Ad... |
166 |
|
ecebbf6cc target/iblock: Ad... |
167 168 |
out_blkdev_put: blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); |
0fd97ccf4 target: kill stru... |
169 170 171 172 173 |
out_free_bioset: bioset_free(ib_dev->ibd_bio_set); ib_dev->ibd_bio_set = NULL; out: return ret; |
c66ac9db8 [SCSI] target: Ad... |
174 |
} |
4cc987eaf target: Drop lun_... |
175 176 177 178 179 180 181 |
static void iblock_dev_call_rcu(struct rcu_head *p) { struct se_device *dev = container_of(p, struct se_device, rcu_head); struct iblock_dev *ib_dev = IBLOCK_DEV(dev); kfree(ib_dev); } |
0fd97ccf4 target: kill stru... |
182 |
static void iblock_free_device(struct se_device *dev) |
c66ac9db8 [SCSI] target: Ad... |
183 |
{ |
0fd97ccf4 target: kill stru... |
184 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); |
c66ac9db8 [SCSI] target: Ad... |
185 |
|
bc6655247 [SCSI] target/ibl... |
186 187 |
if (ib_dev->ibd_bd != NULL) blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); |
d84287bcf target/iblock: Fi... |
188 |
if (ib_dev->ibd_bio_set != NULL) |
bc6655247 [SCSI] target/ibl... |
189 |
bioset_free(ib_dev->ibd_bio_set); |
d84287bcf target/iblock: Fi... |
190 |
|
4cc987eaf target: Drop lun_... |
191 |
call_rcu(&dev->rcu_head, iblock_dev_call_rcu); |
c66ac9db8 [SCSI] target: Ad... |
192 |
} |
c66ac9db8 [SCSI] target: Ad... |
193 194 195 196 197 198 199 200 |
static unsigned long long iblock_emulate_read_cap_with_block_size( struct se_device *dev, struct block_device *bd, struct request_queue *q) { unsigned long long blocks_long = (div_u64(i_size_read(bd->bd_inode), bdev_logical_block_size(bd)) - 1); u32 block_size = bdev_logical_block_size(bd); |
0fd97ccf4 target: kill stru... |
201 |
if (block_size == dev->dev_attrib.block_size) |
c66ac9db8 [SCSI] target: Ad... |
202 203 204 205 |
return blocks_long; switch (block_size) { case 4096: |
0fd97ccf4 target: kill stru... |
206 |
switch (dev->dev_attrib.block_size) { |
c66ac9db8 [SCSI] target: Ad... |
207 208 209 210 211 212 213 214 215 216 217 218 219 |
case 2048: blocks_long <<= 1; break; case 1024: blocks_long <<= 2; break; case 512: blocks_long <<= 3; default: break; } break; case 2048: |
0fd97ccf4 target: kill stru... |
220 |
switch (dev->dev_attrib.block_size) { |
c66ac9db8 [SCSI] target: Ad... |
221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
case 4096: blocks_long >>= 1; break; case 1024: blocks_long <<= 1; break; case 512: blocks_long <<= 2; break; default: break; } break; case 1024: |
0fd97ccf4 target: kill stru... |
235 |
switch (dev->dev_attrib.block_size) { |
c66ac9db8 [SCSI] target: Ad... |
236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
case 4096: blocks_long >>= 2; break; case 2048: blocks_long >>= 1; break; case 512: blocks_long <<= 1; break; default: break; } break; case 512: |
0fd97ccf4 target: kill stru... |
250 |
switch (dev->dev_attrib.block_size) { |
c66ac9db8 [SCSI] target: Ad... |
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
case 4096: blocks_long >>= 3; break; case 2048: blocks_long >>= 2; break; case 1024: blocks_long >>= 1; break; default: break; } break; default: break; } return blocks_long; } |
3a41d85fe target/iblock: Fo... |
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
static void iblock_complete_cmd(struct se_cmd *cmd) { struct iblock_req *ibr = cmd->priv; u8 status; if (!atomic_dec_and_test(&ibr->pending)) return; if (atomic_read(&ibr->ib_bio_err_cnt)) status = SAM_STAT_CHECK_CONDITION; else status = SAM_STAT_GOOD; target_complete_cmd(cmd, status); kfree(ibr); } |
4246a0b63 block: add a bi_e... |
286 |
static void iblock_bio_done(struct bio *bio) |
3a41d85fe target/iblock: Fo... |
287 288 289 |
{ struct se_cmd *cmd = bio->bi_private; struct iblock_req *ibr = cmd->priv; |
4246a0b63 block: add a bi_e... |
290 291 292 |
if (bio->bi_error) { pr_err("bio error: %p, err: %d ", bio, bio->bi_error); |
3a41d85fe target/iblock: Fo... |
293 294 295 296 |
/* * Bump the ib_bio_err_cnt and release bio. */ atomic_inc(&ibr->ib_bio_err_cnt); |
4e857c58e arch: Mass conver... |
297 |
smp_mb__after_atomic(); |
3a41d85fe target/iblock: Fo... |
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
} bio_put(bio); iblock_complete_cmd(cmd); } static struct bio * iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) { struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); struct bio *bio; /* * Only allocate as many vector entries as the bio code allows us to, * we'll loop later on until we have handled the whole request. */ if (sg_num > BIO_MAX_PAGES) sg_num = BIO_MAX_PAGES; bio = bio_alloc_bioset(GFP_NOIO, sg_num, ib_dev->ibd_bio_set); if (!bio) { pr_err("Unable to allocate memory for bio "); return NULL; } bio->bi_bdev = ib_dev->ibd_bd; bio->bi_private = cmd; bio->bi_end_io = &iblock_bio_done; |
4f024f379 block: Abstract o... |
328 |
bio->bi_iter.bi_sector = lba; |
3a41d85fe target/iblock: Fo... |
329 330 331 332 333 334 335 336 337 338 339 340 341 342 |
return bio; } static void iblock_submit_bios(struct bio_list *list, int rw) { struct blk_plug plug; struct bio *bio; blk_start_plug(&plug); while ((bio = bio_list_pop(list))) submit_bio(rw, bio); blk_finish_plug(&plug); } |
4246a0b63 block: add a bi_e... |
343 |
static void iblock_end_io_flush(struct bio *bio) |
df5fa691c target: make iblo... |
344 345 |
{ struct se_cmd *cmd = bio->bi_private; |
4246a0b63 block: add a bi_e... |
346 347 348 |
if (bio->bi_error) pr_err("IBLOCK: cache flush failed: %d ", bio->bi_error); |
df5fa691c target: make iblo... |
349 |
|
5787cacd0 target: remove st... |
350 |
if (cmd) { |
4246a0b63 block: add a bi_e... |
351 |
if (bio->bi_error) |
5787cacd0 target: remove st... |
352 |
target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); |
de103c93a target: pass sens... |
353 |
else |
5787cacd0 target: remove st... |
354 |
target_complete_cmd(cmd, SAM_STAT_GOOD); |
5787cacd0 target: remove st... |
355 |
} |
df5fa691c target: make iblo... |
356 357 |
bio_put(bio); } |
c66ac9db8 [SCSI] target: Ad... |
358 |
/* |
df5fa691c target: make iblo... |
359 360 |
* Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must * always flush the whole cache. |
c66ac9db8 [SCSI] target: Ad... |
361 |
*/ |
de103c93a target: pass sens... |
362 363 |
static sense_reason_t iblock_execute_sync_cache(struct se_cmd *cmd) |
c66ac9db8 [SCSI] target: Ad... |
364 |
{ |
0fd97ccf4 target: kill stru... |
365 |
struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); |
a1d8b49ab target: Updates f... |
366 |
int immed = (cmd->t_task_cdb[1] & 0x2); |
df5fa691c target: make iblo... |
367 |
struct bio *bio; |
c66ac9db8 [SCSI] target: Ad... |
368 369 370 |
/* * If the Immediate bit is set, queue up the GOOD response |
df5fa691c target: make iblo... |
371 |
* for this SYNCHRONIZE_CACHE op. |
c66ac9db8 [SCSI] target: Ad... |
372 373 |
*/ if (immed) |
5787cacd0 target: remove st... |
374 |
target_complete_cmd(cmd, SAM_STAT_GOOD); |
c66ac9db8 [SCSI] target: Ad... |
375 |
|
df5fa691c target: make iblo... |
376 377 378 |
bio = bio_alloc(GFP_KERNEL, 0); bio->bi_end_io = iblock_end_io_flush; bio->bi_bdev = ib_dev->ibd_bd; |
c66ac9db8 [SCSI] target: Ad... |
379 |
if (!immed) |
df5fa691c target: make iblo... |
380 381 |
bio->bi_private = cmd; submit_bio(WRITE_FLUSH, bio); |
ad67f0d9e target: move sync... |
382 |
return 0; |
c66ac9db8 [SCSI] target: Ad... |
383 |
} |
de103c93a target: pass sens... |
384 |
static sense_reason_t |
62e469425 target: simplify ... |
385 |
iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) |
dbc21c5ab target/iblock: Ad... |
386 |
{ |
62e469425 target: simplify ... |
387 |
struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; |
8a9ebe717 target: Fix WRITE... |
388 |
struct se_device *dev = cmd->se_dev; |
dbc21c5ab target/iblock: Ad... |
389 |
int ret; |
8a9ebe717 target: Fix WRITE... |
390 391 392 393 |
ret = blkdev_issue_discard(bdev, target_to_linux_sector(dev, lba), target_to_linux_sector(dev, nolb), GFP_KERNEL, 0); |
dbc21c5ab target/iblock: Ad... |
394 395 396 397 398 399 400 401 402 403 |
if (ret < 0) { pr_err("blkdev_issue_discard() failed: %d ", ret); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } return 0; } static sense_reason_t |
07b631968 target/iblock: pa... |
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 |
iblock_execute_write_same_direct(struct block_device *bdev, struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; struct scatterlist *sg = &cmd->t_data_sg[0]; struct page *page = NULL; int ret; if (sg->offset) { page = alloc_page(GFP_KERNEL); if (!page) return TCM_OUT_OF_RESOURCES; sg_copy_to_buffer(sg, cmd->t_data_nents, page_address(page), dev->dev_attrib.block_size); } ret = blkdev_issue_write_same(bdev, target_to_linux_sector(dev, cmd->t_task_lba), target_to_linux_sector(dev, sbc_get_write_same_sectors(cmd)), GFP_KERNEL, page ? page : sg_page(sg)); if (page) __free_page(page); if (ret) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; target_complete_cmd(cmd, GOOD); return 0; } static sense_reason_t |
f6970ad31 target/iblock: Ad... |
434 435 |
iblock_execute_write_same(struct se_cmd *cmd) { |
07b631968 target/iblock: pa... |
436 |
struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; |
f6970ad31 target/iblock: Ad... |
437 438 439 440 |
struct iblock_req *ibr; struct scatterlist *sg; struct bio *bio; struct bio_list list; |
8a9ebe717 target: Fix WRITE... |
441 442 443 444 |
struct se_device *dev = cmd->se_dev; sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba); sector_t sectors = target_to_linux_sector(dev, sbc_get_write_same_sectors(cmd)); |
f6970ad31 target/iblock: Ad... |
445 |
|
afd73f1b6 target: Perform P... |
446 447 448 449 450 451 |
if (cmd->prot_op) { pr_err("WRITE_SAME: Protection information with IBLOCK" " backends not supported "); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } |
f6970ad31 target/iblock: Ad... |
452 453 454 455 456 457 458 459 460 461 |
sg = &cmd->t_data_sg[0]; if (cmd->t_data_nents > 1 || sg->length != cmd->se_dev->dev_attrib.block_size) { pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u" " block_size: %u ", cmd->t_data_nents, sg->length, cmd->se_dev->dev_attrib.block_size); return TCM_INVALID_CDB_FIELD; } |
07b631968 target/iblock: pa... |
462 463 |
if (bdev_write_same(bdev)) return iblock_execute_write_same_direct(bdev, cmd); |
f6970ad31 target/iblock: Ad... |
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 |
ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); if (!ibr) goto fail; cmd->priv = ibr; bio = iblock_get_bio(cmd, block_lba, 1); if (!bio) goto fail_free_ibr; bio_list_init(&list); bio_list_add(&list, bio); atomic_set(&ibr->pending, 1); while (sectors) { while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) != sg->length) { bio = iblock_get_bio(cmd, block_lba, 1); if (!bio) goto fail_put_bios; atomic_inc(&ibr->pending); bio_list_add(&list, bio); } /* Always in 512 byte units for Linux/Block */ block_lba += sg->length >> IBLOCK_LBA_SHIFT; sectors -= 1; } iblock_submit_bios(&list, WRITE); return 0; fail_put_bios: while ((bio = bio_list_pop(&list))) bio_put(bio); fail_free_ibr: kfree(ibr); fail: return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } |
c66ac9db8 [SCSI] target: Ad... |
506 |
enum { |
44bfd0185 target/iblock: Ad... |
507 |
Opt_udev_path, Opt_readonly, Opt_force, Opt_err |
c66ac9db8 [SCSI] target: Ad... |
508 509 510 511 |
}; static match_table_t tokens = { {Opt_udev_path, "udev_path=%s"}, |
44bfd0185 target/iblock: Ad... |
512 |
{Opt_readonly, "readonly=%d"}, |
c66ac9db8 [SCSI] target: Ad... |
513 514 515 |
{Opt_force, "force=%d"}, {Opt_err, NULL} }; |
0fd97ccf4 target: kill stru... |
516 517 |
static ssize_t iblock_set_configfs_dev_params(struct se_device *dev, const char *page, ssize_t count) |
c66ac9db8 [SCSI] target: Ad... |
518 |
{ |
0fd97ccf4 target: kill stru... |
519 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); |
6d1802539 [SCSI] target: Fi... |
520 |
char *orig, *ptr, *arg_p, *opts; |
c66ac9db8 [SCSI] target: Ad... |
521 |
substring_t args[MAX_OPT_ARGS]; |
21bca31c9 target/iblock: Re... |
522 |
int ret = 0, token; |
44bfd0185 target/iblock: Ad... |
523 |
unsigned long tmp_readonly; |
c66ac9db8 [SCSI] target: Ad... |
524 525 526 527 528 529 |
opts = kstrdup(page, GFP_KERNEL); if (!opts) return -ENOMEM; orig = opts; |
90c161b64 target: use \n as... |
530 531 |
while ((ptr = strsep(&opts, ", ")) != NULL) { |
c66ac9db8 [SCSI] target: Ad... |
532 533 534 535 536 537 538 |
if (!*ptr) continue; token = match_token(ptr, tokens, args); switch (token) { case Opt_udev_path: if (ib_dev->ibd_bd) { |
6708bb27b target: Follow up... |
539 |
pr_err("Unable to set udev_path= while" |
c66ac9db8 [SCSI] target: Ad... |
540 541 542 543 544 |
" ib_dev->ibd_bd exists "); ret = -EEXIST; goto out; } |
852b6ed11 target/iblock: Us... |
545 546 547 |
if (match_strlcpy(ib_dev->ibd_udev_path, &args[0], SE_UDEV_PATH_LEN) == 0) { ret = -EINVAL; |
6d1802539 [SCSI] target: Fi... |
548 549 |
break; } |
6708bb27b target: Follow up... |
550 551 |
pr_debug("IBLOCK: Referencing UDEV path: %s ", |
c66ac9db8 [SCSI] target: Ad... |
552 553 554 |
ib_dev->ibd_udev_path); ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; break; |
44bfd0185 target/iblock: Ad... |
555 556 557 558 559 560 |
case Opt_readonly: arg_p = match_strdup(&args[0]); if (!arg_p) { ret = -ENOMEM; break; } |
57103d7fe target: replace s... |
561 |
ret = kstrtoul(arg_p, 0, &tmp_readonly); |
44bfd0185 target/iblock: Ad... |
562 563 |
kfree(arg_p); if (ret < 0) { |
57103d7fe target: replace s... |
564 |
pr_err("kstrtoul() failed for" |
44bfd0185 target/iblock: Ad... |
565 566 567 568 569 570 571 572 |
" readonly= "); goto out; } ib_dev->ibd_readonly = tmp_readonly; pr_debug("IBLOCK: readonly: %d ", ib_dev->ibd_readonly); break; |
c66ac9db8 [SCSI] target: Ad... |
573 |
case Opt_force: |
c66ac9db8 [SCSI] target: Ad... |
574 575 576 577 578 579 580 581 582 583 |
break; default: break; } } out: kfree(orig); return (!ret) ? count : ret; } |
0fd97ccf4 target: kill stru... |
584 |
static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b) |
c66ac9db8 [SCSI] target: Ad... |
585 |
{ |
0fd97ccf4 target: kill stru... |
586 587 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct block_device *bd = ib_dev->ibd_bd; |
c66ac9db8 [SCSI] target: Ad... |
588 589 590 591 592 593 |
char buf[BDEVNAME_SIZE]; ssize_t bl = 0; if (bd) bl += sprintf(b + bl, "iBlock device: %s", bdevname(bd, buf)); |
0fd97ccf4 target: kill stru... |
594 |
if (ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH) |
44bfd0185 target/iblock: Ad... |
595 |
bl += sprintf(b + bl, " UDEV PATH: %s", |
0fd97ccf4 target: kill stru... |
596 597 598 |
ib_dev->ibd_udev_path); bl += sprintf(b + bl, " readonly: %d ", ib_dev->ibd_readonly); |
c66ac9db8 [SCSI] target: Ad... |
599 600 601 602 603 |
bl += sprintf(b + bl, " "); if (bd) { bl += sprintf(b + bl, "Major: %d Minor: %d %s ", |
21bca31c9 target/iblock: Re... |
604 |
MAJOR(bd->bd_dev), MINOR(bd->bd_dev), (!bd->bd_contains) ? |
0fd97ccf4 target: kill stru... |
605 |
"" : (bd->bd_holder == ib_dev) ? |
c66ac9db8 [SCSI] target: Ad... |
606 607 |
"CLAIMED: IBLOCK" : "CLAIMED: OS"); } else { |
21bca31c9 target/iblock: Re... |
608 609 |
bl += sprintf(b + bl, "Major: 0 Minor: 0 "); |
c66ac9db8 [SCSI] target: Ad... |
610 611 612 613 |
} return bl; } |
ecebbf6cc target/iblock: Ad... |
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 |
static int iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio) { struct se_device *dev = cmd->se_dev; struct blk_integrity *bi; struct bio_integrity_payload *bip; struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct scatterlist *sg; int i, rc; bi = bdev_get_integrity(ib_dev->ibd_bd); if (!bi) { pr_err("Unable to locate bio_integrity "); return -ENODEV; } bip = bio_integrity_alloc(bio, GFP_NOIO, cmd->t_prot_nents); |
06c1e3902 blk-integrity: em... |
632 |
if (IS_ERR(bip)) { |
ecebbf6cc target/iblock: Ad... |
633 634 |
pr_err("Unable to allocate bio_integrity_payload "); |
06c1e3902 blk-integrity: em... |
635 |
return PTR_ERR(bip); |
ecebbf6cc target/iblock: Ad... |
636 |
} |
4e13c5d02 Merge branch 'for... |
637 |
bip->bip_iter.bi_size = (cmd->data_length / dev->dev_attrib.block_size) * |
ecebbf6cc target/iblock: Ad... |
638 |
dev->prot_length; |
4e13c5d02 Merge branch 'for... |
639 |
bip->bip_iter.bi_sector = bio->bi_iter.bi_sector; |
ecebbf6cc target/iblock: Ad... |
640 |
|
4e13c5d02 Merge branch 'for... |
641 642 643 |
pr_debug("IBLOCK BIP Size: %u Sector: %llu ", bip->bip_iter.bi_size, (unsigned long long)bip->bip_iter.bi_sector); |
ecebbf6cc target/iblock: Ad... |
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 |
for_each_sg(cmd->t_prot_sg, sg, cmd->t_prot_nents, i) { rc = bio_integrity_add_page(bio, sg_page(sg), sg->length, sg->offset); if (rc != sg->length) { pr_err("bio_integrity_add_page() failed; %d ", rc); return -ENOMEM; } pr_debug("Added bio integrity page: %p length: %d offset; %d ", sg_page(sg), sg->length, sg->offset); } return 0; } |
de103c93a target: pass sens... |
662 |
static sense_reason_t |
a82a9538d target: Allow sbc... |
663 664 |
iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) |
c66ac9db8 [SCSI] target: Ad... |
665 |
{ |
5951146de target: More core... |
666 |
struct se_device *dev = cmd->se_dev; |
8a9ebe717 target: Fix WRITE... |
667 |
sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba); |
5787cacd0 target: remove st... |
668 |
struct iblock_req *ibr; |
ecebbf6cc target/iblock: Ad... |
669 |
struct bio *bio, *bio_start; |
dbbf3e94c target: cleanup i... |
670 |
struct bio_list list; |
c66ac9db8 [SCSI] target: Ad... |
671 |
struct scatterlist *sg; |
5787cacd0 target: remove st... |
672 |
u32 sg_num = sgl_nents; |
d5b4a21b3 target: increase ... |
673 |
unsigned bio_cnt; |
d0c8b259f target/iblock: Us... |
674 |
int rw = 0; |
5787cacd0 target: remove st... |
675 |
int i; |
dbbf3e94c target: cleanup i... |
676 |
|
5787cacd0 target: remove st... |
677 |
if (data_direction == DMA_TO_DEVICE) { |
d0c8b259f target/iblock: Us... |
678 679 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct request_queue *q = bdev_get_queue(ib_dev->ibd_bd); |
dbbf3e94c target: cleanup i... |
680 |
/* |
d0c8b259f target/iblock: Us... |
681 682 |
* Force writethrough using WRITE_FUA if a volatile write cache * is not enabled, or if initiator set the Force Unit Access bit. |
dbbf3e94c target: cleanup i... |
683 |
*/ |
d0c8b259f target/iblock: Us... |
684 685 686 687 688 |
if (q->flush_flags & REQ_FUA) { if (cmd->se_cmd_flags & SCF_FUA) rw = WRITE_FUA; else if (!(q->flush_flags & REQ_FLUSH)) rw = WRITE_FUA; |
d2bdbee0d target/iblock: Fi... |
689 690 |
else rw = WRITE; |
d0c8b259f target/iblock: Us... |
691 |
} else { |
dbbf3e94c target: cleanup i... |
692 |
rw = WRITE; |
d0c8b259f target/iblock: Us... |
693 |
} |
dbbf3e94c target: cleanup i... |
694 695 696 |
} else { rw = READ; } |
5787cacd0 target: remove st... |
697 698 699 700 |
ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); if (!ibr) goto fail; cmd->priv = ibr; |
e0de44573 target: do not su... |
701 702 703 704 705 |
if (!sgl_nents) { atomic_set(&ibr->pending, 1); iblock_complete_cmd(cmd); return 0; } |
5787cacd0 target: remove st... |
706 707 708 |
bio = iblock_get_bio(cmd, block_lba, sgl_nents); if (!bio) goto fail_free_ibr; |
dbbf3e94c target: cleanup i... |
709 |
|
ecebbf6cc target/iblock: Ad... |
710 |
bio_start = bio; |
dbbf3e94c target: cleanup i... |
711 712 |
bio_list_init(&list); bio_list_add(&list, bio); |
5787cacd0 target: remove st... |
713 714 |
atomic_set(&ibr->pending, 2); |
d5b4a21b3 target: increase ... |
715 |
bio_cnt = 1; |
c66ac9db8 [SCSI] target: Ad... |
716 |
|
5787cacd0 target: remove st... |
717 |
for_each_sg(sgl, sg, sgl_nents, i) { |
dbbf3e94c target: cleanup i... |
718 719 720 721 722 723 724 |
/* * XXX: if the length the device accepts is shorter than the * length of the S/G list entry this will cause and * endless loop. Better hope no driver uses huge pages. */ while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) != sg->length) { |
d5b4a21b3 target: increase ... |
725 726 727 728 |
if (bio_cnt >= IBLOCK_MAX_BIO_PER_TASK) { iblock_submit_bios(&list, rw); bio_cnt = 0; } |
5787cacd0 target: remove st... |
729 |
bio = iblock_get_bio(cmd, block_lba, sg_num); |
6708bb27b target: Follow up... |
730 |
if (!bio) |
5787cacd0 target: remove st... |
731 732 733 |
goto fail_put_bios; atomic_inc(&ibr->pending); |
dbbf3e94c target: cleanup i... |
734 |
bio_list_add(&list, bio); |
d5b4a21b3 target: increase ... |
735 |
bio_cnt++; |
c66ac9db8 [SCSI] target: Ad... |
736 |
} |
dbbf3e94c target: cleanup i... |
737 |
|
c66ac9db8 [SCSI] target: Ad... |
738 739 740 |
/* Always in 512 byte units for Linux/Block */ block_lba += sg->length >> IBLOCK_LBA_SHIFT; sg_num--; |
c66ac9db8 [SCSI] target: Ad... |
741 |
} |
6f16ec43e target/iblock: Ad... |
742 |
if (cmd->prot_type && dev->dev_attrib.pi_prot_type) { |
ecebbf6cc target/iblock: Ad... |
743 744 745 746 |
int rc = iblock_alloc_bip(cmd, bio_start); if (rc) goto fail_put_bios; } |
d5b4a21b3 target: increase ... |
747 |
iblock_submit_bios(&list, rw); |
5787cacd0 target: remove st... |
748 |
iblock_complete_cmd(cmd); |
03e98c9eb target: Address l... |
749 |
return 0; |
dbbf3e94c target: cleanup i... |
750 |
|
5787cacd0 target: remove st... |
751 |
fail_put_bios: |
dbbf3e94c target: cleanup i... |
752 |
while ((bio = bio_list_pop(&list))) |
c66ac9db8 [SCSI] target: Ad... |
753 |
bio_put(bio); |
5787cacd0 target: remove st... |
754 755 |
fail_free_ibr: kfree(ibr); |
5787cacd0 target: remove st... |
756 |
fail: |
de103c93a target: pass sens... |
757 |
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
c66ac9db8 [SCSI] target: Ad... |
758 |
} |
c66ac9db8 [SCSI] target: Ad... |
759 760 |
static sector_t iblock_get_blocks(struct se_device *dev) { |
0fd97ccf4 target: kill stru... |
761 762 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct block_device *bd = ib_dev->ibd_bd; |
c66ac9db8 [SCSI] target: Ad... |
763 764 765 766 |
struct request_queue *q = bdev_get_queue(bd); return iblock_emulate_read_cap_with_block_size(dev, bd, q); } |
7f7caf6aa target: Pass thro... |
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
static sector_t iblock_get_alignment_offset_lbas(struct se_device *dev) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct block_device *bd = ib_dev->ibd_bd; int ret; ret = bdev_alignment_offset(bd); if (ret == -1) return 0; /* convert offset-bytes to offset-lbas */ return ret / bdev_logical_block_size(bd); } static unsigned int iblock_get_lbppbe(struct se_device *dev) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct block_device *bd = ib_dev->ibd_bd; int logs_per_phys = bdev_physical_block_size(bd) / bdev_logical_block_size(bd); return ilog2(logs_per_phys); } static unsigned int iblock_get_io_min(struct se_device *dev) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct block_device *bd = ib_dev->ibd_bd; return bdev_io_min(bd); } static unsigned int iblock_get_io_opt(struct se_device *dev) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct block_device *bd = ib_dev->ibd_bd; return bdev_io_opt(bd); } |
9e999a6c5 target: rename sp... |
805 |
static struct sbc_ops iblock_sbc_ops = { |
0c2ad7d11 target: add struc... |
806 |
.execute_rw = iblock_execute_rw, |
ad67f0d9e target: move sync... |
807 |
.execute_sync_cache = iblock_execute_sync_cache, |
6f974e8ce target: move writ... |
808 |
.execute_write_same = iblock_execute_write_same, |
14150a6bb target: move unma... |
809 |
.execute_unmap = iblock_execute_unmap, |
0c2ad7d11 target: add struc... |
810 |
}; |
de103c93a target: pass sens... |
811 812 |
static sense_reason_t iblock_parse_cdb(struct se_cmd *cmd) |
0c2ad7d11 target: add struc... |
813 |
{ |
9e999a6c5 target: rename sp... |
814 |
return sbc_parse_cdb(cmd, &iblock_sbc_ops); |
0c2ad7d11 target: add struc... |
815 |
} |
452e20106 drivers: target: ... |
816 |
static bool iblock_get_write_cache(struct se_device *dev) |
d0c8b259f target/iblock: Us... |
817 818 819 820 821 822 823 |
{ struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct block_device *bd = ib_dev->ibd_bd; struct request_queue *q = bdev_get_queue(bd); return q->flush_flags & REQ_FLUSH; } |
0a06d4309 target: simplify ... |
824 |
static const struct target_backend_ops iblock_ops = { |
c66ac9db8 [SCSI] target: Ad... |
825 |
.name = "iblock", |
0fd97ccf4 target: kill stru... |
826 827 |
.inquiry_prod = "IBLOCK", .inquiry_rev = IBLOCK_VERSION, |
c66ac9db8 [SCSI] target: Ad... |
828 |
.owner = THIS_MODULE, |
c66ac9db8 [SCSI] target: Ad... |
829 830 |
.attach_hba = iblock_attach_hba, .detach_hba = iblock_detach_hba, |
0fd97ccf4 target: kill stru... |
831 832 |
.alloc_device = iblock_alloc_device, .configure_device = iblock_configure_device, |
c66ac9db8 [SCSI] target: Ad... |
833 |
.free_device = iblock_free_device, |
0c2ad7d11 target: add struc... |
834 |
.parse_cdb = iblock_parse_cdb, |
c66ac9db8 [SCSI] target: Ad... |
835 836 |
.set_configfs_dev_params = iblock_set_configfs_dev_params, .show_configfs_dev_params = iblock_show_configfs_dev_params, |
6f23ac8a3 target: provide g... |
837 |
.get_device_type = sbc_get_device_type, |
c66ac9db8 [SCSI] target: Ad... |
838 |
.get_blocks = iblock_get_blocks, |
7f7caf6aa target: Pass thro... |
839 840 841 842 |
.get_alignment_offset_lbas = iblock_get_alignment_offset_lbas, .get_lbppbe = iblock_get_lbppbe, .get_io_min = iblock_get_io_min, .get_io_opt = iblock_get_io_opt, |
d0c8b259f target/iblock: Us... |
843 |
.get_write_cache = iblock_get_write_cache, |
5873c4d15 target: consolida... |
844 |
.tb_dev_attrib_attrs = sbc_attrib_attrs, |
c66ac9db8 [SCSI] target: Ad... |
845 846 847 848 |
}; static int __init iblock_module_init(void) { |
0a06d4309 target: simplify ... |
849 |
return transport_backend_register(&iblock_ops); |
c66ac9db8 [SCSI] target: Ad... |
850 |
} |
63b91d5a4 target: Add __exi... |
851 |
static void __exit iblock_module_exit(void) |
c66ac9db8 [SCSI] target: Ad... |
852 |
{ |
0a06d4309 target: simplify ... |
853 |
target_backend_unregister(&iblock_ops); |
c66ac9db8 [SCSI] target: Ad... |
854 855 856 857 858 859 860 861 |
} MODULE_DESCRIPTION("TCM IBLOCK subsystem plugin"); MODULE_AUTHOR("nab@Linux-iSCSI.org"); MODULE_LICENSE("GPL"); module_init(iblock_module_init); module_exit(iblock_module_exit); |