diff options
-rw-r--r-- | drivers/scsi/sd_zbc.c | 104 |
1 files changed, 75 insertions, 29 deletions
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index ec3764c8f3f1..db16c19e05c4 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c | |||
@@ -9,6 +9,8 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/blkdev.h> | 11 | #include <linux/blkdev.h> |
12 | #include <linux/vmalloc.h> | ||
13 | #include <linux/sched/mm.h> | ||
12 | 14 | ||
13 | #include <asm/unaligned.h> | 15 | #include <asm/unaligned.h> |
14 | 16 | ||
@@ -50,7 +52,7 @@ static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf, | |||
50 | /** | 52 | /** |
51 | * sd_zbc_do_report_zones - Issue a REPORT ZONES scsi command. | 53 | * sd_zbc_do_report_zones - Issue a REPORT ZONES scsi command. |
52 | * @sdkp: The target disk | 54 | * @sdkp: The target disk |
53 | * @buf: Buffer to use for the reply | 55 | * @buf: vmalloc-ed buffer to use for the reply |
54 | * @buflen: the buffer size | 56 | * @buflen: the buffer size |
55 | * @lba: Start LBA of the report | 57 | * @lba: Start LBA of the report |
56 | * @partial: Do partial report | 58 | * @partial: Do partial report |
@@ -79,7 +81,6 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf, | |||
79 | put_unaligned_be32(buflen, &cmd[10]); | 81 | put_unaligned_be32(buflen, &cmd[10]); |
80 | if (partial) | 82 | if (partial) |
81 | cmd[14] = ZBC_REPORT_ZONE_PARTIAL; | 83 | cmd[14] = ZBC_REPORT_ZONE_PARTIAL; |
82 | memset(buf, 0, buflen); | ||
83 | 84 | ||
84 | result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, | 85 | result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, |
85 | buf, buflen, &sshdr, | 86 | buf, buflen, &sshdr, |
@@ -103,6 +104,53 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf, | |||
103 | return 0; | 104 | return 0; |
104 | } | 105 | } |
105 | 106 | ||
107 | /* | ||
108 | * Maximum number of zones to get with one report zones command. | ||
109 | */ | ||
110 | #define SD_ZBC_REPORT_MAX_ZONES 8192U | ||
111 | |||
112 | /** | ||
113 | * Allocate a buffer for report zones reply. | ||
114 | * @sdkp: The target disk | ||
115 | * @nr_zones: Maximum number of zones to report | ||
116 | * @buflen: Size of the buffer allocated | ||
117 | * | ||
118 | * Try to allocate a reply buffer for the number of requested zones. | ||
119 | * The size of the buffer allocated may be smaller than requested to | ||
120 | * satify the device constraint (max_hw_sectors, max_segments, etc). | ||
121 | * | ||
122 | * Return the address of the allocated buffer and update @buflen with | ||
123 | * the size of the allocated buffer. | ||
124 | */ | ||
125 | static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, | ||
126 | unsigned int nr_zones, size_t *buflen) | ||
127 | { | ||
128 | struct request_queue *q = sdkp->disk->queue; | ||
129 | size_t bufsize; | ||
130 | void *buf; | ||
131 | |||
132 | /* | ||
133 | * Report zone buffer size should be at most 64B times the number of | ||
134 | * zones requested plus the 64B reply header, but should be at least | ||
135 | * SECTOR_SIZE for ATA devices. | ||
136 | * Make sure that this size does not exceed the hardware capabilities. | ||
137 | * Furthermore, since the report zone command cannot be split, make | ||
138 | * sure that the allocated buffer can always be mapped by limiting the | ||
139 | * number of pages allocated to the HBA max segments limit. | ||
140 | */ | ||
141 | nr_zones = min(nr_zones, SD_ZBC_REPORT_MAX_ZONES); | ||
142 | bufsize = roundup((nr_zones + 1) * 64, 512); | ||
143 | bufsize = min_t(size_t, bufsize, | ||
144 | queue_max_hw_sectors(q) << SECTOR_SHIFT); | ||
145 | bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT); | ||
146 | |||
147 | buf = vzalloc(bufsize); | ||
148 | if (buf) | ||
149 | *buflen = bufsize; | ||
150 | |||
151 | return buf; | ||
152 | } | ||
153 | |||
106 | /** | 154 | /** |
107 | * sd_zbc_report_zones - Disk report zones operation. | 155 | * sd_zbc_report_zones - Disk report zones operation. |
108 | * @disk: The target disk | 156 | * @disk: The target disk |
@@ -116,30 +164,23 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, | |||
116 | struct blk_zone *zones, unsigned int *nr_zones) | 164 | struct blk_zone *zones, unsigned int *nr_zones) |
117 | { | 165 | { |
118 | struct scsi_disk *sdkp = scsi_disk(disk); | 166 | struct scsi_disk *sdkp = scsi_disk(disk); |
119 | unsigned int i, buflen, nrz = *nr_zones; | 167 | unsigned int i, nrz = *nr_zones; |
120 | unsigned char *buf; | 168 | unsigned char *buf; |
121 | size_t offset = 0; | 169 | size_t buflen = 0, offset = 0; |
122 | int ret = 0; | 170 | int ret = 0; |
123 | 171 | ||
124 | if (!sd_is_zoned(sdkp)) | 172 | if (!sd_is_zoned(sdkp)) |
125 | /* Not a zoned device */ | 173 | /* Not a zoned device */ |
126 | return -EOPNOTSUPP; | 174 | return -EOPNOTSUPP; |
127 | 175 | ||
128 | /* | 176 | buf = sd_zbc_alloc_report_buffer(sdkp, nrz, &buflen); |
129 | * Get a reply buffer for the number of requested zones plus a header, | ||
130 | * without exceeding the device maximum command size. For ATA disks, | ||
131 | * buffers must be aligned to 512B. | ||
132 | */ | ||
133 | buflen = min(queue_max_hw_sectors(disk->queue) << 9, | ||
134 | roundup((nrz + 1) * 64, 512)); | ||
135 | buf = kmalloc(buflen, GFP_KERNEL); | ||
136 | if (!buf) | 177 | if (!buf) |
137 | return -ENOMEM; | 178 | return -ENOMEM; |
138 | 179 | ||
139 | ret = sd_zbc_do_report_zones(sdkp, buf, buflen, | 180 | ret = sd_zbc_do_report_zones(sdkp, buf, buflen, |
140 | sectors_to_logical(sdkp->device, sector), true); | 181 | sectors_to_logical(sdkp->device, sector), true); |
141 | if (ret) | 182 | if (ret) |
142 | goto out_free_buf; | 183 | goto out; |
143 | 184 | ||
144 | nrz = min(nrz, get_unaligned_be32(&buf[0]) / 64); | 185 | nrz = min(nrz, get_unaligned_be32(&buf[0]) / 64); |
145 | for (i = 0; i < nrz; i++) { | 186 | for (i = 0; i < nrz; i++) { |
@@ -150,8 +191,8 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, | |||
150 | 191 | ||
151 | *nr_zones = nrz; | 192 | *nr_zones = nrz; |
152 | 193 | ||
153 | out_free_buf: | 194 | out: |
154 | kfree(buf); | 195 | kvfree(buf); |
155 | 196 | ||
156 | return ret; | 197 | return ret; |
157 | } | 198 | } |
@@ -285,8 +326,6 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, | |||
285 | return 0; | 326 | return 0; |
286 | } | 327 | } |
287 | 328 | ||
288 | #define SD_ZBC_BUF_SIZE 131072U | ||
289 | |||
290 | /** | 329 | /** |
291 | * sd_zbc_check_zones - Check the device capacity and zone sizes | 330 | * sd_zbc_check_zones - Check the device capacity and zone sizes |
292 | * @sdkp: Target disk | 331 | * @sdkp: Target disk |
@@ -302,22 +341,28 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, | |||
302 | */ | 341 | */ |
303 | static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) | 342 | static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) |
304 | { | 343 | { |
344 | size_t bufsize, buflen; | ||
345 | unsigned int noio_flag; | ||
305 | u64 zone_blocks = 0; | 346 | u64 zone_blocks = 0; |
306 | sector_t max_lba, block = 0; | 347 | sector_t max_lba, block = 0; |
307 | unsigned char *buf; | 348 | unsigned char *buf; |
308 | unsigned char *rec; | 349 | unsigned char *rec; |
309 | unsigned int buf_len; | ||
310 | unsigned int list_length; | ||
311 | int ret; | 350 | int ret; |
312 | u8 same; | 351 | u8 same; |
313 | 352 | ||
353 | /* Do all memory allocations as if GFP_NOIO was specified */ | ||
354 | noio_flag = memalloc_noio_save(); | ||
355 | |||
314 | /* Get a buffer */ | 356 | /* Get a buffer */ |
315 | buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); | 357 | buf = sd_zbc_alloc_report_buffer(sdkp, SD_ZBC_REPORT_MAX_ZONES, |
316 | if (!buf) | 358 | &bufsize); |
317 | return -ENOMEM; | 359 | if (!buf) { |
360 | ret = -ENOMEM; | ||
361 | goto out; | ||
362 | } | ||
318 | 363 | ||
319 | /* Do a report zone to get max_lba and the same field */ | 364 | /* Do a report zone to get max_lba and the same field */ |
320 | ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false); | 365 | ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, 0, false); |
321 | if (ret) | 366 | if (ret) |
322 | goto out_free; | 367 | goto out_free; |
323 | 368 | ||
@@ -353,12 +398,12 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) | |||
353 | do { | 398 | do { |
354 | 399 | ||
355 | /* Parse REPORT ZONES header */ | 400 | /* Parse REPORT ZONES header */ |
356 | list_length = get_unaligned_be32(&buf[0]) + 64; | 401 | buflen = min_t(size_t, get_unaligned_be32(&buf[0]) + 64, |
402 | bufsize); | ||
357 | rec = buf + 64; | 403 | rec = buf + 64; |
358 | buf_len = min(list_length, SD_ZBC_BUF_SIZE); | ||
359 | 404 | ||
360 | /* Parse zone descriptors */ | 405 | /* Parse zone descriptors */ |
361 | while (rec < buf + buf_len) { | 406 | while (rec < buf + buflen) { |
362 | u64 this_zone_blocks = get_unaligned_be64(&rec[8]); | 407 | u64 this_zone_blocks = get_unaligned_be64(&rec[8]); |
363 | 408 | ||
364 | if (zone_blocks == 0) { | 409 | if (zone_blocks == 0) { |
@@ -374,8 +419,8 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) | |||
374 | } | 419 | } |
375 | 420 | ||
376 | if (block < sdkp->capacity) { | 421 | if (block < sdkp->capacity) { |
377 | ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, | 422 | ret = sd_zbc_do_report_zones(sdkp, buf, bufsize, block, |
378 | block, true); | 423 | true); |
379 | if (ret) | 424 | if (ret) |
380 | goto out_free; | 425 | goto out_free; |
381 | } | 426 | } |
@@ -406,7 +451,8 @@ out: | |||
406 | } | 451 | } |
407 | 452 | ||
408 | out_free: | 453 | out_free: |
409 | kfree(buf); | 454 | memalloc_noio_restore(noio_flag); |
455 | kvfree(buf); | ||
410 | 456 | ||
411 | return ret; | 457 | return ret; |
412 | } | 458 | } |