| @@ -96,16 +96,14 @@ struct virtblk_req { · 95 unmodified lines |
| 96 | 96 | |
| 97 | 97 | /* |
| 98 | 98 | * The zone append command has an extended in header. |
| 99 | | − * The status field in zone_append_in_hdr must have |
| 100 | | − * the same offset in virtblk_req as the non-zoned |
| 101 | | − * status field above. |
| 99 | + * The status field in zone_append_in_hdr must always |
| 100 | + * be the last byte. |
| 102 | 101 | */ |
| 103 | 102 | struct { |
| 103 | + __virtio64 sector; |
| 104 | 104 | u8 status; |
| 105 | | − u8 reserved[7]; |
| 106 | | − __le64 append_sector; |
| 107 | | − } zone_append_in_hdr; |
| 108 | | − }; |
| 105 | + } zone_append; |
| 106 | + } in_hdr; |
| 109 | 107 | |
| 110 | 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 | 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 | 156 | sgs[num_out + num_in++] = &in_hdr; |
| 159 | 157 | |
| 160 | 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 | 240 | struct request *req, |
| 243 | 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 | 244 | bool unmap = false; |
| 247 | 245 | u32 type; |
| 248 | 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 | 251 | /* Set fields for all request types */ |
| 251 | 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 | 288 | case REQ_OP_ZONE_APPEND: |
| 288 | 289 | type = VIRTIO_BLK_T_ZONE_APPEND; |
| 289 | 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 | 292 | break; |
| 292 | 293 | case REQ_OP_ZONE_RESET: |
| 293 | 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 | 298 | type = VIRTIO_BLK_T_ZONE_RESET_ALL; |
| 298 | 299 | break; |
| 299 | 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 | 305 | return 0; |
| 302 | 306 | default: |
| 303 | 307 | WARN_ON_ONCE(1); |
| @@ -318,16 +322,28 @@ static blk_status_t virtblk_setup_cmd(struct virtio_device *vdev, · 14 unmodified lines |
| 318 | 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 | 335 | static inline void virtblk_request_done(struct request *req) |
| 322 | 336 | { |
| 323 | 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 | 341 | virtblk_unmap_data(req, vbr); |
| 327 | 342 | virtblk_cleanup_cmd(req); |
| 328 | 343 | |
| 329 | 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 | 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 | 372 | if (likely(!blk_should_fake_timeout(req->q)) && |
| 357 | 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 | 375 | virtblk_complete_batch)) |
| 360 | 376 | virtblk_request_done(req); |
| 361 | 377 | req_done++; |
| @@ -550,7 +566,6 @@ static void virtio_queue_rqs(struct request **rqlist) · 188 unmodified lines |
| 550 | 566 | #ifdef CONFIG_BLK_DEV_ZONED |
| 551 | 567 | static void *virtblk_alloc_report_buffer(struct virtio_blk *vblk, |
| 552 | 568 | unsigned int nr_zones, |
| 553 | | − unsigned int zone_sectors, |
| 554 | 569 | size_t *buflen) |
| 555 | 570 | { |
| 556 | 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 | 573 | void *buf; |
| 559 | 574 | |
| 560 | 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 | 578 | bufsize = sizeof(struct virtio_blk_zone_report) + |
| 564 | 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 | 607 | return PTR_ERR(req); |
| 593 | 608 | |
| 594 | 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 | 611 | vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_ZONE_REPORT); |
| 597 | 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 | 616 | goto out; |
| 602 | 617 | |
| 603 | 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 | 620 | out: |
| 606 | 621 | blk_mq_free_request(req); |
| 607 | 622 | return err; |
| @@ -609,29 +624,72 @@ out: · 1 unmodified line |
| 609 | 624 | |
| 610 | 625 | static int virtblk_parse_zone(struct virtio_blk *vblk, |
| 611 | 626 | struct virtio_blk_zone_descriptor *entry, |
| 612 | | − unsigned int idx, unsigned int zone_sectors, |
| 613 | | − report_zones_cb cb, void *data) |
| 627 | + unsigned int idx, report_zones_cb cb, void *data) |
| 614 | 628 | { |
| 615 | 629 | struct blk_zone zone = { }; |
| 616 | 630 | |
| 617 | | − if (entry->z_type != VIRTIO_BLK_ZT_SWR && |
| 618 | | − entry->z_type != VIRTIO_BLK_ZT_SWP && |
| 619 | | − entry->z_type != VIRTIO_BLK_ZT_CONV) { |
| 620 | | − dev_err(&vblk->vdev->dev, "invalid zone type %#x\n", |
| 621 | | − entry->z_type); |
| 622 | | − return -EINVAL; |
| 631 | + zone.start = virtio64_to_cpu(vblk->vdev, entry->z_start); |
| 632 | + if (zone.start + vblk->zone_sectors <= get_capacity(vblk->disk)) |
| 633 | + zone.len = vblk->zone_sectors; |
| 634 | + else |
| 635 | + zone.len = get_capacity(vblk->disk) - zone.start; |
| 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; |
| 626 | | − zone.cond = entry->z_state; |
| 627 | | − zone.len = zone_sectors; |
| 628 | | − zone.capacity = le64_to_cpu(entry->z_cap); |
| 629 | | − zone.start = le64_to_cpu(entry->z_start); |
| 630 | | − if (zone.cond == BLK_ZONE_COND_FULL) |
| 655 | + switch (entry->z_state) { |
| 656 | + case VIRTIO_BLK_ZS_EMPTY: |
| 657 | + zone.cond = BLK_ZONE_COND_EMPTY; |
| 658 | + break; |
| 659 | + case VIRTIO_BLK_ZS_CLOSED: |
| 660 | + zone.cond = BLK_ZONE_COND_CLOSED; |
| 661 | + break; |
| 662 | + case VIRTIO_BLK_ZS_FULL: |
| 663 | + zone.cond = BLK_ZONE_COND_FULL; |
| 631 | 664 | zone.wp = zone.start + zone.len; |
| 632 | | − else |
| 633 | | − zone.wp = le64_to_cpu(entry->z_wp); |
| 665 | + break; |
| 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 | 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 | 700 | struct virtio_blk *vblk = disk->private_data; |
| 643 | 701 | struct virtio_blk_zone_report *report; |
| 644 | | − unsigned int zone_sectors = vblk->zone_sectors; |
| 645 | | − unsigned int nz, i; |
| 646 | | − int ret, zone_idx = 0; |
| 702 | + unsigned long long nz, i; |
| 647 | 703 | size_t buflen; |
| 704 | + unsigned int zone_idx = 0; |
| 705 | + int ret; |
| 648 | 706 | |
| 649 | 707 | if (WARN_ON_ONCE(!vblk->zone_sectors)) |
| 650 | 708 | return -EOPNOTSUPP; |
| 651 | 709 | |
| 652 | | − report = virtblk_alloc_report_buffer(vblk, nr_zones, |
| 653 | | − zone_sectors, &buflen); |
| 710 | + report = virtblk_alloc_report_buffer(vblk, nr_zones, &buflen); |
| 654 | 711 | if (!report) |
| 655 | 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 | 721 | while (zone_idx < nr_zones && sector < get_capacity(vblk->disk)) { |
| 658 | 722 | memset(report, 0, buflen); |
| 659 | 723 | |
| 660 | 724 | ret = virtblk_submit_zone_report(vblk, (char *)report, |
| 661 | 725 | buflen, sector); |
| 662 | | − if (ret) { |
| 663 | | − if (ret > 0) |
| 664 | | − ret = -EIO; |
| 665 | | − goto out_free; |
| 666 | | − } |
| 667 | | − nz = min((unsigned int)le64_to_cpu(report->nr_zones), nr_zones); |
| 726 | + if (ret) |
| 727 | + goto fail_report; |
| 728 | + |
| 729 | + nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones), |
| 730 | + nr_zones); |
| 668 | 731 | if (!nz) |
| 669 | 732 | break; |
| 670 | 733 | |
| 671 | 734 | for (i = 0; i < nz && zone_idx < nr_zones; i++) { |
| 672 | 735 | ret = virtblk_parse_zone(vblk, &report->zones[i], |
| 673 | | − zone_idx, zone_sectors, cb, data); |
| 736 | + zone_idx, cb, data); |
| 674 | 737 | if (ret) |
| 675 | | − goto out_free; |
| 676 | | − sector = le64_to_cpu(report->zones[i].z_start) + zone_sectors; |
| 738 | + goto fail_report; |
| 739 | + |
| 740 | + sector = virtio64_to_cpu(vblk->vdev, |
| 741 | + report->zones[i].z_start) + |
| 742 | + vblk->zone_sectors; |
| 677 | 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 | 748 | ret = zone_idx; |
| 683 | 749 | else |
| 684 | 750 | ret = -EINVAL; |
| 685 | | −out_free: |
| 751 | +fail_report: |
| 752 | + mutex_unlock(&vblk->vdev_mutex); |
| 686 | 753 | kvfree(report); |
| 687 | 754 | return ret; |
| 688 | 755 | } |
| @@ -691,20 +758,28 @@ static void virtblk_revalidate_zones(struct virtio_blk *vblk) · 2 unmodified lines |
| 691 | 758 | { |
| 692 | 759 | u8 model; |
| 693 | 760 | |
| 694 | | − if (!vblk->zone_sectors) |
| 695 | | − return; |
| 696 | | − |
| 697 | 761 | virtio_cread(vblk->vdev, struct virtio_blk_config, |
| 698 | 762 | zoned.model, &model); |
| 699 | | − if (!blk_revalidate_disk_zones(vblk->disk, NULL)) |
| 700 | | − set_capacity_and_notify(vblk->disk, 0); |
| 763 | + switch (model) { |
| 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 | 778 | static int virtblk_probe_zoned_device(struct virtio_device *vdev, |
| 704 | 779 | struct virtio_blk *vblk, |
| 705 | 780 | struct request_queue *q) |
| 706 | 781 | { |
| 707 | | − u32 v; |
| 782 | + u32 v, wg; |
| 708 | 783 | u8 model; |
| 709 | 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 | 789 | switch (model) { |
| 715 | 790 | case VIRTIO_BLK_Z_NONE: |
| 791 | + case VIRTIO_BLK_Z_HA: |
| 792 | + /* Present the host-aware device as non-zoned */ |
| 716 | 793 | return 0; |
| 717 | 794 | case VIRTIO_BLK_Z_HM: |
| 718 | 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 | 796 | default: |
| 727 | 797 | dev_err(&vdev->dev, "unsupported zone model %d\n", model); |
| 728 | 798 | return -EINVAL; |
| @@ -735,32 +805,31 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, · 6 unmodified lines |
| 735 | 805 | |
| 736 | 806 | virtio_cread(vdev, struct virtio_blk_config, |
| 737 | 807 | zoned.max_open_zones, &v); |
| 738 | | − disk_set_max_open_zones(vblk->disk, le32_to_cpu(v)); |
| 739 | | − |
| 740 | | − dev_dbg(&vdev->dev, "max open zones = %u\n", le32_to_cpu(v)); |
| 808 | + disk_set_max_open_zones(vblk->disk, v); |
| 809 | + dev_dbg(&vdev->dev, "max open zones = %u\n", v); |
| 741 | 810 | |
| 742 | 811 | virtio_cread(vdev, struct virtio_blk_config, |
| 743 | 812 | zoned.max_active_zones, &v); |
| 744 | | − disk_set_max_active_zones(vblk->disk, le32_to_cpu(v)); |
| 745 | | − dev_dbg(&vdev->dev, "max active zones = %u\n", le32_to_cpu(v)); |
| 813 | + disk_set_max_active_zones(vblk->disk, v); |
| 814 | + dev_dbg(&vdev->dev, "max active zones = %u\n", v); |
| 746 | 815 | |
| 747 | 816 | virtio_cread(vdev, struct virtio_blk_config, |
| 748 | | − zoned.write_granularity, &v); |
| 749 | | − if (!v) { |
| 817 | + zoned.write_granularity, &wg); |
| 818 | + if (!wg) { |
| 750 | 819 | dev_warn(&vdev->dev, "zero write granularity reported\n"); |
| 751 | 820 | return -ENODEV; |
| 752 | 821 | } |
| 753 | | − blk_queue_physical_block_size(q, le32_to_cpu(v)); |
| 754 | | − blk_queue_io_min(q, le32_to_cpu(v)); |
| 822 | + blk_queue_physical_block_size(q, wg); |
| 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 | 828 | * virtio ZBD specification doesn't require zones to be a power of |
| 760 | 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); |
| 763 | | − vblk->zone_sectors = le32_to_cpu(v); |
| 831 | + virtio_cread(vdev, struct virtio_blk_config, zoned.zone_sectors, |
| 832 | + &vblk->zone_sectors); |
| 764 | 833 | if (vblk->zone_sectors == 0 || !is_power_of_2(vblk->zone_sectors)) { |
| 765 | 834 | dev_err(&vdev->dev, |
| 766 | 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 | 852 | dev_warn(&vdev->dev, "zero max_append_sectors reported\n"); |
| 784 | 853 | return -ENODEV; |
| 785 | 854 | } |
| 786 | | − blk_queue_max_zone_append_sectors(q, le32_to_cpu(v)); |
| 787 | | − dev_dbg(&vdev->dev, "max append sectors = %u\n", le32_to_cpu(v)); |
| 855 | + if ((v << SECTOR_SHIFT) < wg) { |
| 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 | 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 | 869 | #else |
| 798 | 870 | |
| 799 | 871 | /* |
| 800 | 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 | 876 | #define virtblk_report_zones NULL |
| 877 | + |
| 804 | 878 | static inline void virtblk_revalidate_zones(struct virtio_blk *vblk) |
| 805 | 879 | { |
| 806 | 880 | } |
| 881 | + |
| 807 | 882 | static inline int virtblk_probe_zoned_device(struct virtio_device *vdev, |
| 808 | 883 | struct virtio_blk *vblk, struct request_queue *q) |
| 809 | 884 | { |
| 810 | | − return -EOPNOTSUPP; |
| 811 | | −} |
| 885 | + u8 model; |
| 812 | 886 | |
| 813 | | −static inline bool virtblk_has_zoned_feature(struct virtio_device *vdev) |
| 814 | | −{ |
| 815 | | − return false; |
| 887 | + virtio_cread(vdev, struct virtio_blk_config, zoned.model, &model); |
| 888 | + if (model == VIRTIO_BLK_Z_HM) { |
| 889 | + dev_err(&vdev->dev, |
| 890 | + "virtio_blk: zoned devices are not supported"); |
| 891 | + return -EOPNOTSUPP; |
| 892 | + } |
| 893 | + |
| 894 | + return 0; |
| 816 | 895 | } |
| 817 | 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 | 910 | return PTR_ERR(req); |
| 832 | 911 | |
| 833 | 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 | 914 | vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID); |
| 836 | 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 | 919 | goto out; |
| 841 | 920 | |
| 842 | 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 | 923 | out: |
| 845 | 924 | blk_mq_free_request(req); |
| 846 | 925 | return err; |
| @@ -1498,15 +1577,16 @@ static int virtblk_probe(struct virtio_device *vdev) · 651 unmodified lines |
| 1498 | 1577 | virtblk_update_capacity(vblk, false); |
| 1499 | 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 | 1585 | err = virtblk_probe_zoned_device(vdev, vblk, q); |
| 1503 | 1586 | if (err) |
| 1504 | 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 | 1590 | err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); |
| 1511 | 1591 | if (err) |
| 1512 | 1592 | goto out_cleanup_disk; |
| @@ -1607,10 +1687,7 @@ static unsigned int features[] = { · 94 unmodified lines |
| 1607 | 1687 | VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, |
| 1608 | 1688 | VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, |
| 1609 | 1689 | VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_WRITE_ZEROES, |
| 1610 | | − VIRTIO_BLK_F_SECURE_ERASE, |
| 1611 | | −#ifdef CONFIG_BLK_DEV_ZONED |
| 1612 | | − VIRTIO_BLK_F_ZONED, |
| 1613 | | −#endif /* CONFIG_BLK_DEV_ZONED */ |
| 1690 | + VIRTIO_BLK_F_SECURE_ERASE, VIRTIO_BLK_F_ZONED, |
| 1614 | 1691 | }; |
| 1615 | 1692 | |
| 1616 | 1693 | static struct virtio_driver virtio_blk = { |