Blame view
drivers/target/target_core_iblock.c
21.2 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> |
c66ac9db8 [SCSI] target: Ad... |
37 38 |
#include <scsi/scsi.h> #include <scsi/scsi_host.h> |
14150a6bb target: move unma... |
39 |
#include <asm/unaligned.h> |
c66ac9db8 [SCSI] target: Ad... |
40 41 |
#include <target/target_core_base.h> |
c4795fb20 target: header re... |
42 |
#include <target/target_core_backend.h> |
c66ac9db8 [SCSI] target: Ad... |
43 44 |
#include "target_core_iblock.h" |
d5b4a21b3 target: increase ... |
45 46 |
#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... |
47 48 49 50 |
static inline struct iblock_dev *IBLOCK_DEV(struct se_device *dev) { return container_of(dev, struct iblock_dev, dev); } |
c66ac9db8 [SCSI] target: Ad... |
51 |
static struct se_subsystem_api iblock_template; |
c66ac9db8 [SCSI] target: Ad... |
52 53 54 55 56 57 |
/* iblock_attach_hba(): (Part of se_subsystem_api_t template) * * */ static int iblock_attach_hba(struct se_hba *hba, u32 host_id) { |
6708bb27b target: Follow up... |
58 |
pr_debug("CORE_HBA[%d] - TCM iBlock HBA Driver %s on" |
c66ac9db8 [SCSI] target: Ad... |
59 60 61 |
" Generic Target Core Stack %s ", hba->hba_id, IBLOCK_VERSION, TARGET_CORE_MOD_VERSION); |
c66ac9db8 [SCSI] target: Ad... |
62 63 64 65 66 |
return 0; } static void iblock_detach_hba(struct se_hba *hba) { |
c66ac9db8 [SCSI] target: Ad... |
67 |
} |
0fd97ccf4 target: kill stru... |
68 |
static struct se_device *iblock_alloc_device(struct se_hba *hba, const char *name) |
c66ac9db8 [SCSI] target: Ad... |
69 70 |
{ struct iblock_dev *ib_dev = NULL; |
c66ac9db8 [SCSI] target: Ad... |
71 72 |
ib_dev = kzalloc(sizeof(struct iblock_dev), GFP_KERNEL); |
6708bb27b target: Follow up... |
73 74 75 |
if (!ib_dev) { pr_err("Unable to allocate struct iblock_dev "); |
c66ac9db8 [SCSI] target: Ad... |
76 77 |
return NULL; } |
c66ac9db8 [SCSI] target: Ad... |
78 |
|
6708bb27b target: Follow up... |
79 80 |
pr_debug( "IBLOCK: Allocated ib_dev for %s ", name); |
c66ac9db8 [SCSI] target: Ad... |
81 |
|
0fd97ccf4 target: kill stru... |
82 |
return &ib_dev->dev; |
c66ac9db8 [SCSI] target: Ad... |
83 |
} |
0fd97ccf4 target: kill stru... |
84 |
static int iblock_configure_device(struct se_device *dev) |
c66ac9db8 [SCSI] target: Ad... |
85 |
{ |
0fd97ccf4 target: kill stru... |
86 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); |
c66ac9db8 [SCSI] target: Ad... |
87 |
struct request_queue *q; |
0fd97ccf4 target: kill stru... |
88 |
struct block_device *bd = NULL; |
ecebbf6cc target/iblock: Ad... |
89 |
struct blk_integrity *bi; |
44bfd0185 target/iblock: Ad... |
90 |
fmode_t mode; |
0fd97ccf4 target: kill stru... |
91 |
int ret = -ENOMEM; |
c66ac9db8 [SCSI] target: Ad... |
92 |
|
0fd97ccf4 target: kill stru... |
93 94 95 96 |
if (!(ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH)) { pr_err("Missing udev_path= parameters for IBLOCK "); return -EINVAL; |
c66ac9db8 [SCSI] target: Ad... |
97 |
} |
d5b4a21b3 target: increase ... |
98 99 |
ib_dev->ibd_bio_set = bioset_create(IBLOCK_BIO_POOL_SIZE, 0); |
6708bb27b target: Follow up... |
100 |
if (!ib_dev->ibd_bio_set) { |
0fd97ccf4 target: kill stru... |
101 102 103 |
pr_err("IBLOCK: Unable to create bioset "); goto out; |
c66ac9db8 [SCSI] target: Ad... |
104 |
} |
0fd97ccf4 target: kill stru... |
105 |
|
6708bb27b target: Follow up... |
106 107 |
pr_debug( "IBLOCK: Claiming struct block_device: %s ", |
c66ac9db8 [SCSI] target: Ad... |
108 |
ib_dev->ibd_udev_path); |
44bfd0185 target/iblock: Ad... |
109 110 111 112 113 |
mode = FMODE_READ|FMODE_EXCL; if (!ib_dev->ibd_readonly) mode |= FMODE_WRITE; bd = blkdev_get_by_path(ib_dev->ibd_udev_path, mode, ib_dev); |
613640e4e [SCSI] target: Co... |
114 115 |
if (IS_ERR(bd)) { ret = PTR_ERR(bd); |
0fd97ccf4 target: kill stru... |
116 |
goto out_free_bioset; |
613640e4e [SCSI] target: Co... |
117 |
} |
c66ac9db8 [SCSI] target: Ad... |
118 |
ib_dev->ibd_bd = bd; |
0fd97ccf4 target: kill stru... |
119 120 121 |
q = bdev_get_queue(bd); dev->dev_attrib.hw_block_size = bdev_logical_block_size(bd); |
82bc9d04f target: Drop arbi... |
122 |
dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q); |
0fd97ccf4 target: kill stru... |
123 |
dev->dev_attrib.hw_queue_depth = q->nr_requests; |
c66ac9db8 [SCSI] target: Ad... |
124 |
|
c66ac9db8 [SCSI] target: Ad... |
125 126 127 128 129 |
/* * Check if the underlying struct block_device request_queue supports * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM * in ATA and we need to set TPE=1 */ |
613640e4e [SCSI] target: Co... |
130 |
if (blk_queue_discard(q)) { |
0fd97ccf4 target: kill stru... |
131 |
dev->dev_attrib.max_unmap_lba_count = |
c66ac9db8 [SCSI] target: Ad... |
132 |
q->limits.max_discard_sectors; |
0fd97ccf4 target: kill stru... |
133 |
|
c66ac9db8 [SCSI] target: Ad... |
134 135 136 |
/* * Currently hardcoded to 1 in Linux/SCSI code.. */ |
0fd97ccf4 target: kill stru... |
137 138 |
dev->dev_attrib.max_unmap_block_desc_count = 1; dev->dev_attrib.unmap_granularity = |
7347b5ff7 target: Fix ibloc... |
139 |
q->limits.discard_granularity >> 9; |
0fd97ccf4 target: kill stru... |
140 |
dev->dev_attrib.unmap_granularity_alignment = |
c66ac9db8 [SCSI] target: Ad... |
141 |
q->limits.discard_alignment; |
6708bb27b target: Follow up... |
142 |
pr_debug("IBLOCK: BLOCK Discard support available," |
c66ac9db8 [SCSI] target: Ad... |
143 144 145 |
" disabled by default "); } |
f6970ad31 target/iblock: Ad... |
146 147 148 149 150 |
/* * 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... |
151 |
|
e22a7f075 target: Implement... |
152 |
if (blk_queue_nonrot(q)) |
0fd97ccf4 target: kill stru... |
153 |
dev->dev_attrib.is_nonrot = 1; |
d0c8b259f target/iblock: Us... |
154 |
|
ecebbf6cc target/iblock: Ad... |
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
bi = bdev_get_integrity(bd); if (bi) { struct bio_set *bs = ib_dev->ibd_bio_set; if (!strcmp(bi->name, "T10-DIF-TYPE3-IP") || !strcmp(bi->name, "T10-DIF-TYPE1-IP")) { pr_err("IBLOCK export of blk_integrity: %s not" " supported ", bi->name); ret = -ENOSYS; goto out_blkdev_put; } if (!strcmp(bi->name, "T10-DIF-TYPE3-CRC")) { dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE3_PROT; } else if (!strcmp(bi->name, "T10-DIF-TYPE1-CRC")) { 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... |
187 |
return 0; |
c66ac9db8 [SCSI] target: Ad... |
188 |
|
ecebbf6cc target/iblock: Ad... |
189 190 |
out_blkdev_put: blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); |
0fd97ccf4 target: kill stru... |
191 192 193 194 195 |
out_free_bioset: bioset_free(ib_dev->ibd_bio_set); ib_dev->ibd_bio_set = NULL; out: return ret; |
c66ac9db8 [SCSI] target: Ad... |
196 |
} |
0fd97ccf4 target: kill stru... |
197 |
static void iblock_free_device(struct se_device *dev) |
c66ac9db8 [SCSI] target: Ad... |
198 |
{ |
0fd97ccf4 target: kill stru... |
199 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); |
c66ac9db8 [SCSI] target: Ad... |
200 |
|
bc6655247 [SCSI] target/ibl... |
201 202 |
if (ib_dev->ibd_bd != NULL) blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); |
d84287bcf target/iblock: Fi... |
203 |
if (ib_dev->ibd_bio_set != NULL) |
bc6655247 [SCSI] target/ibl... |
204 |
bioset_free(ib_dev->ibd_bio_set); |
d84287bcf target/iblock: Fi... |
205 |
|
c66ac9db8 [SCSI] target: Ad... |
206 207 |
kfree(ib_dev); } |
c66ac9db8 [SCSI] target: Ad... |
208 209 210 211 212 213 214 215 |
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... |
216 |
if (block_size == dev->dev_attrib.block_size) |
c66ac9db8 [SCSI] target: Ad... |
217 218 219 220 |
return blocks_long; switch (block_size) { case 4096: |
0fd97ccf4 target: kill stru... |
221 |
switch (dev->dev_attrib.block_size) { |
c66ac9db8 [SCSI] target: Ad... |
222 223 224 225 226 227 228 229 230 231 232 233 234 |
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... |
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 >>= 1; break; case 1024: blocks_long <<= 1; break; case 512: blocks_long <<= 2; break; default: break; } break; case 1024: |
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 |
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... |
265 |
switch (dev->dev_attrib.block_size) { |
c66ac9db8 [SCSI] target: Ad... |
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
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... |
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
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); } static void iblock_bio_done(struct bio *bio, int err) { struct se_cmd *cmd = bio->bi_private; struct iblock_req *ibr = cmd->priv; /* * Set -EIO if !BIO_UPTODATE and the passed is still err=0 */ if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err) err = -EIO; if (err != 0) { pr_err("test_bit(BIO_UPTODATE) failed for bio: %p," " err: %d ", bio, err); /* * Bump the ib_bio_err_cnt and release bio. */ atomic_inc(&ibr->ib_bio_err_cnt); |
4e857c58e arch: Mass conver... |
321 |
smp_mb__after_atomic(); |
3a41d85fe target/iblock: Fo... |
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
} 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... |
352 |
bio->bi_iter.bi_sector = lba; |
3a41d85fe target/iblock: Fo... |
353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
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); } |
df5fa691c target: make iblo... |
367 368 369 370 371 372 373 |
static void iblock_end_io_flush(struct bio *bio, int err) { struct se_cmd *cmd = bio->bi_private; if (err) pr_err("IBLOCK: cache flush failed: %d ", err); |
5787cacd0 target: remove st... |
374 |
if (cmd) { |
de103c93a target: pass sens... |
375 |
if (err) |
5787cacd0 target: remove st... |
376 |
target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); |
de103c93a target: pass sens... |
377 |
else |
5787cacd0 target: remove st... |
378 |
target_complete_cmd(cmd, SAM_STAT_GOOD); |
5787cacd0 target: remove st... |
379 |
} |
df5fa691c target: make iblo... |
380 381 |
bio_put(bio); } |
c66ac9db8 [SCSI] target: Ad... |
382 |
/* |
df5fa691c target: make iblo... |
383 384 |
* Implement SYCHRONIZE CACHE. Note that we can't handle lba ranges and must * always flush the whole cache. |
c66ac9db8 [SCSI] target: Ad... |
385 |
*/ |
de103c93a target: pass sens... |
386 387 |
static sense_reason_t iblock_execute_sync_cache(struct se_cmd *cmd) |
c66ac9db8 [SCSI] target: Ad... |
388 |
{ |
0fd97ccf4 target: kill stru... |
389 |
struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); |
a1d8b49ab target: Updates f... |
390 |
int immed = (cmd->t_task_cdb[1] & 0x2); |
df5fa691c target: make iblo... |
391 |
struct bio *bio; |
c66ac9db8 [SCSI] target: Ad... |
392 393 394 |
/* * If the Immediate bit is set, queue up the GOOD response |
df5fa691c target: make iblo... |
395 |
* for this SYNCHRONIZE_CACHE op. |
c66ac9db8 [SCSI] target: Ad... |
396 397 |
*/ if (immed) |
5787cacd0 target: remove st... |
398 |
target_complete_cmd(cmd, SAM_STAT_GOOD); |
c66ac9db8 [SCSI] target: Ad... |
399 |
|
df5fa691c target: make iblo... |
400 401 402 |
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... |
403 |
if (!immed) |
df5fa691c target: make iblo... |
404 405 |
bio->bi_private = cmd; submit_bio(WRITE_FLUSH, bio); |
ad67f0d9e target: move sync... |
406 |
return 0; |
c66ac9db8 [SCSI] target: Ad... |
407 |
} |
de103c93a target: pass sens... |
408 |
static sense_reason_t |
86d718298 target: Add sbc_e... |
409 |
iblock_do_unmap(struct se_cmd *cmd, void *priv, |
dbc21c5ab target/iblock: Ad... |
410 411 |
sector_t lba, sector_t nolb) { |
86d718298 target: Add sbc_e... |
412 |
struct block_device *bdev = priv; |
dbc21c5ab target/iblock: Ad... |
413 414 415 416 417 418 419 420 421 422 423 424 425 |
int ret; ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0); if (ret < 0) { pr_err("blkdev_issue_discard() failed: %d ", ret); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } return 0; } static sense_reason_t |
de103c93a target: pass sens... |
426 |
iblock_execute_unmap(struct se_cmd *cmd) |
c66ac9db8 [SCSI] target: Ad... |
427 |
{ |
86d718298 target: Add sbc_e... |
428 |
struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; |
c66ac9db8 [SCSI] target: Ad... |
429 |
|
86d718298 target: Add sbc_e... |
430 |
return sbc_execute_unmap(cmd, iblock_do_unmap, bdev); |
c66ac9db8 [SCSI] target: Ad... |
431 |
} |
de103c93a target: pass sens... |
432 |
static sense_reason_t |
f6970ad31 target/iblock: Ad... |
433 |
iblock_execute_write_same_unmap(struct se_cmd *cmd) |
6f974e8ce target: move writ... |
434 |
{ |
dbc21c5ab target/iblock: Ad... |
435 436 437 438 439 440 441 442 |
struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; sector_t lba = cmd->t_task_lba; sector_t nolb = sbc_get_write_same_sectors(cmd); int ret; ret = iblock_do_unmap(cmd, bdev, lba, nolb); if (ret) return ret; |
6f974e8ce target: move writ... |
443 444 445 446 |
target_complete_cmd(cmd, GOOD); return 0; } |
f6970ad31 target/iblock: Ad... |
447 448 449 450 451 452 453 454 |
static sense_reason_t iblock_execute_write_same(struct se_cmd *cmd) { struct iblock_req *ibr; struct scatterlist *sg; struct bio *bio; struct bio_list list; sector_t block_lba = cmd->t_task_lba; |
972b29c8f target: Rename sp... |
455 |
sector_t sectors = sbc_get_write_same_sectors(cmd); |
f6970ad31 target/iblock: Ad... |
456 457 458 459 460 461 462 463 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 506 507 508 509 |
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; } 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... |
510 |
enum { |
44bfd0185 target/iblock: Ad... |
511 |
Opt_udev_path, Opt_readonly, Opt_force, Opt_err |
c66ac9db8 [SCSI] target: Ad... |
512 513 514 515 |
}; static match_table_t tokens = { {Opt_udev_path, "udev_path=%s"}, |
44bfd0185 target/iblock: Ad... |
516 |
{Opt_readonly, "readonly=%d"}, |
c66ac9db8 [SCSI] target: Ad... |
517 518 519 |
{Opt_force, "force=%d"}, {Opt_err, NULL} }; |
0fd97ccf4 target: kill stru... |
520 521 |
static ssize_t iblock_set_configfs_dev_params(struct se_device *dev, const char *page, ssize_t count) |
c66ac9db8 [SCSI] target: Ad... |
522 |
{ |
0fd97ccf4 target: kill stru... |
523 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); |
6d1802539 [SCSI] target: Fi... |
524 |
char *orig, *ptr, *arg_p, *opts; |
c66ac9db8 [SCSI] target: Ad... |
525 |
substring_t args[MAX_OPT_ARGS]; |
21bca31c9 target/iblock: Re... |
526 |
int ret = 0, token; |
44bfd0185 target/iblock: Ad... |
527 |
unsigned long tmp_readonly; |
c66ac9db8 [SCSI] target: Ad... |
528 529 530 531 532 533 |
opts = kstrdup(page, GFP_KERNEL); if (!opts) return -ENOMEM; orig = opts; |
90c161b64 target: use \n as... |
534 535 |
while ((ptr = strsep(&opts, ", ")) != NULL) { |
c66ac9db8 [SCSI] target: Ad... |
536 537 538 539 540 541 542 |
if (!*ptr) continue; token = match_token(ptr, tokens, args); switch (token) { case Opt_udev_path: if (ib_dev->ibd_bd) { |
6708bb27b target: Follow up... |
543 |
pr_err("Unable to set udev_path= while" |
c66ac9db8 [SCSI] target: Ad... |
544 545 546 547 548 |
" ib_dev->ibd_bd exists "); ret = -EEXIST; goto out; } |
852b6ed11 target/iblock: Us... |
549 550 551 |
if (match_strlcpy(ib_dev->ibd_udev_path, &args[0], SE_UDEV_PATH_LEN) == 0) { ret = -EINVAL; |
6d1802539 [SCSI] target: Fi... |
552 553 |
break; } |
6708bb27b target: Follow up... |
554 555 |
pr_debug("IBLOCK: Referencing UDEV path: %s ", |
c66ac9db8 [SCSI] target: Ad... |
556 557 558 |
ib_dev->ibd_udev_path); ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; break; |
44bfd0185 target/iblock: Ad... |
559 560 561 562 563 564 |
case Opt_readonly: arg_p = match_strdup(&args[0]); if (!arg_p) { ret = -ENOMEM; break; } |
57103d7fe target: replace s... |
565 |
ret = kstrtoul(arg_p, 0, &tmp_readonly); |
44bfd0185 target/iblock: Ad... |
566 567 |
kfree(arg_p); if (ret < 0) { |
57103d7fe target: replace s... |
568 |
pr_err("kstrtoul() failed for" |
44bfd0185 target/iblock: Ad... |
569 570 571 572 573 574 575 576 |
" readonly= "); goto out; } ib_dev->ibd_readonly = tmp_readonly; pr_debug("IBLOCK: readonly: %d ", ib_dev->ibd_readonly); break; |
c66ac9db8 [SCSI] target: Ad... |
577 |
case Opt_force: |
c66ac9db8 [SCSI] target: Ad... |
578 579 580 581 582 583 584 585 586 587 |
break; default: break; } } out: kfree(orig); return (!ret) ? count : ret; } |
0fd97ccf4 target: kill stru... |
588 |
static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b) |
c66ac9db8 [SCSI] target: Ad... |
589 |
{ |
0fd97ccf4 target: kill stru... |
590 591 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct block_device *bd = ib_dev->ibd_bd; |
c66ac9db8 [SCSI] target: Ad... |
592 593 594 595 596 597 |
char buf[BDEVNAME_SIZE]; ssize_t bl = 0; if (bd) bl += sprintf(b + bl, "iBlock device: %s", bdevname(bd, buf)); |
0fd97ccf4 target: kill stru... |
598 |
if (ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH) |
44bfd0185 target/iblock: Ad... |
599 |
bl += sprintf(b + bl, " UDEV PATH: %s", |
0fd97ccf4 target: kill stru... |
600 601 602 |
ib_dev->ibd_udev_path); bl += sprintf(b + bl, " readonly: %d ", ib_dev->ibd_readonly); |
c66ac9db8 [SCSI] target: Ad... |
603 604 605 606 607 |
bl += sprintf(b + bl, " "); if (bd) { bl += sprintf(b + bl, "Major: %d Minor: %d %s ", |
21bca31c9 target/iblock: Re... |
608 |
MAJOR(bd->bd_dev), MINOR(bd->bd_dev), (!bd->bd_contains) ? |
0fd97ccf4 target: kill stru... |
609 |
"" : (bd->bd_holder == ib_dev) ? |
c66ac9db8 [SCSI] target: Ad... |
610 611 |
"CLAIMED: IBLOCK" : "CLAIMED: OS"); } else { |
21bca31c9 target/iblock: Re... |
612 613 |
bl += sprintf(b + bl, "Major: 0 Minor: 0 "); |
c66ac9db8 [SCSI] target: Ad... |
614 615 616 617 |
} return bl; } |
ecebbf6cc target/iblock: Ad... |
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 |
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); if (!bip) { pr_err("Unable to allocate bio_integrity_payload "); return -ENOMEM; } |
4e13c5d02 Merge branch 'for... |
641 |
bip->bip_iter.bi_size = (cmd->data_length / dev->dev_attrib.block_size) * |
ecebbf6cc target/iblock: Ad... |
642 |
dev->prot_length; |
4e13c5d02 Merge branch 'for... |
643 |
bip->bip_iter.bi_sector = bio->bi_iter.bi_sector; |
ecebbf6cc target/iblock: Ad... |
644 |
|
4e13c5d02 Merge branch 'for... |
645 646 647 |
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... |
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 |
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... |
666 |
static sense_reason_t |
a82a9538d target: Allow sbc... |
667 668 |
iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) |
c66ac9db8 [SCSI] target: Ad... |
669 |
{ |
5951146de target: More core... |
670 |
struct se_device *dev = cmd->se_dev; |
5787cacd0 target: remove st... |
671 |
struct iblock_req *ibr; |
ecebbf6cc target/iblock: Ad... |
672 |
struct bio *bio, *bio_start; |
dbbf3e94c target: cleanup i... |
673 |
struct bio_list list; |
c66ac9db8 [SCSI] target: Ad... |
674 |
struct scatterlist *sg; |
5787cacd0 target: remove st... |
675 |
u32 sg_num = sgl_nents; |
c66ac9db8 [SCSI] target: Ad... |
676 |
sector_t block_lba; |
d5b4a21b3 target: increase ... |
677 |
unsigned bio_cnt; |
d0c8b259f target/iblock: Us... |
678 |
int rw = 0; |
5787cacd0 target: remove st... |
679 |
int i; |
dbbf3e94c target: cleanup i... |
680 |
|
5787cacd0 target: remove st... |
681 |
if (data_direction == DMA_TO_DEVICE) { |
d0c8b259f target/iblock: Us... |
682 683 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct request_queue *q = bdev_get_queue(ib_dev->ibd_bd); |
dbbf3e94c target: cleanup i... |
684 |
/* |
d0c8b259f target/iblock: Us... |
685 686 |
* 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... |
687 |
*/ |
d0c8b259f target/iblock: Us... |
688 689 690 691 692 |
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... |
693 694 |
else rw = WRITE; |
d0c8b259f target/iblock: Us... |
695 |
} else { |
dbbf3e94c target: cleanup i... |
696 |
rw = WRITE; |
d0c8b259f target/iblock: Us... |
697 |
} |
dbbf3e94c target: cleanup i... |
698 699 700 |
} else { rw = READ; } |
c66ac9db8 [SCSI] target: Ad... |
701 |
/* |
5787cacd0 target: remove st... |
702 703 |
* Convert the blocksize advertised to the initiator to the 512 byte * units unconditionally used by the Linux block layer. |
c66ac9db8 [SCSI] target: Ad... |
704 |
*/ |
0fd97ccf4 target: kill stru... |
705 |
if (dev->dev_attrib.block_size == 4096) |
72a0e5e2e target: remove th... |
706 |
block_lba = (cmd->t_task_lba << 3); |
0fd97ccf4 target: kill stru... |
707 |
else if (dev->dev_attrib.block_size == 2048) |
72a0e5e2e target: remove th... |
708 |
block_lba = (cmd->t_task_lba << 2); |
0fd97ccf4 target: kill stru... |
709 |
else if (dev->dev_attrib.block_size == 1024) |
72a0e5e2e target: remove th... |
710 |
block_lba = (cmd->t_task_lba << 1); |
0fd97ccf4 target: kill stru... |
711 |
else if (dev->dev_attrib.block_size == 512) |
72a0e5e2e target: remove th... |
712 |
block_lba = cmd->t_task_lba; |
c66ac9db8 [SCSI] target: Ad... |
713 |
else { |
6708bb27b target: Follow up... |
714 |
pr_err("Unsupported SCSI -> BLOCK LBA conversion:" |
0fd97ccf4 target: kill stru... |
715 716 |
" %u ", dev->dev_attrib.block_size); |
de103c93a target: pass sens... |
717 |
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
c66ac9db8 [SCSI] target: Ad... |
718 |
} |
5787cacd0 target: remove st... |
719 720 721 722 |
ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); if (!ibr) goto fail; cmd->priv = ibr; |
e0de44573 target: do not su... |
723 724 725 726 727 |
if (!sgl_nents) { atomic_set(&ibr->pending, 1); iblock_complete_cmd(cmd); return 0; } |
5787cacd0 target: remove st... |
728 729 730 |
bio = iblock_get_bio(cmd, block_lba, sgl_nents); if (!bio) goto fail_free_ibr; |
dbbf3e94c target: cleanup i... |
731 |
|
ecebbf6cc target/iblock: Ad... |
732 |
bio_start = bio; |
dbbf3e94c target: cleanup i... |
733 734 |
bio_list_init(&list); bio_list_add(&list, bio); |
5787cacd0 target: remove st... |
735 736 |
atomic_set(&ibr->pending, 2); |
d5b4a21b3 target: increase ... |
737 |
bio_cnt = 1; |
c66ac9db8 [SCSI] target: Ad... |
738 |
|
5787cacd0 target: remove st... |
739 |
for_each_sg(sgl, sg, sgl_nents, i) { |
dbbf3e94c target: cleanup i... |
740 741 742 743 744 745 746 |
/* * 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 ... |
747 748 749 750 |
if (bio_cnt >= IBLOCK_MAX_BIO_PER_TASK) { iblock_submit_bios(&list, rw); bio_cnt = 0; } |
5787cacd0 target: remove st... |
751 |
bio = iblock_get_bio(cmd, block_lba, sg_num); |
6708bb27b target: Follow up... |
752 |
if (!bio) |
5787cacd0 target: remove st... |
753 754 755 |
goto fail_put_bios; atomic_inc(&ibr->pending); |
dbbf3e94c target: cleanup i... |
756 |
bio_list_add(&list, bio); |
d5b4a21b3 target: increase ... |
757 |
bio_cnt++; |
c66ac9db8 [SCSI] target: Ad... |
758 |
} |
dbbf3e94c target: cleanup i... |
759 |
|
c66ac9db8 [SCSI] target: Ad... |
760 761 762 |
/* Always in 512 byte units for Linux/Block */ block_lba += sg->length >> IBLOCK_LBA_SHIFT; sg_num--; |
c66ac9db8 [SCSI] target: Ad... |
763 |
} |
ecebbf6cc target/iblock: Ad... |
764 765 766 767 768 |
if (cmd->prot_type) { int rc = iblock_alloc_bip(cmd, bio_start); if (rc) goto fail_put_bios; } |
d5b4a21b3 target: increase ... |
769 |
iblock_submit_bios(&list, rw); |
5787cacd0 target: remove st... |
770 |
iblock_complete_cmd(cmd); |
03e98c9eb target: Address l... |
771 |
return 0; |
dbbf3e94c target: cleanup i... |
772 |
|
5787cacd0 target: remove st... |
773 |
fail_put_bios: |
dbbf3e94c target: cleanup i... |
774 |
while ((bio = bio_list_pop(&list))) |
c66ac9db8 [SCSI] target: Ad... |
775 |
bio_put(bio); |
5787cacd0 target: remove st... |
776 777 |
fail_free_ibr: kfree(ibr); |
5787cacd0 target: remove st... |
778 |
fail: |
de103c93a target: pass sens... |
779 |
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
c66ac9db8 [SCSI] target: Ad... |
780 |
} |
c66ac9db8 [SCSI] target: Ad... |
781 782 |
static sector_t iblock_get_blocks(struct se_device *dev) { |
0fd97ccf4 target: kill stru... |
783 784 |
struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct block_device *bd = ib_dev->ibd_bd; |
c66ac9db8 [SCSI] target: Ad... |
785 786 787 788 |
struct request_queue *q = bdev_get_queue(bd); return iblock_emulate_read_cap_with_block_size(dev, bd, q); } |
7f7caf6aa target: Pass thro... |
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 |
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... |
827 |
static struct sbc_ops iblock_sbc_ops = { |
0c2ad7d11 target: add struc... |
828 |
.execute_rw = iblock_execute_rw, |
ad67f0d9e target: move sync... |
829 |
.execute_sync_cache = iblock_execute_sync_cache, |
6f974e8ce target: move writ... |
830 |
.execute_write_same = iblock_execute_write_same, |
f6970ad31 target/iblock: Ad... |
831 |
.execute_write_same_unmap = iblock_execute_write_same_unmap, |
14150a6bb target: move unma... |
832 |
.execute_unmap = iblock_execute_unmap, |
0c2ad7d11 target: add struc... |
833 |
}; |
de103c93a target: pass sens... |
834 835 |
static sense_reason_t iblock_parse_cdb(struct se_cmd *cmd) |
0c2ad7d11 target: add struc... |
836 |
{ |
9e999a6c5 target: rename sp... |
837 |
return sbc_parse_cdb(cmd, &iblock_sbc_ops); |
0c2ad7d11 target: add struc... |
838 |
} |
452e20106 drivers: target: ... |
839 |
static bool iblock_get_write_cache(struct se_device *dev) |
d0c8b259f target/iblock: Us... |
840 841 842 843 844 845 846 |
{ 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; } |
c66ac9db8 [SCSI] target: Ad... |
847 848 |
static struct se_subsystem_api iblock_template = { .name = "iblock", |
0fd97ccf4 target: kill stru... |
849 850 |
.inquiry_prod = "IBLOCK", .inquiry_rev = IBLOCK_VERSION, |
c66ac9db8 [SCSI] target: Ad... |
851 852 |
.owner = THIS_MODULE, .transport_type = TRANSPORT_PLUGIN_VHBA_PDEV, |
c66ac9db8 [SCSI] target: Ad... |
853 854 |
.attach_hba = iblock_attach_hba, .detach_hba = iblock_detach_hba, |
0fd97ccf4 target: kill stru... |
855 856 |
.alloc_device = iblock_alloc_device, .configure_device = iblock_configure_device, |
c66ac9db8 [SCSI] target: Ad... |
857 |
.free_device = iblock_free_device, |
0c2ad7d11 target: add struc... |
858 |
.parse_cdb = iblock_parse_cdb, |
c66ac9db8 [SCSI] target: Ad... |
859 860 |
.set_configfs_dev_params = iblock_set_configfs_dev_params, .show_configfs_dev_params = iblock_show_configfs_dev_params, |
6f23ac8a3 target: provide g... |
861 |
.get_device_type = sbc_get_device_type, |
c66ac9db8 [SCSI] target: Ad... |
862 |
.get_blocks = iblock_get_blocks, |
7f7caf6aa target: Pass thro... |
863 864 865 866 |
.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... |
867 |
.get_write_cache = iblock_get_write_cache, |
c66ac9db8 [SCSI] target: Ad... |
868 869 870 871 872 873 |
}; static int __init iblock_module_init(void) { return transport_subsystem_register(&iblock_template); } |
63b91d5a4 target: Add __exi... |
874 |
static void __exit iblock_module_exit(void) |
c66ac9db8 [SCSI] target: Ad... |
875 876 877 878 879 880 881 882 883 884 |
{ transport_subsystem_release(&iblock_template); } 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); |