sd_zbc.c (5f832a395859de7191e638e3777ae57f37d46d08) sd_zbc.c (e76239a3748c90a8b0e197f8f4544a8ce52f126e)
1/*
2 * SCSI Zoned Block commands
3 *
4 * Copyright (C) 2014-2015 SUSE Linux GmbH
5 * Written by: Hannes Reinecke <hare@suse.de>
6 * Modified by: Damien Le Moal <damien.lemoal@hgst.com>
7 * Modified by: Shaun Tancheff <shaun.tancheff@seagate.com>
8 *

--- 48 unchanged lines hidden (view full) ---

57 zone->start = logical_to_sectors(sdp, get_unaligned_be64(&buf[16]));
58 zone->wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24]));
59 if (zone->type != ZBC_ZONE_TYPE_CONV &&
60 zone->cond == ZBC_ZONE_COND_FULL)
61 zone->wp = zone->start + zone->len;
62}
63
64/**
1/*
2 * SCSI Zoned Block commands
3 *
4 * Copyright (C) 2014-2015 SUSE Linux GmbH
5 * Written by: Hannes Reinecke <hare@suse.de>
6 * Modified by: Damien Le Moal <damien.lemoal@hgst.com>
7 * Modified by: Shaun Tancheff <shaun.tancheff@seagate.com>
8 *

--- 48 unchanged lines hidden (view full) ---

57 zone->start = logical_to_sectors(sdp, get_unaligned_be64(&buf[16]));
58 zone->wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24]));
59 if (zone->type != ZBC_ZONE_TYPE_CONV &&
60 zone->cond == ZBC_ZONE_COND_FULL)
61 zone->wp = zone->start + zone->len;
62}
63
64/**
65 * sd_zbc_report_zones - Issue a REPORT ZONES scsi command.
65 * sd_zbc_do_report_zones - Issue a REPORT ZONES scsi command.
66 * @sdkp: The target disk
67 * @buf: Buffer to use for the reply
68 * @buflen: the buffer size
69 * @lba: Start LBA of the report
70 * @partial: Do partial report
71 *
72 * For internal use during device validation.
73 * Using partial=true can significantly speed up execution of a report zones
74 * command because the disk does not have to count all possible report matching
75 * zones and will only report the count of zones fitting in the command reply
76 * buffer.
77 */
66 * @sdkp: The target disk
67 * @buf: Buffer to use for the reply
68 * @buflen: the buffer size
69 * @lba: Start LBA of the report
70 * @partial: Do partial report
71 *
72 * For internal use during device validation.
73 * Using partial=true can significantly speed up execution of a report zones
74 * command because the disk does not have to count all possible report matching
75 * zones and will only report the count of zones fitting in the command reply
76 * buffer.
77 */
78static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
79 unsigned int buflen, sector_t lba,
80 bool partial)
78static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
79 unsigned int buflen, sector_t lba,
80 bool partial)
81{
82 struct scsi_device *sdp = sdkp->device;
83 const int timeout = sdp->request_queue->rq_timeout;
84 struct scsi_sense_hdr sshdr;
85 unsigned char cmd[16];
86 unsigned int rep_len;
87 int result;
88

--- 24 unchanged lines hidden (view full) ---

113 rep_len);
114 return -EIO;
115 }
116
117 return 0;
118}
119
120/**
81{
82 struct scsi_device *sdp = sdkp->device;
83 const int timeout = sdp->request_queue->rq_timeout;
84 struct scsi_sense_hdr sshdr;
85 unsigned char cmd[16];
86 unsigned int rep_len;
87 int result;
88

--- 24 unchanged lines hidden (view full) ---

113 rep_len);
114 return -EIO;
115 }
116
117 return 0;
118}
119
120/**
121 * sd_zbc_setup_report_cmnd - Prepare a REPORT ZONES scsi command
122 * @cmd: The command to setup
121 * sd_zbc_report_zones - Disk report zones operation.
122 * @disk: The target disk
123 * @sector: Start 512B sector of the report
124 * @zones: Array of zone descriptors
125 * @nr_zones: Number of descriptors in the array
126 * @gfp_mask: Memory allocation mask
123 *
127 *
124 * Call in sd_init_command() for a REQ_OP_ZONE_REPORT request.
128 * Execute a report zones command on the target disk.
125 */
129 */
126int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd)
130int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
131 struct blk_zone *zones, unsigned int *nr_zones,
132 gfp_t gfp_mask)
127{
133{
128 struct request *rq = cmd->request;
129 struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
130 sector_t lba, sector = blk_rq_pos(rq);
131 unsigned int nr_bytes = blk_rq_bytes(rq);
132 int ret;
134 struct scsi_disk *sdkp = scsi_disk(disk);
135 unsigned int i, buflen, nrz = *nr_zones;
136 unsigned char *buf;
137 size_t offset = 0;
138 int ret = 0;
133
139
134 WARN_ON(nr_bytes == 0);
135
136 if (!sd_is_zoned(sdkp))
137 /* Not a zoned device */
140 if (!sd_is_zoned(sdkp))
141 /* Not a zoned device */
138 return BLKPREP_KILL;
142 return -EOPNOTSUPP;
139
143
140 ret = scsi_init_io(cmd);
141 if (ret != BLKPREP_OK)
142 return ret;
144 /*
145 * Get a reply buffer for the number of requested zones plus a header.
146 * For ATA, buffers must be aligned to 512B.
147 */
148 buflen = roundup((nrz + 1) * 64, 512);
149 buf = kmalloc(buflen, gfp_mask);
150 if (!buf)
151 return -ENOMEM;
143
152
144 cmd->cmd_len = 16;
145 memset(cmd->cmnd, 0, cmd->cmd_len);
146 cmd->cmnd[0] = ZBC_IN;
147 cmd->cmnd[1] = ZI_REPORT_ZONES;
148 lba = sectors_to_logical(sdkp->device, sector);
149 put_unaligned_be64(lba, &cmd->cmnd[2]);
150 put_unaligned_be32(nr_bytes, &cmd->cmnd[10]);
151 /* Do partial report for speeding things up */
152 cmd->cmnd[14] = ZBC_REPORT_ZONE_PARTIAL;
153 ret = sd_zbc_do_report_zones(sdkp, buf, buflen,
154 sectors_to_logical(sdkp->device, sector), true);
155 if (ret)
156 goto out_free_buf;
153
157
154 cmd->sc_data_direction = DMA_FROM_DEVICE;
155 cmd->sdb.length = nr_bytes;
156 cmd->transfersize = sdkp->device->sector_size;
157 cmd->allowed = 0;
158 nrz = min(nrz, get_unaligned_be32(&buf[0]) / 64);
159 for (i = 0; i < nrz; i++) {
160 offset += 64;
161 sd_zbc_parse_report(sdkp, buf + offset, zones);
162 zones++;
163 }
158
164
159 return BLKPREP_OK;
160}
165 *nr_zones = nrz;
161
166
162/**
163 * sd_zbc_report_zones_complete - Process a REPORT ZONES scsi command reply.
164 * @scmd: The completed report zones command
165 * @good_bytes: reply size in bytes
166 *
167 * Convert all reported zone descriptors to struct blk_zone. The conversion
168 * is done in-place, directly in the request specified sg buffer.
169 */
170static void sd_zbc_report_zones_complete(struct scsi_cmnd *scmd,
171 unsigned int good_bytes)
172{
173 struct request *rq = scmd->request;
174 struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
175 struct sg_mapping_iter miter;
176 struct blk_zone_report_hdr hdr;
177 struct blk_zone zone;
178 unsigned int offset, bytes = 0;
179 unsigned long flags;
180 u8 *buf;
167out_free_buf:
168 kfree(buf);
181
169
182 if (good_bytes < 64)
183 return;
184
185 memset(&hdr, 0, sizeof(struct blk_zone_report_hdr));
186
187 sg_miter_start(&miter, scsi_sglist(scmd), scsi_sg_count(scmd),
188 SG_MITER_TO_SG | SG_MITER_ATOMIC);
189
190 local_irq_save(flags);
191 while (sg_miter_next(&miter) && bytes < good_bytes) {
192
193 buf = miter.addr;
194 offset = 0;
195
196 if (bytes == 0) {
197 /* Set the report header */
198 hdr.nr_zones = min_t(unsigned int,
199 (good_bytes - 64) / 64,
200 get_unaligned_be32(&buf[0]) / 64);
201 memcpy(buf, &hdr, sizeof(struct blk_zone_report_hdr));
202 offset += 64;
203 bytes += 64;
204 }
205
206 /* Parse zone descriptors */
207 while (offset < miter.length && hdr.nr_zones) {
208 WARN_ON(offset > miter.length);
209 buf = miter.addr + offset;
210 sd_zbc_parse_report(sdkp, buf, &zone);
211 memcpy(buf, &zone, sizeof(struct blk_zone));
212 offset += 64;
213 bytes += 64;
214 hdr.nr_zones--;
215 }
216
217 if (!hdr.nr_zones)
218 break;
219
220 }
221 sg_miter_stop(&miter);
222 local_irq_restore(flags);
170 return ret;
223}
224
225/**
226 * sd_zbc_zone_sectors - Get the device zone size in number of 512B sectors.
227 * @sdkp: The target disk
228 */
229static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp)
230{

--- 66 unchanged lines hidden (view full) ---

297 */
298 rq->rq_flags |= RQF_QUIET;
299 break;
300
301 case REQ_OP_WRITE:
302 case REQ_OP_WRITE_ZEROES:
303 case REQ_OP_WRITE_SAME:
304 break;
171}
172
173/**
174 * sd_zbc_zone_sectors - Get the device zone size in number of 512B sectors.
175 * @sdkp: The target disk
176 */
177static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp)
178{

--- 66 unchanged lines hidden (view full) ---

245 */
246 rq->rq_flags |= RQF_QUIET;
247 break;
248
249 case REQ_OP_WRITE:
250 case REQ_OP_WRITE_ZEROES:
251 case REQ_OP_WRITE_SAME:
252 break;
305
306 case REQ_OP_ZONE_REPORT:
307
308 if (!result)
309 sd_zbc_report_zones_complete(cmd, good_bytes);
310 break;
311
312 }
313}
314
315/**
316 * sd_zbc_check_zoned_characteristics - Check zoned block device characteristics
317 * @sdkp: Target disk
318 * @buf: Buffer where to store the VPD page data
319 *

--- 65 unchanged lines hidden (view full) ---

385 u8 same;
386
387 /* Get a buffer */
388 buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL);
389 if (!buf)
390 return -ENOMEM;
391
392 /* Do a report zone to get max_lba and the same field */
253 }
254}
255
256/**
257 * sd_zbc_check_zoned_characteristics - Check zoned block device characteristics
258 * @sdkp: Target disk
259 * @buf: Buffer where to store the VPD page data
260 *

--- 65 unchanged lines hidden (view full) ---

326 u8 same;
327
328 /* Get a buffer */
329 buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL);
330 if (!buf)
331 return -ENOMEM;
332
333 /* Do a report zone to get max_lba and the same field */
393 ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false);
334 ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false);
394 if (ret)
395 goto out_free;
396
397 if (sdkp->rc_basis == 0) {
398 /* The max_lba field is the capacity of this device */
399 max_lba = get_unaligned_be64(&buf[8]);
400 if (sdkp->capacity != max_lba + 1) {
401 if (sdkp->first_scan)

--- 40 unchanged lines hidden (view full) ---

442 zone_blocks = 0;
443 goto out;
444 }
445 block += this_zone_blocks;
446 rec += 64;
447 }
448
449 if (block < sdkp->capacity) {
335 if (ret)
336 goto out_free;
337
338 if (sdkp->rc_basis == 0) {
339 /* The max_lba field is the capacity of this device */
340 max_lba = get_unaligned_be64(&buf[8]);
341 if (sdkp->capacity != max_lba + 1) {
342 if (sdkp->first_scan)

--- 40 unchanged lines hidden (view full) ---

383 zone_blocks = 0;
384 goto out;
385 }
386 block += this_zone_blocks;
387 rec += 64;
388 }
389
390 if (block < sdkp->capacity) {
450 ret = sd_zbc_report_zones(sdkp, buf,
451 SD_ZBC_BUF_SIZE, block, true);
391 ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
392 block, true);
452 if (ret)
453 goto out_free;
454 }
455
456 } while (block < sdkp->capacity);
457
458out:
459 if (!zone_blocks) {

--- 100 unchanged lines hidden (view full) ---

560 if (!seq_zones_bitmap)
561 return ERR_PTR(-ENOMEM);
562
563 buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL);
564 if (!buf)
565 goto out;
566
567 while (lba < sdkp->capacity) {
393 if (ret)
394 goto out_free;
395 }
396
397 } while (block < sdkp->capacity);
398
399out:
400 if (!zone_blocks) {

--- 100 unchanged lines hidden (view full) ---

501 if (!seq_zones_bitmap)
502 return ERR_PTR(-ENOMEM);
503
504 buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL);
505 if (!buf)
506 goto out;
507
508 while (lba < sdkp->capacity) {
568 ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
569 lba, true);
509 ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, lba,
510 true);
570 if (ret)
571 goto out;
572 lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
573 zone_shift, seq_zones_bitmap);
574 }
575
576 if (lba != sdkp->capacity) {
577 /* Something went wrong */

--- 152 unchanged lines hidden ---
511 if (ret)
512 goto out;
513 lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
514 zone_shift, seq_zones_bitmap);
515 }
516
517 if (lba != sdkp->capacity) {
518 /* Something went wrong */

--- 152 unchanged lines hidden ---