diff options
Diffstat (limited to 'drivers/scsi/sd_zbc.c')
| -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 | } |
