| @@ -96,16 +96,14 @@ struct virtblk_req { · 95 unmodified lines |
| 96 | | 96 | |
| 97 | /* | 97 | /* |
| 98 | * The zone append command has an extended in header. | 98 | * The zone append command has an extended in header. |
| 99 | * The status field in zone_append_in_hdr must have | 99 | * The status field in zone_append_in_hdr must always |
| 100 | * the same offset in virtblk_req as the non-zoned | 100 | * be the last byte. |
| 101 | * status field above. | | |
| 102 | */ | 101 | */ |
| 103 | struct { | 102 | struct { |
| | 103 | __virtio64 sector; |
| 104 | u8 status; | 104 | u8 status; |
| 105 | u8 reserved[7]; | 105 | } zone_append; |
| 106 | __le64 append_sector; | 106 | } in_hdr; |
| 107 | } zone_append_in_hdr; | | |
| 108 | }; | | |
| 109 | | 107 | |
| 110 | size_t in_hdr_len; | 108 | size_t in_hdr_len; |
| 111 | | 109 | |
| @@ -154,7 +152,7 @@ static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr) · 42 unmodified lines |
| 154 | sgs[num_out + num_in++] = vbr->sg_table.sgl; | 152 | sgs[num_out + num_in++] = vbr->sg_table.sgl; |
| 155 | } | 153 | } |
| 156 | | 154 | |
| 157 | sg_init_one(&in_hdr, &vbr->status, vbr->in_hdr_len); | 155 | sg_init_one(&in_hdr, &vbr->in_hdr.status, vbr->in_hdr_len); |
| 158 | sgs[num_out + num_in++] = &in_hdr; | 156 | sgs[num_out + num_in++] = &in_hdr; |
| 159 | | 157 | |
| 160 | return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); | 158 | return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); |
| @@ -242,11 +240,14 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, · 81 unmodified lines |
| 242 | struct request *req, | 240 | struct request *req, |
| 243 | struct virtblk_req *vbr) | 241 | struct virtblk_req *vbr) |
| 244 | { | 242 | { |
| 245 | size_t in_hdr_len = sizeof(vbr->status); | 243 | size_t in_hdr_len = sizeof(vbr->in_hdr.status); |
| 246 | bool unmap = false; | 244 | bool unmap = false; |
| 247 | u32 type; | 245 | u32 type; |
| 248 | u64 sector = 0; | 246 | u64 sector = 0; |
| 249 | | 247 | |
| | 248 | if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) && op_is_zone_mgmt(req_op(req))) |
| | 249 | return BLK_STS_NOTSUPP; |
| | 250 | |
| 250 | /* Set fields for all request types */ | 251 | /* Set fields for all request types */ |
| 251 | vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req)); | 252 | vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req)); |
| 252 | | 253 | |
| @@ -287,7 +288,7 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, · 34 unmodified lines |
| 287 | case REQ_OP_ZONE_APPEND: | 288 | case REQ_OP_ZONE_APPEND: |
| 288 | type = VIRTIO_BLK_T_ZONE_APPEND; | 289 | type = VIRTIO_BLK_T_ZONE_APPEND; |
| 289 | sector = blk_rq_pos(req); | 290 | sector = blk_rq_pos(req); |
| 290 | in_hdr_len = sizeof(vbr->zone_append_in_hdr); | 291 | in_hdr_len = sizeof(vbr->in_hdr.zone_append); |
| 291 | break; | 292 | break; |
| 292 | case REQ_OP_ZONE_RESET: | 293 | case REQ_OP_ZONE_RESET: |
| 293 | type = VIRTIO_BLK_T_ZONE_RESET; | 294 | type = VIRTIO_BLK_T_ZONE_RESET; |
| @@ -297,7 +298,10 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, · 3 unmodified lines |
| 297 | type = VIRTIO_BLK_T_ZONE_RESET_ALL; | 298 | type = VIRTIO_BLK_T_ZONE_RESET_ALL; |
| 298 | break; | 299 | break; |
| 299 | case REQ_OP_DRV_IN: | 300 | case REQ_OP_DRV_IN: |
| 300 | /* Out header already filled in, nothing to do */ | 301 | /* |
| | 302 | * Out header has already been prepared by the caller (virtblk_get_id() |
| | 303 | * or virtblk_submit_zone_report()), nothing to do here. |
| | 304 | */ |
| 301 | return 0; | 305 | return 0; |
| 302 | default: | 306 | default: |
| 303 | WARN_ON_ONCE(1); | 307 | WARN_ON_ONCE(1); |
| @@ -318,16 +322,28 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, · 14 unmodified lines |
| 318 | return 0; | 322 | return 0; |
| 319 | } | 323 | } |
| 320 | | 324 | |
| | 325 | /* |
| | 326 | * The status byte is always the last byte of the virtblk request |
| | 327 | * in-header. This helper fetches its value for all in-header formats |
| | 328 | * that are currently defined. |
| | 329 | */ |
| | 330 | static inline u8 virtblk_vbr_status(struct virtblk_req *vbr) |
| | 331 | { |
| | 332 | return *((u8 *)&vbr->in_hdr + vbr->in_hdr_len - 1); |
| | 333 | } |
| | 334 | |
| 321 | static inline void virtblk_request_done(struct request *req) | 335 | static inline void virtblk_request_done(struct request *req) |
| 322 | { | 336 | { |
| 323 | struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); | 337 | struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); |
| 324 | blk_status_t status = virtblk_result(vbr->status); | 338 | blk_status_t status = virtblk_result(virtblk_vbr_status(vbr)); |
| | 339 | struct virtio_blk *vblk = req->mq_hctx->queue->queuedata; |
| 325 | | 340 | |
| 326 | virtblk_unmap_data(req, vbr); | 341 | virtblk_unmap_data(req, vbr); |
| 327 | virtblk_cleanup_cmd(req); | 342 | virtblk_cleanup_cmd(req); |
| 328 | | 343 | |
| 329 | if (req_op(req) == REQ_OP_ZONE_APPEND) | 344 | if (req_op(req) == REQ_OP_ZONE_APPEND) |
| 330 | req->__sector = le64_to_cpu(vbr->zone_append_in_hdr.append_sector); | 345 | req->__sector = virtio64_to_cpu(vblk->vdev, |
| | 346 | vbr->in_hdr.zone_append.sector); |
| 331 | | 347 | |
| 332 | blk_mq_end_request(req, status); | 348 | blk_mq_end_request(req, status); |
| 333 | } | 349 | } |
| @@ -355,7 +371,7 @@ static int virtblk_handle_req(struct virtio_blk_vq *vq, · 21 unmodified lines |
| 355 | | 371 | |
| 356 | if (likely(!blk_should_fake_timeout(req->q)) && | 372 | if (likely(!blk_should_fake_timeout(req->q)) && |
| 357 | !blk_mq_complete_request_remote(req) && | 373 | !blk_mq_complete_request_remote(req) && |
| 358 | !blk_mq_add_to_batch(req, iob, vbr->status, | 374 | !blk_mq_add_to_batch(req, iob, virtblk_vbr_status(vbr), |
| 359 | virtblk_complete_batch)) | 375 | virtblk_complete_batch)) |
| 360 | virtblk_request_done(req); | 376 | virtblk_request_done(req); |
| 361 | req_done++; | 377 | req_done++; |
| @@ -550,7 +566,6 @@ static void virtio_queue_rqs(struct request **rqlist) · 188 unmodified lines |
| 550 | #ifdef CONFIG_BLK_DEV_ZONED | 566 | #ifdef CONFIG_BLK_DEV_ZONED |
| 551 | static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk, | 567 | static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk, |
| 552 | unsigned int nr_zones, | 568 | unsigned int nr_zones, |
| 553 | unsigned int zone_sectors, | | |
| 554 | size_t *buflen) | 569 | size_t *buflen) |
| 555 | { | 570 | { |
| 556 | struct request_queue *q = vblk->disk->queue; | 571 | struct request_queue *q = vblk->disk->queue; |
| @@ -558,7 +573,7 @@ static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk, · 1 unmodified line |
| 558 | void *buf; | 573 | void *buf; |
| 559 | | 574 | |
| 560 | nr_zones = min_t(unsigned int, nr_zones, | 575 | nr_zones = min_t(unsigned int, nr_zones, |
| 561 | get_capacity(vblk->disk) >> ilog2(zone_sectors)); | 576 | get_capacity(vblk->disk) >> ilog2(vblk->zone_sectors)); |
| 562 | | 577 | |
| 563 | bufsize = sizeof(struct virtio_blk_zone_report) + | 578 | bufsize = sizeof(struct virtio_blk_zone_report) + |
| 564 | nr_zones * sizeof(struct virtio_blk_zone_descriptor); | 579 | nr_zones * sizeof(struct virtio_blk_zone_descriptor); |
| @@ -592,7 +607,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk, · 27 unmodified lines |
| 592 | return PTR_ERR(req); | 607 | return PTR_ERR(req); |
| 593 | | 608 | |
| 594 | vbr = blk_mq_rq_to_pdu(req); | 609 | vbr = blk_mq_rq_to_pdu(req); |
| 595 | vbr->in_hdr_len = sizeof(vbr->status); | 610 | vbr->in_hdr_len = sizeof(vbr->in_hdr.status); |
| 596 | vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT); | 611 | vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT); |
| 597 | vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector); | 612 | vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, sector); |
| 598 | | 613 | |
| @@ -601,7 +616,7 @@ static int virtblk_submit_zone_report(struct virtio_blk *vblk, · 2 unmodified lines |
| 601 | goto out; | 616 | goto out; |
| 602 | | 617 | |
| 603 | blk_execute_rq(req, false); | 618 | blk_execute_rq(req, false); |
| 604 | err = blk_status_to_errno(virtblk_result(vbr->status)); | 619 | err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status)); |
| 605 | out: | 620 | out: |
| 606 | blk_mq_free_request(req); | 621 | blk_mq_free_request(req); |
| 607 | return err; | 622 | return err; |
| @@ -609,29 +624,72 @@ out: · 1 unmodified line |
| 609 | | 624 | |
| 610 | static int virtblk_parse_zone(struct virtio_blk *vblk, | 625 | static int virtblk_parse_zone(struct virtio_blk *vblk, |
| 611 | struct virtio_blk_zone_descriptor *entry, | 626 | struct virtio_blk_zone_descriptor *entry, |
| 612 | unsigned int idx, unsigned int zone_sectors, | 627 | unsigned int idx, report_zones_cb cb, void *data) |
| 613 | report_zones_cb cb, void *data) | | |
| 614 | { | 628 | { |
| 615 | struct blk_zone zone = { }; | 629 | struct blk_zone zone = { }; |
| 616 | | 630 | |
| 617 | if (entry->z_type != VIRTIO_BLK_ZT_SWR && | 631 | zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start); |
| 618 | entry->z_type != VIRTIO_BLK_ZT_SWP && | 632 | if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk)) |
| 619 | entry->z_type != VIRTIO_BLK_ZT_CONV) { | 633 | zone.len = vblk->zone_sectors; |
| 620 | dev_err(&vblk->vdev->dev, "invalid zone type %#x\n", | 634 | else |
| 621 | entry->z_type); | 635 | zone.len = get_capacity(vblk->disk) - zone.start; |
| 622 | return -EINVAL; | 636 | zone.capacity = virtio64_to_cpu(vblk->vdev, entry->z_cap); |
| | 637 | zone.wp = virtio64_to_cpu(vblk->vdev, entry->z_wp); |
| | 638 | |
| | 639 | switch (entry->z_type) { |
| | 640 | case VIRTIO_BLK_ZT_SWR: |
| | 641 | zone.type = BLK_ZONE_TYPE_SEQWRITE_REQ; |
| | 642 | break; |
| | 643 | case VIRTIO_BLK_ZT_SWP: |
| | 644 | zone.type = BLK_ZONE_TYPE_SEQWRITE_PREF; |
| | 645 | break; |
| | 646 | case VIRTIO_BLK_ZT_CONV: |
| | 647 | zone.type = BLK_ZONE_TYPE_CONVENTIONAL; |
| | 648 | break; |
| | 649 | default: |
| | 650 | dev_err(&vblk->vdev->dev, "zone %llu: invalid type %#x\n", |
| | 651 | zone.start, entry->z_type); |
| | 652 | return -EIO; |
| 623 | } | 653 | } |
| 624 | | 654 | |
| 625 | zone.type = entry->z_type; | 655 | switch (entry->z_state) { |
| 626 | zone.cond = entry->z_state; | 656 | case VIRTIO_BLK_ZS_EMPTY: |
| 627 | zone.len = zone_sectors; | 657 | zone.cond = BLK_ZONE_COND_EMPTY; |
| 628 | zone.capacity = le64_to_cpu(entry->z_cap); | 658 | break; |
| 629 | zone.start = le64_to_cpu(entry->z_start); | 659 | case VIRTIO_BLK_ZS_CLOSED: |
| 630 | if (zone.cond == BLK_ZONE_COND_FULL) | 660 | zone.cond = BLK_ZONE_COND_CLOSED; |
| | 661 | break; |
| | 662 | case VIRTIO_BLK_ZS_FULL: |
| | 663 | zone.cond = BLK_ZONE_COND_FULL; |
| 631 | zone.wp = zone.start + zone.len; | 664 | zone.wp = zone.start + zone.len; |
| 632 | else | 665 | break; |
| 633 | zone.wp = le64_to_cpu(entry->z_wp); | 666 | case VIRTIO_BLK_ZS_EOPEN: |
| | 667 | zone.cond = BLK_ZONE_COND_EXP_OPEN; |
| | 668 | break; |
| | 669 | case VIRTIO_BLK_ZS_IOPEN: |
| | 670 | zone.cond = BLK_ZONE_COND_IMP_OPEN; |
| | 671 | break; |
| | 672 | case VIRTIO_BLK_ZS_NOT_WP: |
| | 673 | zone.cond = BLK_ZONE_COND_NOT_WP; |
| | 674 | break; |
| | 675 | case VIRTIO_BLK_ZS_RDONLY: |
| | 676 | zone.cond = BLK_ZONE_COND_READONLY; |
| | 677 | zone.wp = ULONG_MAX; |
| | 678 | break; |
| | 679 | case VIRTIO_BLK_ZS_OFFLINE: |
| | 680 | zone.cond = BLK_ZONE_COND_OFFLINE; |
| | 681 | zone.wp = ULONG_MAX; |
| | 682 | break; |
| | 683 | default: |
| | 684 | dev_err(&vblk->vdev->dev, "zone %llu: invalid condition %#x\n", |
| | 685 | zone.start, entry->z_state); |
| | 686 | return -EIO; |
| | 687 | } |
| 634 | | 688 | |
| | 689 | /* |
| | 690 | * The callback below checks the validity of the reported |
| | 691 | * entry data, no need to further validate it here. |
| | 692 | */ |
| 635 | return cb(&zone, idx, data); | 693 | return cb(&zone, idx, data); |
| 636 | } | 694 | } |
| 637 | | 695 | |
| @@ -641,39 +699,47 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector, · 3 unmodified lines |
| 641 | { | 699 | { |
| 642 | struct virtio_blk *vblk = disk->private_data; | 700 | struct virtio_blk *vblk = disk->private_data; |
| 643 | struct virtio_blk_zone_report *report; | 701 | struct virtio_blk_zone_report *report; |
| 644 | unsigned int zone_sectors = vblk->zone_sectors; | 702 | unsigned long long nz, i; |
| 645 | unsigned int nz, i; | | |
| 646 | int ret, zone_idx = 0; | | |
| 647 | size_t buflen; | 703 | size_t buflen; |
| | 704 | unsigned int zone_idx = 0; |
| | 705 | int ret; |
| 648 | | 706 | |
| 649 | if (WARN_ON_ONCE(!vblk->zone_sectors)) | 707 | if (WARN_ON_ONCE(!vblk->zone_sectors)) |
| 650 | return -EOPNOTSUPP; | 708 | return -EOPNOTSUPP; |
| 651 | | 709 | |
| 652 | report = virtblk_alloc_report_buffer(vblk, nr_zones, | 710 | report = virtblk_alloc_report_buffer(vblk, nr_zones, &buflen); |
| 653 | zone_sectors, &buflen); | | |
| 654 | if (!report) | 711 | if (!report) |
| 655 | return -ENOMEM; | 712 | return -ENOMEM; |
| 656 | | 713 | |
| | 714 | mutex_lock(&vblk->vdev_mutex); |
| | 715 | |
| | 716 | if (!vblk->vdev) { |
| | 717 | ret = -ENXIO; |
| | 718 | goto fail_report; |
| | 719 | } |
| | 720 | |
| 657 | while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) { | 721 | while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) { |
| 658 | memset(report, 0, buflen); | 722 | memset(report, 0, buflen); |
| 659 | | 723 | |
| 660 | ret = virtblk_submit_zone_report(vblk, (char *)report, | 724 | ret = virtblk_submit_zone_report(vblk, (char *)report, |
| 661 | buflen, sector); | 725 | buflen, sector); |
| 662 | if (ret) { | 726 | if (ret) |
| 663 | if (ret > 0) | 727 | goto fail_report; |
| 664 | ret = -EIO; | 728 | |
| 665 | goto out_free; | 729 | nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones), |
| 666 | } | 730 | nr_zones); |
| 667 | nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones); | | |
| 668 | if (!nz) | 731 | if (!nz) |
| 669 | break; | 732 | break; |
| 670 | | 733 | |
| 671 | for (i = 0; i < nz && zone_idx < nr_zones; i++) { | 734 | for (i = 0; i < nz && zone_idx < nr_zones; i++) { |
| 672 | ret = virtblk_parse_zone(vblk, &report->zones[i], | 735 | ret = virtblk_parse_zone(vblk, &report->zones[i], |
| 673 | zone_idx, zone_sectors, cb, data); | 736 | zone_idx, cb, data); |
| 674 | if (ret) | 737 | if (ret) |
| 675 | goto out_free; | 738 | goto fail_report; |
| 676 | sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors; | 739 | |
| | 740 | sector = virtio64_to_cpu(vblk->vdev, |
| | 741 | report->zones[i].z_start) + |
| | 742 | vblk->zone_sectors; |
| 677 | zone_idx++; | 743 | zone_idx++; |
| 678 | } | 744 | } |
| 679 | } | 745 | } |
| @@ -682,7 +748,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector, · 2 unmodified lines |
| 682 | ret = zone_idx; | 748 | ret = zone_idx; |
| 683 | else | 749 | else |
| 684 | ret = -EINVAL; | 750 | ret = -EINVAL; |
| 685 | out_free: | 751 | fail_report: |
| | 752 | mutex_unlock(&vblk->vdev_mutex); |
| 686 | kvfree(report); | 753 | kvfree(report); |
| 687 | return ret; | 754 | return ret; |
| 688 | } | 755 | } |
| @@ -691,20 +758,28 @@ static void virtblk_revalidate_zones(struct virtio_blk *vblk) · 2 unmodified lines |
| 691 | { | 758 | { |
| 692 | u8 model; | 759 | u8 model; |
| 693 | | 760 | |
| 694 | if (!vblk->zone_sectors) | | |
| 695 | return; | | |
| 696 | | | |
| 697 | virtio_cread(vblk->vdev, struct virtio_blk_config, | 761 | virtio_cread(vblk->vdev, struct virtio_blk_config, |
| 698 | zoned.model, &model); | 762 | zoned.model, &model); |
| 699 | if (!blk_revalidate_disk_zones(vblk->disk, NULL)) | 763 | switch (model) { |
| 700 | set_capacity_and_notify(vblk->disk, 0); | 764 | default: |
| | 765 | dev_err(&vblk->vdev->dev, "unknown zone model %d\n", model); |
| | 766 | fallthrough; |
| | 767 | case VIRTIO_BLK_Z_NONE: |
| | 768 | case VIRTIO_BLK_Z_HA: |
| | 769 | disk_set_zoned(vblk->disk, BLK_ZONED_NONE); |
| | 770 | return; |
| | 771 | case VIRTIO_BLK_Z_HM: |
| | 772 | WARN_ON_ONCE(!vblk->zone_sectors); |
| | 773 | if (!blk_revalidate_disk_zones(vblk->disk, NULL)) |
| | 774 | set_capacity_and_notify(vblk->disk, 0); |
| | 775 | } |
| 701 | } | 776 | } |
| 702 | | 777 | |
| 703 | static int virtblk_probe_zoned_device(struct virtio_device *vdev, | 778 | static int virtblk_probe_zoned_device(struct virtio_device *vdev, |
| 704 | struct virtio_blk *vblk, | 779 | struct virtio_blk *vblk, |
| 705 | struct request_queue *q) | 780 | struct request_queue *q) |
| 706 | { | 781 | { |
| 707 | u32 v; | 782 | u32 v, wg; |
| 708 | u8 model; | 783 | u8 model; |
| 709 | int ret; | 784 | int ret; |
| 710 | | 785 | |
| @@ -713,16 +788,11 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, · 2 unmodified lines |
| 713 | | 788 | |
| 714 | switch (model) { | 789 | switch (model) { |
| 715 | case VIRTIO_BLK_Z_NONE: | 790 | case VIRTIO_BLK_Z_NONE: |
| | 791 | case VIRTIO_BLK_Z_HA: |
| | 792 | /* Present the host-aware device as non-zoned */ |
| 716 | return 0; | 793 | return 0; |
| 717 | case VIRTIO_BLK_Z_HM: | 794 | case VIRTIO_BLK_Z_HM: |
| 718 | break; | 795 | break; |
| 719 | case VIRTIO_BLK_Z_HA: | | |
| 720 | /* | | |
| 721 | * Present the host-aware device as a regular drive. | | |
| 722 | * TODO It is possible to add an option to make it appear | | |
| 723 | * in the system as a zoned drive. | | |
| 724 | */ | | |
| 725 | return 0; | | |
| 726 | default: | 796 | default: |
| 727 | dev_err(&vdev->dev, "unsupported zone model %d\n", model); | 797 | dev_err(&vdev->dev, "unsupported zone model %d\n", model); |
| 728 | return -EINVAL; | 798 | return -EINVAL; |
| @@ -735,32 +805,31 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, · 6 unmodified lines |
| 735 | | 805 | |
| 736 | virtio_cread(vdev, struct virtio_blk_config, | 806 | virtio_cread(vdev, struct virtio_blk_config, |
| 737 | zoned.max_open_zones, &v); | 807 | zoned.max_open_zones, &v); |
| 738 | disk_set_max_open_zones(vblk->disk, le32_to_cpu(v)); | 808 | disk_set_max_open_zones(vblk->disk, v); |
| 739 | | 809 | dev_dbg(&vdev->dev, "max open zones = %u\n", v); |
| 740 | dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v)); | | |
| 741 | | 810 | |
| 742 | virtio_cread(vdev, struct virtio_blk_config, | 811 | virtio_cread(vdev, struct virtio_blk_config, |
| 743 | zoned.max_active_zones, &v); | 812 | zoned.max_active_zones, &v); |
| 744 | disk_set_max_active_zones(vblk->disk, le32_to_cpu(v)); | 813 | disk_set_max_active_zones(vblk->disk, v); |
| 745 | dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v)); | 814 | dev_dbg(&vdev->dev, "max active zones = %u\n", v); |
| 746 | | 815 | |
| 747 | virtio_cread(vdev, struct virtio_blk_config, | 816 | virtio_cread(vdev, struct virtio_blk_config, |
| 748 | zoned.write_granularity, &v); | 817 | zoned.write_granularity, &wg); |
| 749 | if (!v) { | 818 | if (!wg) { |
| 750 | dev_warn(&vdev->dev, "zero write granularity reported\n"); | 819 | dev_warn(&vdev->dev, "zero write granularity reported\n"); |
| 751 | return -ENODEV; | 820 | return -ENODEV; |
| 752 | } | 821 | } |
| 753 | blk_queue_physical_block_size(q, le32_to_cpu(v)); | 822 | blk_queue_physical_block_size(q, wg); |
| 754 | blk_queue_io_min(q, le32_to_cpu(v)); | 823 | blk_queue_io_min(q, wg); |
| 755 | | 824 | |
| 756 | dev_dbg(&vdev->dev, "write granularity = %u\n", le32_to_cpu(v)); | 825 | dev_dbg(&vdev->dev, "write granularity = %u\n", wg); |
| 757 | | 826 | |
| 758 | /* | 827 | /* |
| 759 | * virtio ZBD specification doesn't require zones to be a power of | 828 | * virtio ZBD specification doesn't require zones to be a power of |
| 760 | * two sectors in size, but the code in this driver expects that. | 829 | * two sectors in size, but the code in this driver expects that. |
| 761 | */ | 830 | */ |
| 762 | virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, &v); | 831 | virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, |
| 763 | vblk->zone_sectors = le32_to_cpu(v); | 832 | &vblk->zone_sectors); |
| 764 | if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) { | 833 | if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) { |
| 765 | dev_err(&vdev->dev, | 834 | dev_err(&vdev->dev, |
| 766 | "zoned device with non power of two zone size %u\n", | 835 | "zoned device with non power of two zone size %u\n", |
| @@ -783,36 +852,46 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, · 16 unmodified lines |
| 783 | dev_warn(&vdev->dev, "zero max_append_sectors reported\n"); | 852 | dev_warn(&vdev->dev, "zero max_append_sectors reported\n"); |
| 784 | return -ENODEV; | 853 | return -ENODEV; |
| 785 | } | 854 | } |
| 786 | blk_queue_max_zone_append_sectors(q, le32_to_cpu(v)); | 855 | if ((v << SECTOR_SHIFT) < wg) { |
| 787 | dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v)); | 856 | dev_err(&vdev->dev, |
| | 857 | "write granularity %u exceeds max_append_sectors %u limit\n", |
| | 858 | wg, v); |
| | 859 | return -ENODEV; |
| | 860 | } |
| | 861 | |
| | 862 | blk_queue_max_zone_append_sectors(q, v); |
| | 863 | dev_dbg(&vdev->dev, "max append sectors = %u\n", v); |
| 788 | } | 864 | } |
| 789 | | 865 | |
| 790 | return ret; | 866 | return ret; |
| 791 | } | 867 | } |
| 792 | | 868 | |
| 793 | static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev) | | |
| 794 | { | | |
| 795 | return virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED); | | |
| 796 | } | | |
| 797 | #else | 869 | #else |
| 798 | | 870 | |
| 799 | /* | 871 | /* |
| 800 | * Zoned block device support is not configured in this kernel. | 872 | * Zoned block device support is not configured in this kernel. |
| 801 | * We only need to define a few symbols to avoid compilation errors. | 873 | * Host-managed zoned devices can't be supported, but others are |
| | 874 | * good to go as regular block devices. |
| 802 | */ | 875 | */ |
| 803 | #define virtblk_report_zones NULL | 876 | #define virtblk_report_zones NULL |
| | 877 | |
| 804 | static inline void virtblk_revalidate_zones(struct virtio_blk *vblk) | 878 | static inline void virtblk_revalidate_zones(struct virtio_blk *vblk) |
| 805 | { | 879 | { |
| 806 | } | 880 | } |
| | 881 | |
| 807 | static inline int virtblk_probe_zoned_device(struct virtio_device *vdev, | 882 | static inline int virtblk_probe_zoned_device(struct virtio_device *vdev, |
| 808 | struct virtio_blk *vblk, struct request_queue *q) | 883 | struct virtio_blk *vblk, struct request_queue *q) |
| 809 | { | 884 | { |
| 810 | return -EOPNOTSUPP; | 885 | u8 model; |
| 811 | } | | |
| 812 | | 886 | |
| 813 | static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev) | 887 | virtio_cread(vdev, struct virtio_blk_config, zoned.model, &model); |
| 814 | { | 888 | if (model == VIRTIO_BLK_Z_HM) { |
| 815 | return false; | 889 | dev_err(&vdev->dev, |
| | 890 | "virtio_blk: zoned devices are not supported"); |
| | 891 | return -EOPNOTSUPP; |
| | 892 | } |
| | 893 | |
| | 894 | return 0; |
| 816 | } | 895 | } |
| 817 | #endif /* CONFIG_BLK_DEV_ZONED */ | 896 | #endif /* CONFIG_BLK_DEV_ZONED */ |
| 818 | | 897 | |
| @@ -831,7 +910,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) · 12 unmodified lines |
| 831 | return PTR_ERR(req); | 910 | return PTR_ERR(req); |
| 832 | | 911 | |
| 833 | vbr = blk_mq_rq_to_pdu(req); | 912 | vbr = blk_mq_rq_to_pdu(req); |
| 834 | vbr->in_hdr_len = sizeof(vbr->status); | 913 | vbr->in_hdr_len = sizeof(vbr->in_hdr.status); |
| 835 | vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID); | 914 | vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID); |
| 836 | vbr->out_hdr.sector = 0; | 915 | vbr->out_hdr.sector = 0; |
| 837 | | 916 | |
| @@ -840,7 +919,7 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) · 2 unmodified lines |
| 840 | goto out; | 919 | goto out; |
| 841 | | 920 | |
| 842 | blk_execute_rq(req, false); | 921 | blk_execute_rq(req, false); |
| 843 | err = blk_status_to_errno(virtblk_result(vbr->status)); | 922 | err = blk_status_to_errno(virtblk_result(vbr->in_hdr.status)); |
| 844 | out: | 923 | out: |
| 845 | blk_mq_free_request(req); | 924 | blk_mq_free_request(req); |
| 846 | return err; | 925 | return err; |
| @@ -1498,15 +1577,16 @@ static int virtblk_probe(struct virtio_device *vdev) · 651 unmodified lines |
| 1498 | virtblk_update_capacity(vblk, false); | 1577 | virtblk_update_capacity(vblk, false); |
| 1499 | virtio_device_ready(vdev); | 1578 | virtio_device_ready(vdev); |
| 1500 | | 1579 | |
| 1501 | if (virtblk_has_zoned_feature(vdev)) { | 1580 | /* |
| | 1581 | * All steps that follow use the VQs therefore they need to be |
| | 1582 | * placed after the virtio_device_ready() call above. |
| | 1583 | */ |
| | 1584 | if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) { |
| 1502 | err = virtblk_probe_zoned_device(vdev, vblk, q); | 1585 | err = virtblk_probe_zoned_device(vdev, vblk, q); |
| 1503 | if (err) | 1586 | if (err) |
| 1504 | goto out_cleanup_disk; | 1587 | goto out_cleanup_disk; |
| 1505 | } | 1588 | } |
| 1506 | | 1589 | |
| 1507 | dev_info(&vdev->dev, "blk config size: %zu\n", | | |
| 1508 | sizeof(struct virtio_blk_config)); | | |
| 1509 | | | |
| 1510 | err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); | 1590 | err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); |
| 1511 | if (err) | 1591 | if (err) |
| 1512 | goto out_cleanup_disk; | 1592 | goto out_cleanup_disk; |
| @@ -1607,10 +1687,7 @@ static unsigned int features[] = { · 94 unmodified lines |
| 1607 | VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, | 1687 | VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
| 1608 | VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, | 1688 | VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, |
| 1609 | VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, | 1689 | VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, |
| 1610 | VIRTIO_BLK_F_SECURE_ERASE, | 1690 | VIRTIO_BLK_F_SECURE_ERASE, VIRTIO_BLK_F_ZONED, |
| 1611 | #ifdef CONFIG_BLK_DEV_ZONED | | |
| 1612 | VIRTIO_BLK_F_ZONED, | | |
| 1613 | #endif /* CONFIG_BLK_DEV_ZONED */ | | |
| 1614 | }; | 1691 | }; |
| 1615 | | 1692 | |
| 1616 | static struct virtio_driver virtio_blk = { | 1693 | static struct virtio_driver virtio_blk = { |