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 --- |