diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2010-09-10 14:50:10 -0400 |
---|---|---|
committer | Jens Axboe <axboe@carl.home.kernel.dk> | 2010-09-10 14:50:10 -0400 |
commit | 13f05c8d8e98bbdce89158bfdb2e380940695a88 (patch) | |
tree | 055215e7e2b1bdc684ead64daa61b30b35eaa3c5 /include | |
parent | c8bf1336824ebd698d37b71763e1c43190f2229a (diff) |
block/scsi: Provide a limit on the number of integrity segments
Some controllers have a hardware limit on the number of protection
information scatter-gather list segments they can handle.
Introduce a max_integrity_segments limit in the block layer and provide
a new scsi_host_template setting that allows HBA drivers to provide a
value suitable for the hardware.
Add support for honoring the integrity segment limit when merging both
bios and requests.
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jens Axboe <axboe@carl.home.kernel.dk>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/bio.h | 4 | ||||
-rw-r--r-- | include/linux/blkdev.h | 33 | ||||
-rw-r--r-- | include/scsi/scsi.h | 6 | ||||
-rw-r--r-- | include/scsi/scsi_host.h | 7 |
4 files changed, 46 insertions, 4 deletions
diff --git a/include/linux/bio.h b/include/linux/bio.h index 5274103434a..2c3fd742160 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h | |||
@@ -496,6 +496,10 @@ static inline struct bio *bio_list_get(struct bio_list *bl) | |||
496 | #define bip_for_each_vec(bvl, bip, i) \ | 496 | #define bip_for_each_vec(bvl, bip, i) \ |
497 | __bip_for_each_vec(bvl, bip, i, (bip)->bip_idx) | 497 | __bip_for_each_vec(bvl, bip, i, (bip)->bip_idx) |
498 | 498 | ||
499 | #define bio_for_each_integrity_vec(_bvl, _bio, _iter) \ | ||
500 | for_each_bio(_bio) \ | ||
501 | bip_for_each_vec(_bvl, _bio->bi_integrity, _iter) | ||
502 | |||
499 | #define bio_integrity(bio) (bio->bi_integrity != NULL) | 503 | #define bio_integrity(bio) (bio->bi_integrity != NULL) |
500 | 504 | ||
501 | extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *); | 505 | extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *); |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2c54906f678..7e661106270 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -124,6 +124,9 @@ struct request { | |||
124 | * physical address coalescing is performed. | 124 | * physical address coalescing is performed. |
125 | */ | 125 | */ |
126 | unsigned short nr_phys_segments; | 126 | unsigned short nr_phys_segments; |
127 | #if defined(CONFIG_BLK_DEV_INTEGRITY) | ||
128 | unsigned short nr_integrity_segments; | ||
129 | #endif | ||
127 | 130 | ||
128 | unsigned short ioprio; | 131 | unsigned short ioprio; |
129 | 132 | ||
@@ -243,6 +246,7 @@ struct queue_limits { | |||
243 | 246 | ||
244 | unsigned short logical_block_size; | 247 | unsigned short logical_block_size; |
245 | unsigned short max_segments; | 248 | unsigned short max_segments; |
249 | unsigned short max_integrity_segments; | ||
246 | 250 | ||
247 | unsigned char misaligned; | 251 | unsigned char misaligned; |
248 | unsigned char discard_misaligned; | 252 | unsigned char discard_misaligned; |
@@ -1213,8 +1217,13 @@ struct blk_integrity { | |||
1213 | extern int blk_integrity_register(struct gendisk *, struct blk_integrity *); | 1217 | extern int blk_integrity_register(struct gendisk *, struct blk_integrity *); |
1214 | extern void blk_integrity_unregister(struct gendisk *); | 1218 | extern void blk_integrity_unregister(struct gendisk *); |
1215 | extern int blk_integrity_compare(struct gendisk *, struct gendisk *); | 1219 | extern int blk_integrity_compare(struct gendisk *, struct gendisk *); |
1216 | extern int blk_rq_map_integrity_sg(struct request *, struct scatterlist *); | 1220 | extern int blk_rq_map_integrity_sg(struct request_queue *, struct bio *, |
1217 | extern int blk_rq_count_integrity_sg(struct request *); | 1221 | struct scatterlist *); |
1222 | extern int blk_rq_count_integrity_sg(struct request_queue *, struct bio *); | ||
1223 | extern int blk_integrity_merge_rq(struct request_queue *, struct request *, | ||
1224 | struct request *); | ||
1225 | extern int blk_integrity_merge_bio(struct request_queue *, struct request *, | ||
1226 | struct bio *); | ||
1218 | 1227 | ||
1219 | static inline | 1228 | static inline |
1220 | struct blk_integrity *bdev_get_integrity(struct block_device *bdev) | 1229 | struct blk_integrity *bdev_get_integrity(struct block_device *bdev) |
@@ -1235,16 +1244,32 @@ static inline int blk_integrity_rq(struct request *rq) | |||
1235 | return bio_integrity(rq->bio); | 1244 | return bio_integrity(rq->bio); |
1236 | } | 1245 | } |
1237 | 1246 | ||
1247 | static inline void blk_queue_max_integrity_segments(struct request_queue *q, | ||
1248 | unsigned int segs) | ||
1249 | { | ||
1250 | q->limits.max_integrity_segments = segs; | ||
1251 | } | ||
1252 | |||
1253 | static inline unsigned short | ||
1254 | queue_max_integrity_segments(struct request_queue *q) | ||
1255 | { | ||
1256 | return q->limits.max_integrity_segments; | ||
1257 | } | ||
1258 | |||
1238 | #else /* CONFIG_BLK_DEV_INTEGRITY */ | 1259 | #else /* CONFIG_BLK_DEV_INTEGRITY */ |
1239 | 1260 | ||
1240 | #define blk_integrity_rq(rq) (0) | 1261 | #define blk_integrity_rq(rq) (0) |
1241 | #define blk_rq_count_integrity_sg(a) (0) | 1262 | #define blk_rq_count_integrity_sg(a, b) (0) |
1242 | #define blk_rq_map_integrity_sg(a, b) (0) | 1263 | #define blk_rq_map_integrity_sg(a, b, c) (0) |
1243 | #define bdev_get_integrity(a) (0) | 1264 | #define bdev_get_integrity(a) (0) |
1244 | #define blk_get_integrity(a) (0) | 1265 | #define blk_get_integrity(a) (0) |
1245 | #define blk_integrity_compare(a, b) (0) | 1266 | #define blk_integrity_compare(a, b) (0) |
1246 | #define blk_integrity_register(a, b) (0) | 1267 | #define blk_integrity_register(a, b) (0) |
1247 | #define blk_integrity_unregister(a) do { } while (0); | 1268 | #define blk_integrity_unregister(a) do { } while (0); |
1269 | #define blk_queue_max_integrity_segments(a, b) do { } while (0); | ||
1270 | #define queue_max_integrity_segments(a) (0) | ||
1271 | #define blk_integrity_merge_rq(a, b, c) (0) | ||
1272 | #define blk_integrity_merge_bio(a, b, c) (0) | ||
1248 | 1273 | ||
1249 | #endif /* CONFIG_BLK_DEV_INTEGRITY */ | 1274 | #endif /* CONFIG_BLK_DEV_INTEGRITY */ |
1250 | 1275 | ||
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 8fcb6e0e9e7..d63533a4a59 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h | |||
@@ -32,6 +32,12 @@ struct scsi_cmnd; | |||
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | /* | 34 | /* |
35 | * DIX-capable adapters effectively support infinite chaining for the | ||
36 | * protection information scatterlist | ||
37 | */ | ||
38 | #define SCSI_MAX_PROT_SG_SEGMENTS 0xFFFF | ||
39 | |||
40 | /* | ||
35 | * Special value for scanning to specify scanning or rescanning of all | 41 | * Special value for scanning to specify scanning or rescanning of all |
36 | * possible channels, (target) ids, or luns on a given shost. | 42 | * possible channels, (target) ids, or luns on a given shost. |
37 | */ | 43 | */ |
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index b7bdecb7b76..d0a6a845f20 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h | |||
@@ -388,6 +388,7 @@ struct scsi_host_template { | |||
388 | * of scatter-gather. | 388 | * of scatter-gather. |
389 | */ | 389 | */ |
390 | unsigned short sg_tablesize; | 390 | unsigned short sg_tablesize; |
391 | unsigned short sg_prot_tablesize; | ||
391 | 392 | ||
392 | /* | 393 | /* |
393 | * Set this if the host adapter has limitations beside segment count. | 394 | * Set this if the host adapter has limitations beside segment count. |
@@ -599,6 +600,7 @@ struct Scsi_Host { | |||
599 | int can_queue; | 600 | int can_queue; |
600 | short cmd_per_lun; | 601 | short cmd_per_lun; |
601 | short unsigned int sg_tablesize; | 602 | short unsigned int sg_tablesize; |
603 | short unsigned int sg_prot_tablesize; | ||
602 | short unsigned int max_sectors; | 604 | short unsigned int max_sectors; |
603 | unsigned long dma_boundary; | 605 | unsigned long dma_boundary; |
604 | /* | 606 | /* |
@@ -823,6 +825,11 @@ static inline unsigned int scsi_host_get_prot(struct Scsi_Host *shost) | |||
823 | return shost->prot_capabilities; | 825 | return shost->prot_capabilities; |
824 | } | 826 | } |
825 | 827 | ||
828 | static inline int scsi_host_prot_dma(struct Scsi_Host *shost) | ||
829 | { | ||
830 | return shost->prot_capabilities >= SHOST_DIX_TYPE0_PROTECTION; | ||
831 | } | ||
832 | |||
826 | static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsigned int target_type) | 833 | static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsigned int target_type) |
827 | { | 834 | { |
828 | static unsigned char cap[] = { 0, | 835 | static unsigned char cap[] = { 0, |