Commit | Line | Data |
---|---|---|
89d94756 HR |
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 | * | |
9 | * This program is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU General Public License version | |
11 | * 2 as published by the Free Software Foundation. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; see the file COPYING. If not, write to | |
20 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, | |
21 | * USA. | |
22 | * | |
23 | */ | |
24 | ||
25 | #include <linux/blkdev.h> | |
26 | ||
27 | #include <asm/unaligned.h> | |
28 | ||
29 | #include <scsi/scsi.h> | |
30 | #include <scsi/scsi_cmnd.h> | |
89d94756 HR |
31 | |
32 | #include "sd.h" | |
89d94756 HR |
33 | |
34 | /** | |
e98f42bc DLM |
35 | * sd_zbc_parse_report - Convert a zone descriptor to a struct blk_zone, |
36 | * @sdkp: The disk the report originated from | |
37 | * @buf: Address of the report zone descriptor | |
38 | * @zone: the destination zone structure | |
39 | * | |
40 | * All LBA sized values are converted to 512B sectors unit. | |
89d94756 | 41 | */ |
e98f42bc | 42 | static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf, |
89d94756 HR |
43 | struct blk_zone *zone) |
44 | { | |
45 | struct scsi_device *sdp = sdkp->device; | |
46 | ||
47 | memset(zone, 0, sizeof(struct blk_zone)); | |
48 | ||
49 | zone->type = buf[0] & 0x0f; | |
50 | zone->cond = (buf[1] >> 4) & 0xf; | |
51 | if (buf[1] & 0x01) | |
52 | zone->reset = 1; | |
53 | if (buf[1] & 0x02) | |
54 | zone->non_seq = 1; | |
55 | ||
56 | zone->len = logical_to_sectors(sdp, get_unaligned_be64(&buf[8])); | |
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 | /** | |
e98f42bc DLM |
65 | * sd_zbc_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 | * | |
71 | * For internal use during device validation. | |
89d94756 HR |
72 | */ |
73 | static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf, | |
74 | unsigned int buflen, sector_t lba) | |
75 | { | |
76 | struct scsi_device *sdp = sdkp->device; | |
77 | const int timeout = sdp->request_queue->rq_timeout; | |
78 | struct scsi_sense_hdr sshdr; | |
79 | unsigned char cmd[16]; | |
80 | unsigned int rep_len; | |
81 | int result; | |
82 | ||
83 | memset(cmd, 0, 16); | |
84 | cmd[0] = ZBC_IN; | |
85 | cmd[1] = ZI_REPORT_ZONES; | |
86 | put_unaligned_be64(lba, &cmd[2]); | |
87 | put_unaligned_be32(buflen, &cmd[10]); | |
88 | memset(buf, 0, buflen); | |
89 | ||
90 | result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, | |
91 | buf, buflen, &sshdr, | |
92 | timeout, SD_MAX_RETRIES, NULL); | |
93 | if (result) { | |
94 | sd_printk(KERN_ERR, sdkp, | |
95 | "REPORT ZONES lba %llu failed with %d/%d\n", | |
96 | (unsigned long long)lba, | |
97 | host_byte(result), driver_byte(result)); | |
98 | return -EIO; | |
99 | } | |
100 | ||
101 | rep_len = get_unaligned_be32(&buf[0]); | |
102 | if (rep_len < 64) { | |
103 | sd_printk(KERN_ERR, sdkp, | |
104 | "REPORT ZONES report invalid length %u\n", | |
105 | rep_len); | |
106 | return -EIO; | |
107 | } | |
108 | ||
109 | return 0; | |
110 | } | |
111 | ||
e98f42bc DLM |
112 | /** |
113 | * sd_zbc_setup_report_cmnd - Prepare a REPORT ZONES scsi command | |
114 | * @cmd: The command to setup | |
115 | * | |
116 | * Call in sd_init_command() for a REQ_OP_ZONE_REPORT request. | |
117 | */ | |
89d94756 HR |
118 | int sd_zbc_setup_report_cmnd(struct scsi_cmnd *cmd) |
119 | { | |
120 | struct request *rq = cmd->request; | |
121 | struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); | |
122 | sector_t lba, sector = blk_rq_pos(rq); | |
123 | unsigned int nr_bytes = blk_rq_bytes(rq); | |
124 | int ret; | |
125 | ||
126 | WARN_ON(nr_bytes == 0); | |
127 | ||
128 | if (!sd_is_zoned(sdkp)) | |
129 | /* Not a zoned device */ | |
130 | return BLKPREP_KILL; | |
131 | ||
132 | ret = scsi_init_io(cmd); | |
133 | if (ret != BLKPREP_OK) | |
134 | return ret; | |
135 | ||
136 | cmd->cmd_len = 16; | |
137 | memset(cmd->cmnd, 0, cmd->cmd_len); | |
138 | cmd->cmnd[0] = ZBC_IN; | |
139 | cmd->cmnd[1] = ZI_REPORT_ZONES; | |
140 | lba = sectors_to_logical(sdkp->device, sector); | |
141 | put_unaligned_be64(lba, &cmd->cmnd[2]); | |
142 | put_unaligned_be32(nr_bytes, &cmd->cmnd[10]); | |
143 | /* Do partial report for speeding things up */ | |
144 | cmd->cmnd[14] = ZBC_REPORT_ZONE_PARTIAL; | |
145 | ||
146 | cmd->sc_data_direction = DMA_FROM_DEVICE; | |
147 | cmd->sdb.length = nr_bytes; | |
148 | cmd->transfersize = sdkp->device->sector_size; | |
149 | cmd->allowed = 0; | |
150 | ||
151 | /* | |
152 | * Report may return less bytes than requested. Make sure | |
153 | * to report completion on the entire initial request. | |
154 | */ | |
155 | rq->__data_len = nr_bytes; | |
156 | ||
157 | return BLKPREP_OK; | |
158 | } | |
159 | ||
e98f42bc DLM |
160 | /** |
161 | * sd_zbc_report_zones_complete - Process a REPORT ZONES scsi command reply. | |
162 | * @scmd: The completed report zones command | |
163 | * @good_bytes: reply size in bytes | |
164 | * | |
165 | * Convert all reported zone descriptors to struct blk_zone. The conversion | |
166 | * is done in-place, directly in the request specified sg buffer. | |
167 | */ | |
89d94756 HR |
168 | static void sd_zbc_report_zones_complete(struct scsi_cmnd *scmd, |
169 | unsigned int good_bytes) | |
170 | { | |
171 | struct request *rq = scmd->request; | |
172 | struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); | |
173 | struct sg_mapping_iter miter; | |
174 | struct blk_zone_report_hdr hdr; | |
175 | struct blk_zone zone; | |
176 | unsigned int offset, bytes = 0; | |
177 | unsigned long flags; | |
178 | u8 *buf; | |
179 | ||
180 | if (good_bytes < 64) | |
181 | return; | |
182 | ||
183 | memset(&hdr, 0, sizeof(struct blk_zone_report_hdr)); | |
184 | ||
185 | sg_miter_start(&miter, scsi_sglist(scmd), scsi_sg_count(scmd), | |
186 | SG_MITER_TO_SG | SG_MITER_ATOMIC); | |
187 | ||
188 | local_irq_save(flags); | |
189 | while (sg_miter_next(&miter) && bytes < good_bytes) { | |
190 | ||
191 | buf = miter.addr; | |
192 | offset = 0; | |
193 | ||
194 | if (bytes == 0) { | |
195 | /* Set the report header */ | |
196 | hdr.nr_zones = min_t(unsigned int, | |
197 | (good_bytes - 64) / 64, | |
198 | get_unaligned_be32(&buf[0]) / 64); | |
199 | memcpy(buf, &hdr, sizeof(struct blk_zone_report_hdr)); | |
200 | offset += 64; | |
201 | bytes += 64; | |
202 | } | |
203 | ||
204 | /* Parse zone descriptors */ | |
205 | while (offset < miter.length && hdr.nr_zones) { | |
206 | WARN_ON(offset > miter.length); | |
207 | buf = miter.addr + offset; | |
208 | sd_zbc_parse_report(sdkp, buf, &zone); | |
209 | memcpy(buf, &zone, sizeof(struct blk_zone)); | |
210 | offset += 64; | |
211 | bytes += 64; | |
212 | hdr.nr_zones--; | |
213 | } | |
214 | ||
215 | if (!hdr.nr_zones) | |
216 | break; | |
217 | ||
218 | } | |
219 | sg_miter_stop(&miter); | |
220 | local_irq_restore(flags); | |
221 | } | |
222 | ||
e98f42bc DLM |
223 | /** |
224 | * sd_zbc_zone_sectors - Get the device zone size in number of 512B sectors. | |
225 | * @sdkp: The target disk | |
226 | */ | |
89d94756 HR |
227 | static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp) |
228 | { | |
229 | return logical_to_sectors(sdkp->device, sdkp->zone_blocks); | |
230 | } | |
231 | ||
e98f42bc DLM |
232 | /** |
233 | * sd_zbc_setup_reset_cmnd - Prepare a RESET WRITE POINTER scsi command. | |
234 | * @cmd: the command to setup | |
235 | * | |
236 | * Called from sd_init_command() for a REQ_OP_ZONE_RESET request. | |
237 | */ | |
89d94756 HR |
238 | int sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd) |
239 | { | |
240 | struct request *rq = cmd->request; | |
241 | struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); | |
242 | sector_t sector = blk_rq_pos(rq); | |
243 | sector_t block = sectors_to_logical(sdkp->device, sector); | |
89d94756 HR |
244 | |
245 | if (!sd_is_zoned(sdkp)) | |
246 | /* Not a zoned device */ | |
247 | return BLKPREP_KILL; | |
248 | ||
249 | if (sdkp->device->changed) | |
250 | return BLKPREP_KILL; | |
251 | ||
252 | if (sector & (sd_zbc_zone_sectors(sdkp) - 1)) | |
253 | /* Unaligned request */ | |
254 | return BLKPREP_KILL; | |
255 | ||
89d94756 HR |
256 | cmd->cmd_len = 16; |
257 | memset(cmd->cmnd, 0, cmd->cmd_len); | |
258 | cmd->cmnd[0] = ZBC_OUT; | |
259 | cmd->cmnd[1] = ZO_RESET_WRITE_POINTER; | |
260 | put_unaligned_be64(block, &cmd->cmnd[2]); | |
261 | ||
262 | rq->timeout = SD_TIMEOUT; | |
263 | cmd->sc_data_direction = DMA_NONE; | |
264 | cmd->transfersize = 0; | |
265 | cmd->allowed = 0; | |
266 | ||
267 | return BLKPREP_OK; | |
268 | } | |
269 | ||
e98f42bc DLM |
270 | /** |
271 | * sd_zbc_complete - ZBC command post processing. | |
272 | * @cmd: Completed command | |
273 | * @good_bytes: Command reply bytes | |
274 | * @sshdr: command sense header | |
275 | * | |
276 | * Called from sd_done(). Process report zones reply and handle reset zone | |
277 | * and write commands errors. | |
278 | */ | |
279 | void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, | |
89d94756 HR |
280 | struct scsi_sense_hdr *sshdr) |
281 | { | |
282 | int result = cmd->result; | |
283 | struct request *rq = cmd->request; | |
284 | ||
285 | switch (req_op(rq)) { | |
868ed5a5 DLM |
286 | case REQ_OP_ZONE_RESET: |
287 | ||
288 | if (result && | |
289 | sshdr->sense_key == ILLEGAL_REQUEST && | |
290 | sshdr->asc == 0x24) | |
291 | /* | |
292 | * INVALID FIELD IN CDB error: reset of a conventional | |
293 | * zone was attempted. Nothing to worry about, so be | |
294 | * quiet about the error. | |
295 | */ | |
296 | rq->rq_flags |= RQF_QUIET; | |
297 | break; | |
298 | ||
89d94756 | 299 | case REQ_OP_WRITE: |
02d26103 | 300 | case REQ_OP_WRITE_ZEROES: |
89d94756 | 301 | case REQ_OP_WRITE_SAME: |
89d94756 | 302 | |
868ed5a5 DLM |
303 | if (result && |
304 | sshdr->sense_key == ILLEGAL_REQUEST && | |
305 | sshdr->asc == 0x21) | |
89d94756 HR |
306 | /* |
307 | * INVALID ADDRESS FOR WRITE error: It is unlikely that | |
308 | * retrying write requests failed with any kind of | |
309 | * alignement error will result in success. So don't. | |
310 | */ | |
311 | cmd->allowed = 0; | |
89d94756 HR |
312 | break; |
313 | ||
314 | case REQ_OP_ZONE_REPORT: | |
315 | ||
316 | if (!result) | |
317 | sd_zbc_report_zones_complete(cmd, good_bytes); | |
318 | break; | |
319 | ||
320 | } | |
321 | } | |
322 | ||
323 | /** | |
e98f42bc DLM |
324 | * sd_zbc_read_zoned_characteristics - Read zoned block device characteristics |
325 | * @sdkp: Target disk | |
326 | * @buf: Buffer where to store the VPD page data | |
327 | * | |
328 | * Read VPD page B6. | |
89d94756 HR |
329 | */ |
330 | static int sd_zbc_read_zoned_characteristics(struct scsi_disk *sdkp, | |
331 | unsigned char *buf) | |
332 | { | |
333 | ||
334 | if (scsi_get_vpd_page(sdkp->device, 0xb6, buf, 64)) { | |
335 | sd_printk(KERN_NOTICE, sdkp, | |
336 | "Unconstrained-read check failed\n"); | |
337 | return -ENODEV; | |
338 | } | |
339 | ||
340 | if (sdkp->device->type != TYPE_ZBC) { | |
341 | /* Host-aware */ | |
342 | sdkp->urswrz = 1; | |
4a109032 DLM |
343 | sdkp->zones_optimal_open = get_unaligned_be32(&buf[8]); |
344 | sdkp->zones_optimal_nonseq = get_unaligned_be32(&buf[12]); | |
89d94756 HR |
345 | sdkp->zones_max_open = 0; |
346 | } else { | |
347 | /* Host-managed */ | |
348 | sdkp->urswrz = buf[4] & 1; | |
349 | sdkp->zones_optimal_open = 0; | |
350 | sdkp->zones_optimal_nonseq = 0; | |
4a109032 | 351 | sdkp->zones_max_open = get_unaligned_be32(&buf[16]); |
89d94756 HR |
352 | } |
353 | ||
354 | return 0; | |
355 | } | |
356 | ||
357 | /** | |
e98f42bc DLM |
358 | * sd_zbc_check_capacity - Check reported capacity. |
359 | * @sdkp: Target disk | |
360 | * @buf: Buffer to use for commands | |
361 | * | |
362 | * ZBC drive may report only the capacity of the first conventional zones at | |
363 | * LBA 0. This is indicated by the RC_BASIS field of the read capacity reply. | |
364 | * Check this here. If the disk reported only its conventional zones capacity, | |
365 | * get the total capacity by doing a report zones. | |
89d94756 | 366 | */ |
e98f42bc | 367 | static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf) |
89d94756 HR |
368 | { |
369 | sector_t lba; | |
370 | int ret; | |
371 | ||
372 | if (sdkp->rc_basis != 0) | |
373 | return 0; | |
374 | ||
375 | /* Do a report zone to get the maximum LBA to check capacity */ | |
376 | ret = sd_zbc_report_zones(sdkp, buf, SD_BUF_SIZE, 0); | |
377 | if (ret) | |
378 | return ret; | |
379 | ||
380 | /* The max_lba field is the capacity of this device */ | |
381 | lba = get_unaligned_be64(&buf[8]); | |
382 | if (lba + 1 == sdkp->capacity) | |
383 | return 0; | |
384 | ||
385 | if (sdkp->first_scan) | |
386 | sd_printk(KERN_WARNING, sdkp, | |
387 | "Changing capacity from %llu to max LBA+1 %llu\n", | |
388 | (unsigned long long)sdkp->capacity, | |
389 | (unsigned long long)lba + 1); | |
390 | sdkp->capacity = lba + 1; | |
391 | ||
392 | return 0; | |
393 | } | |
394 | ||
e8c77ec4 | 395 | #define SD_ZBC_BUF_SIZE 131072U |
89d94756 | 396 | |
e98f42bc DLM |
397 | /** |
398 | * sd_zbc_check_zone_size - Check the device zone sizes | |
399 | * @sdkp: Target disk | |
400 | * | |
401 | * Check that all zones of the device are equal. The last zone can however | |
402 | * be smaller. The zone size must also be a power of two number of LBAs. | |
403 | */ | |
89d94756 HR |
404 | static int sd_zbc_check_zone_size(struct scsi_disk *sdkp) |
405 | { | |
4b433924 | 406 | u64 zone_blocks = 0; |
89d94756 HR |
407 | sector_t block = 0; |
408 | unsigned char *buf; | |
409 | unsigned char *rec; | |
410 | unsigned int buf_len; | |
411 | unsigned int list_length; | |
412 | int ret; | |
413 | u8 same; | |
414 | ||
415 | sdkp->zone_blocks = 0; | |
416 | ||
417 | /* Get a buffer */ | |
418 | buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); | |
419 | if (!buf) | |
420 | return -ENOMEM; | |
421 | ||
422 | /* Do a report zone to get the same field */ | |
423 | ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0); | |
4b433924 DLM |
424 | if (ret) |
425 | goto out_free; | |
89d94756 HR |
426 | |
427 | same = buf[4] & 0x0f; | |
428 | if (same > 0) { | |
429 | rec = &buf[64]; | |
430 | zone_blocks = get_unaligned_be64(&rec[8]); | |
431 | goto out; | |
432 | } | |
433 | ||
434 | /* | |
435 | * Check the size of all zones: all zones must be of | |
436 | * equal size, except the last zone which can be smaller | |
437 | * than other zones. | |
438 | */ | |
439 | do { | |
440 | ||
441 | /* Parse REPORT ZONES header */ | |
442 | list_length = get_unaligned_be32(&buf[0]) + 64; | |
443 | rec = buf + 64; | |
e8c77ec4 | 444 | buf_len = min(list_length, SD_ZBC_BUF_SIZE); |
89d94756 HR |
445 | |
446 | /* Parse zone descriptors */ | |
447 | while (rec < buf + buf_len) { | |
448 | zone_blocks = get_unaligned_be64(&rec[8]); | |
449 | if (sdkp->zone_blocks == 0) { | |
450 | sdkp->zone_blocks = zone_blocks; | |
451 | } else if (zone_blocks != sdkp->zone_blocks && | |
452 | (block + zone_blocks < sdkp->capacity | |
453 | || zone_blocks > sdkp->zone_blocks)) { | |
454 | zone_blocks = 0; | |
455 | goto out; | |
456 | } | |
457 | block += zone_blocks; | |
458 | rec += 64; | |
459 | } | |
460 | ||
461 | if (block < sdkp->capacity) { | |
462 | ret = sd_zbc_report_zones(sdkp, buf, | |
463 | SD_ZBC_BUF_SIZE, block); | |
464 | if (ret) | |
4b433924 | 465 | goto out_free; |
89d94756 HR |
466 | } |
467 | ||
468 | } while (block < sdkp->capacity); | |
469 | ||
470 | zone_blocks = sdkp->zone_blocks; | |
471 | ||
472 | out: | |
89d94756 HR |
473 | if (!zone_blocks) { |
474 | if (sdkp->first_scan) | |
475 | sd_printk(KERN_NOTICE, sdkp, | |
476 | "Devices with non constant zone " | |
477 | "size are not supported\n"); | |
4b433924 DLM |
478 | ret = -ENODEV; |
479 | } else if (!is_power_of_2(zone_blocks)) { | |
89d94756 HR |
480 | if (sdkp->first_scan) |
481 | sd_printk(KERN_NOTICE, sdkp, | |
482 | "Devices with non power of 2 zone " | |
483 | "size are not supported\n"); | |
4b433924 DLM |
484 | ret = -ENODEV; |
485 | } else if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { | |
89d94756 HR |
486 | if (sdkp->first_scan) |
487 | sd_printk(KERN_NOTICE, sdkp, | |
488 | "Zone size too large\n"); | |
4b433924 DLM |
489 | ret = -ENODEV; |
490 | } else { | |
491 | sdkp->zone_blocks = zone_blocks; | |
492 | sdkp->zone_shift = ilog2(zone_blocks); | |
89d94756 HR |
493 | } |
494 | ||
4b433924 DLM |
495 | out_free: |
496 | kfree(buf); | |
89d94756 | 497 | |
4b433924 | 498 | return ret; |
89d94756 HR |
499 | } |
500 | ||
23349ca9 DLM |
501 | /** |
502 | * sd_zbc_alloc_zone_bitmap - Allocate a zone bitmap (one bit per zone). | |
503 | * @sdkp: The disk of the bitmap | |
504 | */ | |
505 | static inline unsigned long *sd_zbc_alloc_zone_bitmap(struct scsi_disk *sdkp) | |
506 | { | |
507 | struct request_queue *q = sdkp->disk->queue; | |
508 | ||
509 | return kzalloc_node(BITS_TO_LONGS(sdkp->nr_zones) | |
510 | * sizeof(unsigned long), | |
511 | GFP_KERNEL, q->node); | |
512 | } | |
513 | ||
514 | /** | |
515 | * sd_zbc_get_seq_zones - Parse report zones reply to identify sequential zones | |
516 | * @sdkp: disk used | |
517 | * @buf: report reply buffer | |
518 | * @seq_zone_bitamp: bitmap of sequential zones to set | |
519 | * | |
520 | * Parse reported zone descriptors in @buf to identify sequential zones and | |
521 | * set the reported zone bit in @seq_zones_bitmap accordingly. | |
522 | * Since read-only and offline zones cannot be written, do not | |
523 | * mark them as sequential in the bitmap. | |
524 | * Return the LBA after the last zone reported. | |
525 | */ | |
526 | static sector_t sd_zbc_get_seq_zones(struct scsi_disk *sdkp, unsigned char *buf, | |
527 | unsigned int buflen, | |
528 | unsigned long *seq_zones_bitmap) | |
529 | { | |
530 | sector_t lba, next_lba = sdkp->capacity; | |
531 | unsigned int buf_len, list_length; | |
532 | unsigned char *rec; | |
533 | u8 type, cond; | |
534 | ||
535 | list_length = get_unaligned_be32(&buf[0]) + 64; | |
536 | buf_len = min(list_length, buflen); | |
537 | rec = buf + 64; | |
538 | ||
539 | while (rec < buf + buf_len) { | |
540 | type = rec[0] & 0x0f; | |
541 | cond = (rec[1] >> 4) & 0xf; | |
542 | lba = get_unaligned_be64(&rec[16]); | |
543 | if (type != ZBC_ZONE_TYPE_CONV && | |
544 | cond != ZBC_ZONE_COND_READONLY && | |
545 | cond != ZBC_ZONE_COND_OFFLINE) | |
546 | set_bit(lba >> sdkp->zone_shift, seq_zones_bitmap); | |
547 | next_lba = lba + get_unaligned_be64(&rec[8]); | |
548 | rec += 64; | |
549 | } | |
550 | ||
551 | return next_lba; | |
552 | } | |
553 | ||
554 | /** | |
555 | * sd_zbc_setup_seq_zones_bitmap - Initialize the disk seq zone bitmap. | |
556 | * @sdkp: target disk | |
557 | * | |
558 | * Allocate a zone bitmap and initialize it by identifying sequential zones. | |
559 | */ | |
560 | static int sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp) | |
561 | { | |
562 | struct request_queue *q = sdkp->disk->queue; | |
563 | unsigned long *seq_zones_bitmap; | |
564 | sector_t lba = 0; | |
565 | unsigned char *buf; | |
566 | int ret = -ENOMEM; | |
567 | ||
568 | seq_zones_bitmap = sd_zbc_alloc_zone_bitmap(sdkp); | |
569 | if (!seq_zones_bitmap) | |
570 | return -ENOMEM; | |
571 | ||
572 | buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); | |
573 | if (!buf) | |
574 | goto out; | |
575 | ||
576 | while (lba < sdkp->capacity) { | |
577 | ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, lba); | |
578 | if (ret) | |
579 | goto out; | |
580 | lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE, | |
581 | seq_zones_bitmap); | |
582 | } | |
583 | ||
584 | if (lba != sdkp->capacity) { | |
585 | /* Something went wrong */ | |
586 | ret = -EIO; | |
587 | } | |
588 | ||
589 | out: | |
590 | kfree(buf); | |
591 | if (ret) { | |
592 | kfree(seq_zones_bitmap); | |
593 | return ret; | |
594 | } | |
595 | ||
596 | q->seq_zones_bitmap = seq_zones_bitmap; | |
597 | ||
598 | return 0; | |
599 | } | |
600 | ||
601 | static void sd_zbc_cleanup(struct scsi_disk *sdkp) | |
602 | { | |
603 | struct request_queue *q = sdkp->disk->queue; | |
604 | ||
605 | kfree(q->seq_zones_bitmap); | |
606 | q->seq_zones_bitmap = NULL; | |
607 | ||
608 | kfree(q->seq_zones_wlock); | |
609 | q->seq_zones_wlock = NULL; | |
610 | ||
611 | q->nr_zones = 0; | |
612 | } | |
613 | ||
89d94756 HR |
614 | static int sd_zbc_setup(struct scsi_disk *sdkp) |
615 | { | |
23349ca9 DLM |
616 | struct request_queue *q = sdkp->disk->queue; |
617 | int ret; | |
89d94756 | 618 | |
5eed92d1 DLM |
619 | /* READ16/WRITE16 is mandatory for ZBC disks */ |
620 | sdkp->device->use_16_for_rw = 1; | |
621 | sdkp->device->use_10_for_rw = 0; | |
622 | ||
89d94756 HR |
623 | /* chunk_sectors indicates the zone size */ |
624 | blk_queue_chunk_sectors(sdkp->disk->queue, | |
625 | logical_to_sectors(sdkp->device, sdkp->zone_blocks)); | |
e8c77ec4 DLM |
626 | sdkp->nr_zones = |
627 | round_up(sdkp->capacity, sdkp->zone_blocks) >> sdkp->zone_shift; | |
89d94756 | 628 | |
23349ca9 DLM |
629 | /* |
630 | * Initialize the device request queue information if the number | |
631 | * of zones changed. | |
632 | */ | |
633 | if (sdkp->nr_zones != q->nr_zones) { | |
634 | ||
635 | sd_zbc_cleanup(sdkp); | |
636 | ||
637 | q->nr_zones = sdkp->nr_zones; | |
638 | if (sdkp->nr_zones) { | |
639 | q->seq_zones_wlock = sd_zbc_alloc_zone_bitmap(sdkp); | |
640 | if (!q->seq_zones_wlock) { | |
641 | ret = -ENOMEM; | |
642 | goto err; | |
643 | } | |
644 | ||
645 | ret = sd_zbc_setup_seq_zones_bitmap(sdkp); | |
646 | if (ret) { | |
647 | sd_zbc_cleanup(sdkp); | |
648 | goto err; | |
649 | } | |
650 | } | |
651 | ||
89d94756 HR |
652 | } |
653 | ||
654 | return 0; | |
23349ca9 DLM |
655 | |
656 | err: | |
657 | sd_zbc_cleanup(sdkp); | |
658 | return ret; | |
89d94756 HR |
659 | } |
660 | ||
e98f42bc | 661 | int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) |
89d94756 | 662 | { |
f7053240 | 663 | int ret; |
89d94756 HR |
664 | |
665 | if (!sd_is_zoned(sdkp)) | |
666 | /* | |
667 | * Device managed or normal SCSI disk, | |
668 | * no special handling required | |
669 | */ | |
670 | return 0; | |
671 | ||
89d94756 HR |
672 | /* Get zoned block device characteristics */ |
673 | ret = sd_zbc_read_zoned_characteristics(sdkp, buf); | |
674 | if (ret) | |
675 | goto err; | |
676 | ||
677 | /* | |
678 | * Check for unconstrained reads: host-managed devices with | |
679 | * constrained reads (drives failing read after write pointer) | |
680 | * are not supported. | |
681 | */ | |
682 | if (!sdkp->urswrz) { | |
683 | if (sdkp->first_scan) | |
684 | sd_printk(KERN_NOTICE, sdkp, | |
685 | "constrained reads devices are not supported\n"); | |
686 | ret = -ENODEV; | |
687 | goto err; | |
688 | } | |
689 | ||
690 | /* Check capacity */ | |
691 | ret = sd_zbc_check_capacity(sdkp, buf); | |
692 | if (ret) | |
693 | goto err; | |
89d94756 HR |
694 | |
695 | /* | |
696 | * Check zone size: only devices with a constant zone size (except | |
697 | * an eventual last runt zone) that is a power of 2 are supported. | |
698 | */ | |
699 | ret = sd_zbc_check_zone_size(sdkp); | |
700 | if (ret) | |
701 | goto err; | |
702 | ||
703 | /* The drive satisfies the kernel restrictions: set it up */ | |
704 | ret = sd_zbc_setup(sdkp); | |
705 | if (ret) | |
706 | goto err; | |
707 | ||
708 | return 0; | |
709 | ||
710 | err: | |
711 | sdkp->capacity = 0; | |
23349ca9 | 712 | sd_zbc_cleanup(sdkp); |
89d94756 HR |
713 | |
714 | return ret; | |
715 | } | |
716 | ||
717 | void sd_zbc_remove(struct scsi_disk *sdkp) | |
718 | { | |
23349ca9 | 719 | sd_zbc_cleanup(sdkp); |
89d94756 HR |
720 | } |
721 | ||
722 | void sd_zbc_print_zones(struct scsi_disk *sdkp) | |
723 | { | |
724 | if (!sd_is_zoned(sdkp) || !sdkp->capacity) | |
725 | return; | |
726 | ||
727 | if (sdkp->capacity & (sdkp->zone_blocks - 1)) | |
728 | sd_printk(KERN_NOTICE, sdkp, | |
729 | "%u zones of %u logical blocks + 1 runt zone\n", | |
730 | sdkp->nr_zones - 1, | |
731 | sdkp->zone_blocks); | |
732 | else | |
733 | sd_printk(KERN_NOTICE, sdkp, | |
734 | "%u zones of %u logical blocks\n", | |
735 | sdkp->nr_zones, | |
736 | sdkp->zone_blocks); | |
737 | } |