Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi

Pull more SCSI updates from James Bottomley:
"The vfs has long had a write lifetime hint mechanism that gives the
expected longevity on storage of the data being written. f2fs was the
original consumer of this and used the hint for flash data placement
(mostly to avoid write amplification by placing objects with similar
lifetimes in the same erase block).

More recently the SCSI based UFS (Universal Flash Storage) drivers
have wanted to take advantage of this as well, for the same reasons as
f2fs, necessitating plumbing the write hints through the block layer
and then adding it to the SCSI core.

The vfs write_hints already taken plumbs this as far as block and this
completes the SCSI core enabling based on a recently agreed reuse of
the old write command group number. The additions to the scsi_debug
driver are for emulating this property so we can run tests on it in
the absence of an actual UFS device"

* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
scsi: scsi_debug: Maintain write statistics per group number
scsi: scsi_debug: Implement GET STREAM STATUS
scsi: scsi_debug: Implement the IO Advice Hints Grouping mode page
scsi: scsi_debug: Allocate the MODE SENSE response from the heap
scsi: scsi_debug: Rework subpage code error handling
scsi: scsi_debug: Rework page code error handling
scsi: scsi_debug: Support the block limits extension VPD page
scsi: scsi_debug: Reduce code duplication
scsi: sd: Translate data lifetime information
scsi: scsi_proto: Add structures and constants related to I/O groups and streams
scsi: core: Query the Block Limits Extension VPD page

+490 -71
+5
drivers/scsi/Kconfig
··· 241 241 Note that this setting also affects whether resuming from 242 242 system suspend will be performed asynchronously. 243 243 244 + config SCSI_PROTO_TEST 245 + tristate "scsi_proto.h unit tests" if !KUNIT_ALL_TESTS 246 + depends on SCSI && KUNIT 247 + default KUNIT_ALL_TESTS 248 + 244 249 menu "SCSI Transports" 245 250 depends on SCSI 246 251
+2
drivers/scsi/Makefile
··· 24 24 25 25 obj-$(CONFIG_RAID_ATTRS) += raid_class.o 26 26 27 + obj-$(CONFIG_SCSI_PROTO_TEST) += scsi_proto_test.o 28 + 27 29 # --- NOTE ORDERING HERE --- 28 30 # For kernel non-modular link, transport attributes need to 29 31 # be initialised before drivers
+2
drivers/scsi/scsi.c
··· 517 517 scsi_update_vpd_page(sdev, 0xb1, &sdev->vpd_pgb1); 518 518 if (vpd_buf->data[i] == 0xb2) 519 519 scsi_update_vpd_page(sdev, 0xb2, &sdev->vpd_pgb2); 520 + if (vpd_buf->data[i] == 0xb7) 521 + scsi_update_vpd_page(sdev, 0xb7, &sdev->vpd_pgb7); 520 522 } 521 523 kfree(vpd_buf); 522 524 }
+225 -68
drivers/scsi/scsi_debug.c
··· 43 43 #include <linux/prefetch.h> 44 44 #include <linux/debugfs.h> 45 45 #include <linux/async.h> 46 + #include <linux/cleanup.h> 46 47 47 48 #include <net/checksum.h> 48 49 ··· 533 532 static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 534 533 static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 535 534 static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 535 + static int resp_get_stream_status(struct scsi_cmnd *scp, 536 + struct sdebug_dev_info *devip); 536 537 static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 537 538 static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 538 539 static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); ··· 609 606 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 610 607 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 611 608 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ 609 + {0, 0x9e, 0x16, F_SA_LOW | F_D_IN, resp_get_stream_status, NULL, 610 + {16, 0x16, 0, 0, 0xff, 0xff, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 611 + 0, 0} }, /* GET STREAM STATUS */ 612 612 }; 613 613 614 614 static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ ··· 901 895 902 896 static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 903 897 static int poll_queues; /* iouring iopoll interface.*/ 898 + 899 + static atomic_long_t writes_by_group_number[64]; 904 900 905 901 static char sdebug_proc_name[] = MY_NAME; 906 902 static const char *my_name = MY_NAME; ··· 1875 1867 return 0x3c; 1876 1868 } 1877 1869 1870 + #define SDEBUG_BLE_LEN_AFTER_B4 28 /* thus vpage 32 bytes long */ 1871 + 1872 + enum { MAXIMUM_NUMBER_OF_STREAMS = 6, PERMANENT_STREAM_COUNT = 5 }; 1873 + 1874 + /* Block limits extension VPD page (SBC-4) */ 1875 + static int inquiry_vpd_b7(unsigned char *arrb4) 1876 + { 1877 + memset(arrb4, 0, SDEBUG_BLE_LEN_AFTER_B4); 1878 + arrb4[1] = 1; /* Reduced stream control support (RSCS) */ 1879 + put_unaligned_be16(MAXIMUM_NUMBER_OF_STREAMS, &arrb4[2]); 1880 + return SDEBUG_BLE_LEN_AFTER_B4; 1881 + } 1882 + 1878 1883 #define SDEBUG_LONG_INQ_SZ 96 1879 1884 #define SDEBUG_MAX_INQ_ARR_SZ 584 1880 1885 ··· 1924 1903 u32 len; 1925 1904 char lu_id_str[6]; 1926 1905 int host_no = devip->sdbg_host->shost->host_no; 1927 - 1906 + 1907 + arr[1] = cmd[2]; 1928 1908 port_group_id = (((host_no + 1) & 0x7f) << 8) + 1929 1909 (devip->channel & 0x7f); 1930 1910 if (sdebug_vpd_use_hostno == 0) ··· 1936 1914 (devip->target * 1000) - 3; 1937 1915 len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 1938 1916 if (0 == cmd[2]) { /* supported vital product data pages */ 1939 - arr[1] = cmd[2]; /*sanity */ 1940 1917 n = 4; 1941 1918 arr[n++] = 0x0; /* this page */ 1942 1919 arr[n++] = 0x80; /* unit serial number */ ··· 1953 1932 arr[n++] = 0xb2; /* LB Provisioning */ 1954 1933 if (is_zbc) 1955 1934 arr[n++] = 0xb6; /* ZB dev. char. */ 1935 + arr[n++] = 0xb7; /* Block limits extension */ 1956 1936 } 1957 1937 arr[3] = n - 4; /* number of supported VPD pages */ 1958 1938 } else if (0x80 == cmd[2]) { /* unit serial number */ 1959 - arr[1] = cmd[2]; /*sanity */ 1960 1939 arr[3] = len; 1961 1940 memcpy(&arr[4], lu_id_str, len); 1962 1941 } else if (0x83 == cmd[2]) { /* device identification */ 1963 - arr[1] = cmd[2]; /*sanity */ 1964 1942 arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 1965 1943 target_dev_id, lu_id_num, 1966 1944 lu_id_str, len, 1967 1945 &devip->lu_name); 1968 1946 } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1969 - arr[1] = cmd[2]; /*sanity */ 1970 1947 arr[3] = inquiry_vpd_84(&arr[4]); 1971 1948 } else if (0x85 == cmd[2]) { /* Management network addresses */ 1972 - arr[1] = cmd[2]; /*sanity */ 1973 1949 arr[3] = inquiry_vpd_85(&arr[4]); 1974 1950 } else if (0x86 == cmd[2]) { /* extended inquiry */ 1975 - arr[1] = cmd[2]; /*sanity */ 1976 1951 arr[3] = 0x3c; /* number of following entries */ 1977 1952 if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1978 1953 arr[4] = 0x4; /* SPT: GRD_CHK:1 */ ··· 1976 1959 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1977 1960 else 1978 1961 arr[4] = 0x0; /* no protection stuff */ 1979 - arr[5] = 0x7; /* head of q, ordered + simple q's */ 1962 + /* 1963 + * GROUP_SUP=1; HEADSUP=1 (HEAD OF QUEUE); ORDSUP=1 1964 + * (ORDERED queuing); SIMPSUP=1 (SIMPLE queuing). 1965 + */ 1966 + arr[5] = 0x17; 1980 1967 } else if (0x87 == cmd[2]) { /* mode page policy */ 1981 - arr[1] = cmd[2]; /*sanity */ 1982 1968 arr[3] = 0x8; /* number of following entries */ 1983 1969 arr[4] = 0x2; /* disconnect-reconnect mp */ 1984 1970 arr[6] = 0x80; /* mlus, shared */ 1985 1971 arr[8] = 0x18; /* protocol specific lu */ 1986 1972 arr[10] = 0x82; /* mlus, per initiator port */ 1987 1973 } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1988 - arr[1] = cmd[2]; /*sanity */ 1989 1974 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1990 1975 } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ 1991 - arr[1] = cmd[2]; /*sanity */ 1992 1976 n = inquiry_vpd_89(&arr[4]); 1993 1977 put_unaligned_be16(n, arr + 2); 1994 1978 } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ 1995 - arr[1] = cmd[2]; /*sanity */ 1996 1979 arr[3] = inquiry_vpd_b0(&arr[4]); 1997 1980 } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ 1998 - arr[1] = cmd[2]; /*sanity */ 1999 1981 arr[3] = inquiry_vpd_b1(devip, &arr[4]); 2000 1982 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 2001 - arr[1] = cmd[2]; /*sanity */ 2002 1983 arr[3] = inquiry_vpd_b2(&arr[4]); 2003 1984 } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ 2004 - arr[1] = cmd[2]; /*sanity */ 2005 1985 arr[3] = inquiry_vpd_b6(devip, &arr[4]); 1986 + } else if (cmd[2] == 0xb7) { /* block limits extension page */ 1987 + arr[3] = inquiry_vpd_b7(&arr[4]); 2006 1988 } else { 2007 1989 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 2008 1990 kfree(arr); ··· 2570 2554 return sizeof(ctrl_m_pg); 2571 2555 } 2572 2556 2557 + /* IO Advice Hints Grouping mode page */ 2558 + static int resp_grouping_m_pg(unsigned char *p, int pcontrol, int target) 2559 + { 2560 + /* IO Advice Hints Grouping mode page */ 2561 + struct grouping_m_pg { 2562 + u8 page_code; /* OR 0x40 when subpage_code > 0 */ 2563 + u8 subpage_code; 2564 + __be16 page_length; 2565 + u8 reserved[12]; 2566 + struct scsi_io_group_descriptor descr[MAXIMUM_NUMBER_OF_STREAMS]; 2567 + }; 2568 + static const struct grouping_m_pg gr_m_pg = { 2569 + .page_code = 0xa | 0x40, 2570 + .subpage_code = 5, 2571 + .page_length = cpu_to_be16(sizeof(gr_m_pg) - 4), 2572 + .descr = { 2573 + { .st_enble = 1 }, 2574 + { .st_enble = 1 }, 2575 + { .st_enble = 1 }, 2576 + { .st_enble = 1 }, 2577 + { .st_enble = 1 }, 2578 + { .st_enble = 0 }, 2579 + } 2580 + }; 2581 + 2582 + BUILD_BUG_ON(sizeof(struct grouping_m_pg) != 2583 + 16 + MAXIMUM_NUMBER_OF_STREAMS * 16); 2584 + memcpy(p, &gr_m_pg, sizeof(gr_m_pg)); 2585 + if (1 == pcontrol) { 2586 + /* There are no changeable values so clear from byte 4 on. */ 2587 + memset(p + 4, 0, sizeof(gr_m_pg) - 4); 2588 + } 2589 + return sizeof(gr_m_pg); 2590 + } 2573 2591 2574 2592 static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 2575 2593 { /* Informational Exceptions control mode page for mode_sense */ ··· 2677 2627 return sizeof(sas_sha_m_pg); 2678 2628 } 2679 2629 2680 - #define SDEBUG_MAX_MSENSE_SZ 256 2630 + /* PAGE_SIZE is more than necessary but provides room for future expansion. */ 2631 + #define SDEBUG_MAX_MSENSE_SZ PAGE_SIZE 2681 2632 2682 2633 static int resp_mode_sense(struct scsi_cmnd *scp, 2683 2634 struct sdebug_dev_info *devip) ··· 2689 2638 int target_dev_id; 2690 2639 int target = scp->device->id; 2691 2640 unsigned char *ap; 2692 - unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 2641 + unsigned char *arr __free(kfree); 2693 2642 unsigned char *cmd = scp->cmnd; 2694 - bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; 2643 + bool dbd, llbaa, msense_6, is_disk, is_zbc; 2695 2644 2645 + arr = kzalloc(SDEBUG_MAX_MSENSE_SZ, GFP_ATOMIC); 2646 + if (!arr) 2647 + return -ENOMEM; 2696 2648 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 2697 2649 pcontrol = (cmd[2] & 0xc0) >> 6; 2698 2650 pcode = cmd[2] & 0x3f; ··· 2753 2699 ap = arr + offset; 2754 2700 } 2755 2701 2756 - if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2757 - /* TODO: Control Extension page */ 2758 - mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2759 - return check_condition_result; 2760 - } 2761 - bad_pcode = false; 2762 - 2702 + /* 2703 + * N.B. If len>0 before resp_*_pg() call, then form of that call should be: 2704 + * len += resp_*_pg(ap + len, pcontrol, target); 2705 + */ 2763 2706 switch (pcode) { 2764 2707 case 0x1: /* Read-Write error recovery page, direct access */ 2708 + if (subpcode > 0x0 && subpcode < 0xff) 2709 + goto bad_subpcode; 2765 2710 len = resp_err_recov_pg(ap, pcontrol, target); 2766 2711 offset += len; 2767 2712 break; 2768 2713 case 0x2: /* Disconnect-Reconnect page, all devices */ 2714 + if (subpcode > 0x0 && subpcode < 0xff) 2715 + goto bad_subpcode; 2769 2716 len = resp_disconnect_pg(ap, pcontrol, target); 2770 2717 offset += len; 2771 2718 break; 2772 2719 case 0x3: /* Format device page, direct access */ 2720 + if (subpcode > 0x0 && subpcode < 0xff) 2721 + goto bad_subpcode; 2773 2722 if (is_disk) { 2774 2723 len = resp_format_pg(ap, pcontrol, target); 2775 2724 offset += len; 2776 - } else 2777 - bad_pcode = true; 2725 + } else { 2726 + goto bad_pcode; 2727 + } 2778 2728 break; 2779 2729 case 0x8: /* Caching page, direct access */ 2730 + if (subpcode > 0x0 && subpcode < 0xff) 2731 + goto bad_subpcode; 2780 2732 if (is_disk || is_zbc) { 2781 2733 len = resp_caching_pg(ap, pcontrol, target); 2782 2734 offset += len; 2783 - } else 2784 - bad_pcode = true; 2735 + } else { 2736 + goto bad_pcode; 2737 + } 2785 2738 break; 2786 2739 case 0xa: /* Control Mode page, all devices */ 2787 - len = resp_ctrl_m_pg(ap, pcontrol, target); 2740 + switch (subpcode) { 2741 + case 0: 2742 + len = resp_ctrl_m_pg(ap, pcontrol, target); 2743 + break; 2744 + case 0x05: 2745 + len = resp_grouping_m_pg(ap, pcontrol, target); 2746 + break; 2747 + case 0xff: 2748 + len = resp_ctrl_m_pg(ap, pcontrol, target); 2749 + len += resp_grouping_m_pg(ap + len, pcontrol, target); 2750 + break; 2751 + default: 2752 + goto bad_subpcode; 2753 + } 2788 2754 offset += len; 2789 2755 break; 2790 2756 case 0x19: /* if spc==1 then sas phy, control+discover */ 2791 - if ((subpcode > 0x2) && (subpcode < 0xff)) { 2792 - mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2793 - return check_condition_result; 2794 - } 2757 + if (subpcode > 0x2 && subpcode < 0xff) 2758 + goto bad_subpcode; 2795 2759 len = 0; 2796 2760 if ((0x0 == subpcode) || (0xff == subpcode)) 2797 2761 len += resp_sas_sf_m_pg(ap + len, pcontrol, target); ··· 2821 2749 offset += len; 2822 2750 break; 2823 2751 case 0x1c: /* Informational Exceptions Mode page, all devices */ 2752 + if (subpcode > 0x0 && subpcode < 0xff) 2753 + goto bad_subpcode; 2824 2754 len = resp_iec_m_pg(ap, pcontrol, target); 2825 2755 offset += len; 2826 2756 break; 2827 2757 case 0x3f: /* Read all Mode pages */ 2828 - if ((0 == subpcode) || (0xff == subpcode)) { 2829 - len = resp_err_recov_pg(ap, pcontrol, target); 2830 - len += resp_disconnect_pg(ap + len, pcontrol, target); 2831 - if (is_disk) { 2832 - len += resp_format_pg(ap + len, pcontrol, 2833 - target); 2834 - len += resp_caching_pg(ap + len, pcontrol, 2835 - target); 2836 - } else if (is_zbc) { 2837 - len += resp_caching_pg(ap + len, pcontrol, 2838 - target); 2839 - } 2840 - len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2841 - len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2842 - if (0xff == subpcode) { 2843 - len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2844 - target, target_dev_id); 2845 - len += resp_sas_sha_m_spg(ap + len, pcontrol); 2846 - } 2847 - len += resp_iec_m_pg(ap + len, pcontrol, target); 2848 - offset += len; 2849 - } else { 2850 - mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2851 - return check_condition_result; 2758 + if (subpcode > 0x0 && subpcode < 0xff) 2759 + goto bad_subpcode; 2760 + len = resp_err_recov_pg(ap, pcontrol, target); 2761 + len += resp_disconnect_pg(ap + len, pcontrol, target); 2762 + if (is_disk) { 2763 + len += resp_format_pg(ap + len, pcontrol, target); 2764 + len += resp_caching_pg(ap + len, pcontrol, target); 2765 + } else if (is_zbc) { 2766 + len += resp_caching_pg(ap + len, pcontrol, target); 2852 2767 } 2768 + len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2769 + if (0xff == subpcode) 2770 + len += resp_grouping_m_pg(ap + len, pcontrol, target); 2771 + len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2772 + if (0xff == subpcode) { 2773 + len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2774 + target_dev_id); 2775 + len += resp_sas_sha_m_spg(ap + len, pcontrol); 2776 + } 2777 + len += resp_iec_m_pg(ap + len, pcontrol, target); 2778 + offset += len; 2853 2779 break; 2854 2780 default: 2855 - bad_pcode = true; 2856 - break; 2857 - } 2858 - if (bad_pcode) { 2859 - mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2860 - return check_condition_result; 2781 + goto bad_pcode; 2861 2782 } 2862 2783 if (msense_6) 2863 2784 arr[0] = offset - 1; 2864 2785 else 2865 2786 put_unaligned_be16((offset - 2), arr + 0); 2866 2787 return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset)); 2788 + 2789 + bad_pcode: 2790 + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2791 + return check_condition_result; 2792 + 2793 + bad_subpcode: 2794 + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2795 + return check_condition_result; 2867 2796 } 2868 2797 2869 2798 #define SDEBUG_MAX_MSELECT_SZ 512 ··· 3379 3306 3380 3307 /* Returns number of bytes copied or -1 if error. */ 3381 3308 static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 3382 - u32 sg_skip, u64 lba, u32 num, bool do_write) 3309 + u32 sg_skip, u64 lba, u32 num, bool do_write, 3310 + u8 group_number) 3383 3311 { 3384 3312 int ret; 3385 3313 u64 block, rest = 0; ··· 3399 3325 return 0; 3400 3326 if (scp->sc_data_direction != dir) 3401 3327 return -1; 3328 + 3329 + if (do_write && group_number < ARRAY_SIZE(writes_by_group_number)) 3330 + atomic_long_inc(&writes_by_group_number[group_number]); 3331 + 3402 3332 fsp = sip->storep; 3403 3333 3404 3334 block = do_div(lba, sdebug_store_sectors); ··· 3776 3698 } 3777 3699 } 3778 3700 3779 - ret = do_device_access(sip, scp, 0, lba, num, false); 3701 + ret = do_device_access(sip, scp, 0, lba, num, false, 0); 3780 3702 sdeb_read_unlock(sip); 3781 3703 if (unlikely(ret == -1)) 3782 3704 return DID_ERROR << 16; ··· 3961 3883 { 3962 3884 bool check_prot; 3963 3885 u32 num; 3886 + u8 group = 0; 3964 3887 u32 ei_lba; 3965 3888 int ret; 3966 3889 u64 lba; ··· 3973 3894 ei_lba = 0; 3974 3895 lba = get_unaligned_be64(cmd + 2); 3975 3896 num = get_unaligned_be32(cmd + 10); 3897 + group = cmd[14] & 0x3f; 3976 3898 check_prot = true; 3977 3899 break; 3978 3900 case WRITE_10: 3979 3901 ei_lba = 0; 3980 3902 lba = get_unaligned_be32(cmd + 2); 3903 + group = cmd[6] & 0x3f; 3981 3904 num = get_unaligned_be16(cmd + 7); 3982 3905 check_prot = true; 3983 3906 break; ··· 3994 3913 ei_lba = 0; 3995 3914 lba = get_unaligned_be32(cmd + 2); 3996 3915 num = get_unaligned_be32(cmd + 6); 3916 + group = cmd[6] & 0x3f; 3997 3917 check_prot = true; 3998 3918 break; 3999 3919 case 0x53: /* XDWRITEREAD(10) */ 4000 3920 ei_lba = 0; 4001 3921 lba = get_unaligned_be32(cmd + 2); 3922 + group = cmd[6] & 0x1f; 4002 3923 num = get_unaligned_be16(cmd + 7); 4003 3924 check_prot = false; 4004 3925 break; 4005 3926 default: /* assume WRITE(32) */ 3927 + group = cmd[6] & 0x3f; 4006 3928 lba = get_unaligned_be64(cmd + 12); 4007 3929 ei_lba = get_unaligned_be32(cmd + 20); 4008 3930 num = get_unaligned_be32(cmd + 28); ··· 4060 3976 } 4061 3977 } 4062 3978 4063 - ret = do_device_access(sip, scp, 0, lba, num, true); 3979 + ret = do_device_access(sip, scp, 0, lba, num, true, group); 4064 3980 if (unlikely(scsi_debug_lbp())) 4065 3981 map_region(sip, lba, num); 4066 3982 /* If ZBC zone then bump its write pointer */ ··· 4112 4028 u32 lb_size = sdebug_sector_size; 4113 4029 u32 ei_lba; 4114 4030 u64 lba; 4031 + u8 group; 4115 4032 int ret, res; 4116 4033 bool is_16; 4117 4034 static const u32 lrd_size = 32; /* + parameter list header size */ 4118 4035 4119 4036 if (cmd[0] == VARIABLE_LENGTH_CMD) { 4120 4037 is_16 = false; 4038 + group = cmd[6] & 0x3f; 4121 4039 wrprotect = (cmd[10] >> 5) & 0x7; 4122 4040 lbdof = get_unaligned_be16(cmd + 12); 4123 4041 num_lrd = get_unaligned_be16(cmd + 16); ··· 4130 4044 lbdof = get_unaligned_be16(cmd + 4); 4131 4045 num_lrd = get_unaligned_be16(cmd + 8); 4132 4046 bt_len = get_unaligned_be32(cmd + 10); 4047 + group = cmd[14] & 0x3f; 4133 4048 if (unlikely(have_dif_prot)) { 4134 4049 if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 4135 4050 wrprotect) { ··· 4219 4132 } 4220 4133 } 4221 4134 4222 - ret = do_device_access(sip, scp, sg_off, lba, num, true); 4135 + ret = do_device_access(sip, scp, sg_off, lba, num, true, group); 4223 4136 /* If ZBC zone then bump its write pointer */ 4224 4137 if (sdebug_dev_is_zoned(devip)) 4225 4138 zbc_inc_wp(devip, lba, num); ··· 4592 4505 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 4593 4506 4594 4507 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 4508 + } 4509 + 4510 + static int resp_get_stream_status(struct scsi_cmnd *scp, 4511 + struct sdebug_dev_info *devip) 4512 + { 4513 + u16 starting_stream_id, stream_id; 4514 + const u8 *cmd = scp->cmnd; 4515 + u32 alloc_len, offset; 4516 + u8 arr[256] = {}; 4517 + struct scsi_stream_status_header *h = (void *)arr; 4518 + 4519 + starting_stream_id = get_unaligned_be16(cmd + 4); 4520 + alloc_len = get_unaligned_be32(cmd + 10); 4521 + 4522 + if (alloc_len < 8) { 4523 + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 4524 + return check_condition_result; 4525 + } 4526 + 4527 + if (starting_stream_id >= MAXIMUM_NUMBER_OF_STREAMS) { 4528 + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 4529 + return check_condition_result; 4530 + } 4531 + 4532 + /* 4533 + * The GET STREAM STATUS command only reports status information 4534 + * about open streams. Treat the non-permanent stream as open. 4535 + */ 4536 + put_unaligned_be16(MAXIMUM_NUMBER_OF_STREAMS, 4537 + &h->number_of_open_streams); 4538 + 4539 + for (offset = 8, stream_id = starting_stream_id; 4540 + offset + 8 <= min_t(u32, alloc_len, sizeof(arr)) && 4541 + stream_id < MAXIMUM_NUMBER_OF_STREAMS; 4542 + offset += 8, stream_id++) { 4543 + struct scsi_stream_status *stream_status = (void *)arr + offset; 4544 + 4545 + stream_status->perm = stream_id < PERMANENT_STREAM_COUNT; 4546 + put_unaligned_be16(stream_id, 4547 + &stream_status->stream_identifier); 4548 + stream_status->rel_lifetime = stream_id + 1; 4549 + } 4550 + put_unaligned_be32(offset - 8, &h->len); /* PARAMETER DATA LENGTH */ 4551 + 4552 + return fill_from_dev_buffer(scp, arr, min(offset, alloc_len)); 4595 4553 } 4596 4554 4597 4555 static int resp_sync_cache(struct scsi_cmnd *scp, ··· 7314 7182 } 7315 7183 static DRIVER_ATTR_RO(tur_ms_to_ready); 7316 7184 7185 + static ssize_t group_number_stats_show(struct device_driver *ddp, char *buf) 7186 + { 7187 + char *p = buf, *end = buf + PAGE_SIZE; 7188 + int i; 7189 + 7190 + for (i = 0; i < ARRAY_SIZE(writes_by_group_number); i++) 7191 + p += scnprintf(p, end - p, "%d %ld\n", i, 7192 + atomic_long_read(&writes_by_group_number[i])); 7193 + 7194 + return p - buf; 7195 + } 7196 + 7197 + static ssize_t group_number_stats_store(struct device_driver *ddp, 7198 + const char *buf, size_t count) 7199 + { 7200 + int i; 7201 + 7202 + for (i = 0; i < ARRAY_SIZE(writes_by_group_number); i++) 7203 + atomic_long_set(&writes_by_group_number[i], 0); 7204 + 7205 + return count; 7206 + } 7207 + static DRIVER_ATTR_RW(group_number_stats); 7208 + 7317 7209 /* Note: The following array creates attribute files in the 7318 7210 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 7319 7211 files (over those found in the /sys/module/scsi_debug/parameters ··· 7384 7228 &driver_attr_cdb_len.attr, 7385 7229 &driver_attr_tur_ms_to_ready.attr, 7386 7230 &driver_attr_zbc.attr, 7231 + &driver_attr_group_number_stats.attr, 7387 7232 NULL, 7388 7233 }; 7389 7234 ATTRIBUTE_GROUPS(sdebug_drv);
+56
drivers/scsi/scsi_proto_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright 2023 Google LLC 4 + */ 5 + #include <kunit/test.h> 6 + #include <asm-generic/unaligned.h> 7 + #include <scsi/scsi_proto.h> 8 + 9 + static void test_scsi_proto(struct kunit *test) 10 + { 11 + static const union { 12 + struct scsi_io_group_descriptor desc; 13 + u8 arr[sizeof(struct scsi_io_group_descriptor)]; 14 + } d = { .arr = { 0x45, 0, 0, 0, 0xb0, 0xe4, 0xe3 } }; 15 + KUNIT_EXPECT_EQ(test, d.desc.io_advice_hints_mode + 0, 1); 16 + KUNIT_EXPECT_EQ(test, d.desc.st_enble + 0, 1); 17 + KUNIT_EXPECT_EQ(test, d.desc.cs_enble + 0, 0); 18 + KUNIT_EXPECT_EQ(test, d.desc.ic_enable + 0, 1); 19 + KUNIT_EXPECT_EQ(test, d.desc.acdlu + 0, 1); 20 + KUNIT_EXPECT_EQ(test, d.desc.rlbsr + 0, 3); 21 + KUNIT_EXPECT_EQ(test, d.desc.lbm_descriptor_type + 0, 0); 22 + KUNIT_EXPECT_EQ(test, d.desc.params[0] + 0, 0xe4); 23 + KUNIT_EXPECT_EQ(test, d.desc.params[1] + 0, 0xe3); 24 + 25 + static const union { 26 + struct scsi_stream_status s; 27 + u8 arr[sizeof(struct scsi_stream_status)]; 28 + } ss = { .arr = { 0x80, 0, 0x12, 0x34, 0x3f } }; 29 + KUNIT_EXPECT_EQ(test, ss.s.perm + 0, 1); 30 + KUNIT_EXPECT_EQ(test, get_unaligned_be16(&ss.s.stream_identifier), 31 + 0x1234); 32 + KUNIT_EXPECT_EQ(test, ss.s.rel_lifetime + 0, 0x3f); 33 + 34 + static const union { 35 + struct scsi_stream_status_header h; 36 + u8 arr[sizeof(struct scsi_stream_status_header)]; 37 + } sh = { .arr = { 1, 2, 3, 4, 0, 0, 5, 6 } }; 38 + KUNIT_EXPECT_EQ(test, get_unaligned_be32(&sh.h.len), 0x1020304); 39 + KUNIT_EXPECT_EQ(test, get_unaligned_be16(&sh.h.number_of_open_streams), 40 + 0x506); 41 + } 42 + 43 + static struct kunit_case scsi_proto_test_cases[] = { 44 + KUNIT_CASE(test_scsi_proto), 45 + {} 46 + }; 47 + 48 + static struct kunit_suite scsi_proto_test_suite = { 49 + .name = "scsi_proto", 50 + .test_cases = scsi_proto_test_cases, 51 + }; 52 + kunit_test_suite(scsi_proto_test_suite); 53 + 54 + MODULE_DESCRIPTION("<scsi/scsi_proto.h> unit tests"); 55 + MODULE_AUTHOR("Bart Van Assche"); 56 + MODULE_LICENSE("GPL");
+10
drivers/scsi/scsi_sysfs.c
··· 449 449 struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL; 450 450 struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL; 451 451 struct scsi_vpd *vpd_pgb0 = NULL, *vpd_pgb1 = NULL, *vpd_pgb2 = NULL; 452 + struct scsi_vpd *vpd_pgb7 = NULL; 452 453 unsigned long flags; 453 454 454 455 might_sleep(); ··· 495 494 lockdep_is_held(&sdev->inquiry_mutex)); 496 495 vpd_pgb2 = rcu_replace_pointer(sdev->vpd_pgb2, vpd_pgb2, 497 496 lockdep_is_held(&sdev->inquiry_mutex)); 497 + vpd_pgb7 = rcu_replace_pointer(sdev->vpd_pgb7, vpd_pgb7, 498 + lockdep_is_held(&sdev->inquiry_mutex)); 498 499 mutex_unlock(&sdev->inquiry_mutex); 499 500 500 501 if (vpd_pg0) ··· 513 510 kfree_rcu(vpd_pgb1, rcu); 514 511 if (vpd_pgb2) 515 512 kfree_rcu(vpd_pgb2, rcu); 513 + if (vpd_pgb7) 514 + kfree_rcu(vpd_pgb7, rcu); 516 515 kfree(sdev->inquiry); 517 516 kfree(sdev); 518 517 ··· 926 921 sdev_vpd_pg_attr(pgb0); 927 922 sdev_vpd_pg_attr(pgb1); 928 923 sdev_vpd_pg_attr(pgb2); 924 + sdev_vpd_pg_attr(pgb7); 929 925 sdev_vpd_pg_attr(pg0); 930 926 931 927 static ssize_t show_inquiry(struct file *filep, struct kobject *kobj, ··· 1301 1295 if (attr == &dev_attr_vpd_pgb2 && !sdev->vpd_pgb2) 1302 1296 return 0; 1303 1297 1298 + if (attr == &dev_attr_vpd_pgb7 && !sdev->vpd_pgb7) 1299 + return 0; 1300 + 1304 1301 return S_IRUGO; 1305 1302 } 1306 1303 ··· 1356 1347 &dev_attr_vpd_pgb0, 1357 1348 &dev_attr_vpd_pgb1, 1358 1349 &dev_attr_vpd_pgb2, 1350 + &dev_attr_vpd_pgb7, 1359 1351 &dev_attr_inquiry, 1360 1352 NULL 1361 1353 };
+108 -3
drivers/scsi/sd.c
··· 47 47 #include <linux/blkpg.h> 48 48 #include <linux/blk-pm.h> 49 49 #include <linux/delay.h> 50 + #include <linux/rw_hint.h> 50 51 #include <linux/major.h> 51 52 #include <linux/mutex.h> 52 53 #include <linux/string_helpers.h> ··· 1081 1080 return BLK_STS_OK; 1082 1081 } 1083 1082 1083 + /** 1084 + * sd_group_number() - Compute the GROUP NUMBER field 1085 + * @cmd: SCSI command for which to compute the value of the six-bit GROUP NUMBER 1086 + * field. 1087 + * 1088 + * From SBC-5 r05 (https://www.t10.org/cgi-bin/ac.pl?t=f&f=sbc5r05.pdf): 1089 + * 0: no relative lifetime. 1090 + * 1: shortest relative lifetime. 1091 + * 2: second shortest relative lifetime. 1092 + * 3 - 0x3d: intermediate relative lifetimes. 1093 + * 0x3e: second longest relative lifetime. 1094 + * 0x3f: longest relative lifetime. 1095 + */ 1096 + static u8 sd_group_number(struct scsi_cmnd *cmd) 1097 + { 1098 + const struct request *rq = scsi_cmd_to_rq(cmd); 1099 + struct scsi_disk *sdkp = scsi_disk(rq->q->disk); 1100 + 1101 + if (!sdkp->rscs) 1102 + return 0; 1103 + 1104 + return min3((u32)rq->write_hint, (u32)sdkp->permanent_stream_count, 1105 + 0x3fu); 1106 + } 1107 + 1084 1108 static blk_status_t sd_setup_rw32_cmnd(struct scsi_cmnd *cmd, bool write, 1085 1109 sector_t lba, unsigned int nr_blocks, 1086 1110 unsigned char flags, unsigned int dld) 1087 1111 { 1088 1112 cmd->cmd_len = SD_EXT_CDB_SIZE; 1089 1113 cmd->cmnd[0] = VARIABLE_LENGTH_CMD; 1114 + cmd->cmnd[6] = sd_group_number(cmd); 1090 1115 cmd->cmnd[7] = 0x18; /* Additional CDB len */ 1091 1116 cmd->cmnd[9] = write ? WRITE_32 : READ_32; 1092 1117 cmd->cmnd[10] = flags; ··· 1131 1104 cmd->cmd_len = 16; 1132 1105 cmd->cmnd[0] = write ? WRITE_16 : READ_16; 1133 1106 cmd->cmnd[1] = flags | ((dld >> 2) & 0x01); 1134 - cmd->cmnd[14] = (dld & 0x03) << 6; 1107 + cmd->cmnd[14] = ((dld & 0x03) << 6) | sd_group_number(cmd); 1135 1108 cmd->cmnd[15] = 0; 1136 1109 put_unaligned_be64(lba, &cmd->cmnd[2]); 1137 1110 put_unaligned_be32(nr_blocks, &cmd->cmnd[10]); ··· 1146 1119 cmd->cmd_len = 10; 1147 1120 cmd->cmnd[0] = write ? WRITE_10 : READ_10; 1148 1121 cmd->cmnd[1] = flags; 1149 - cmd->cmnd[6] = 0; 1122 + cmd->cmnd[6] = sd_group_number(cmd); 1150 1123 cmd->cmnd[9] = 0; 1151 1124 put_unaligned_be32(lba, &cmd->cmnd[2]); 1152 1125 put_unaligned_be16(nr_blocks, &cmd->cmnd[7]); ··· 1283 1256 ret = sd_setup_rw16_cmnd(cmd, write, lba, nr_blocks, 1284 1257 protect | fua, dld); 1285 1258 } else if ((nr_blocks > 0xff) || (lba > 0x1fffff) || 1286 - sdp->use_10_for_rw || protect) { 1259 + sdp->use_10_for_rw || protect || rq->write_hint) { 1287 1260 ret = sd_setup_rw10_cmnd(cmd, write, lba, nr_blocks, 1288 1261 protect | fua); 1289 1262 } else { ··· 3086 3059 sdkp->DPOFUA = 0; 3087 3060 } 3088 3061 3062 + static bool sd_is_perm_stream(struct scsi_disk *sdkp, unsigned int stream_id) 3063 + { 3064 + u8 cdb[16] = { SERVICE_ACTION_IN_16, SAI_GET_STREAM_STATUS }; 3065 + struct { 3066 + struct scsi_stream_status_header h; 3067 + struct scsi_stream_status s; 3068 + } buf; 3069 + struct scsi_device *sdev = sdkp->device; 3070 + struct scsi_sense_hdr sshdr; 3071 + const struct scsi_exec_args exec_args = { 3072 + .sshdr = &sshdr, 3073 + }; 3074 + int res; 3075 + 3076 + put_unaligned_be16(stream_id, &cdb[4]); 3077 + put_unaligned_be32(sizeof(buf), &cdb[10]); 3078 + 3079 + res = scsi_execute_cmd(sdev, cdb, REQ_OP_DRV_IN, &buf, sizeof(buf), 3080 + SD_TIMEOUT, sdkp->max_retries, &exec_args); 3081 + if (res < 0) 3082 + return false; 3083 + if (scsi_status_is_check_condition(res) && scsi_sense_valid(&sshdr)) 3084 + sd_print_sense_hdr(sdkp, &sshdr); 3085 + if (res) 3086 + return false; 3087 + if (get_unaligned_be32(&buf.h.len) < sizeof(struct scsi_stream_status)) 3088 + return false; 3089 + return buf.h.stream_status[0].perm; 3090 + } 3091 + 3092 + static void sd_read_io_hints(struct scsi_disk *sdkp, unsigned char *buffer) 3093 + { 3094 + struct scsi_device *sdp = sdkp->device; 3095 + const struct scsi_io_group_descriptor *desc, *start, *end; 3096 + struct scsi_sense_hdr sshdr; 3097 + struct scsi_mode_data data; 3098 + int res; 3099 + 3100 + res = scsi_mode_sense(sdp, /*dbd=*/0x8, /*modepage=*/0x0a, 3101 + /*subpage=*/0x05, buffer, SD_BUF_SIZE, SD_TIMEOUT, 3102 + sdkp->max_retries, &data, &sshdr); 3103 + if (res < 0) 3104 + return; 3105 + start = (void *)buffer + data.header_length + 16; 3106 + end = (void *)buffer + ALIGN_DOWN(data.header_length + data.length, 3107 + sizeof(*end)); 3108 + /* 3109 + * From "SBC-5 Constrained Streams with Data Lifetimes": Device severs 3110 + * should assign the lowest numbered stream identifiers to permanent 3111 + * streams. 3112 + */ 3113 + for (desc = start; desc < end; desc++) 3114 + if (!desc->st_enble || !sd_is_perm_stream(sdkp, desc - start)) 3115 + break; 3116 + sdkp->permanent_stream_count = desc - start; 3117 + if (sdkp->rscs && sdkp->permanent_stream_count < 2) 3118 + sd_printk(KERN_INFO, sdkp, 3119 + "Unexpected: RSCS has been set and the permanent stream count is %u\n", 3120 + sdkp->permanent_stream_count); 3121 + else if (sdkp->permanent_stream_count) 3122 + sd_printk(KERN_INFO, sdkp, "permanent stream count = %d\n", 3123 + sdkp->permanent_stream_count); 3124 + } 3125 + 3089 3126 /* 3090 3127 * The ATO bit indicates whether the DIF application tag is available 3091 3128 * for use by the operating system. ··· 3254 3163 } 3255 3164 3256 3165 out: 3166 + rcu_read_unlock(); 3167 + } 3168 + 3169 + /* Parse the Block Limits Extension VPD page (0xb7) */ 3170 + static void sd_read_block_limits_ext(struct scsi_disk *sdkp) 3171 + { 3172 + struct scsi_vpd *vpd; 3173 + 3174 + rcu_read_lock(); 3175 + vpd = rcu_dereference(sdkp->device->vpd_pgb7); 3176 + if (vpd && vpd->len >= 2) 3177 + sdkp->rscs = vpd->data[5] & 1; 3257 3178 rcu_read_unlock(); 3258 3179 } 3259 3180 ··· 3644 3541 if (scsi_device_supports_vpd(sdp)) { 3645 3542 sd_read_block_provisioning(sdkp); 3646 3543 sd_read_block_limits(sdkp); 3544 + sd_read_block_limits_ext(sdkp); 3647 3545 sd_read_block_characteristics(sdkp); 3648 3546 sd_zbc_read_zones(sdkp, buffer); 3649 3547 sd_read_cpr(sdkp); ··· 3654 3550 3655 3551 sd_read_write_protect_flag(sdkp, buffer); 3656 3552 sd_read_cache_type(sdkp, buffer); 3553 + sd_read_io_hints(sdkp, buffer); 3657 3554 sd_read_app_tag_own(sdkp, buffer); 3658 3555 sd_read_write_same(sdkp, buffer); 3659 3556 sd_read_security(sdkp, buffer);
+3
drivers/scsi/sd.h
··· 125 125 unsigned int physical_block_size; 126 126 unsigned int max_medium_access_timeouts; 127 127 unsigned int medium_access_timed_out; 128 + /* number of permanent streams */ 129 + u16 permanent_stream_count; 128 130 u8 media_present; 129 131 u8 write_prot; 130 132 u8 protection_type;/* Data Integrity Field */ ··· 153 151 unsigned urswrz : 1; 154 152 unsigned security : 1; 155 153 unsigned ignore_medium_access_errors : 1; 154 + unsigned rscs : 1; /* reduced stream control support */ 156 155 }; 157 156 #define to_scsi_disk(obj) container_of(obj, struct scsi_disk, disk_dev) 158 157
+1
include/scsi/scsi_device.h
··· 149 149 struct scsi_vpd __rcu *vpd_pgb0; 150 150 struct scsi_vpd __rcu *vpd_pgb1; 151 151 struct scsi_vpd __rcu *vpd_pgb2; 152 + struct scsi_vpd __rcu *vpd_pgb7; 152 153 153 154 struct scsi_target *sdev_target; 154 155
+78
include/scsi/scsi_proto.h
··· 10 10 #ifndef _SCSI_PROTO_H_ 11 11 #define _SCSI_PROTO_H_ 12 12 13 + #include <linux/build_bug.h> 13 14 #include <linux/types.h> 14 15 15 16 /* ··· 127 126 #define SAI_READ_CAPACITY_16 0x10 128 127 #define SAI_GET_LBA_STATUS 0x12 129 128 #define SAI_REPORT_REFERRALS 0x13 129 + #define SAI_GET_STREAM_STATUS 0x16 130 130 /* values for maintenance in */ 131 131 #define MI_REPORT_IDENTIFYING_INFORMATION 0x05 132 132 #define MI_REPORT_TARGET_PGS 0x0a ··· 276 274 struct scsi_lun { 277 275 __u8 scsi_lun[8]; 278 276 }; 277 + 278 + /* SBC-5 IO advice hints group descriptor */ 279 + struct scsi_io_group_descriptor { 280 + #if defined(__BIG_ENDIAN) 281 + u8 io_advice_hints_mode: 2; 282 + u8 reserved1: 3; 283 + u8 st_enble: 1; 284 + u8 cs_enble: 1; 285 + u8 ic_enable: 1; 286 + #elif defined(__LITTLE_ENDIAN) 287 + u8 ic_enable: 1; 288 + u8 cs_enble: 1; 289 + u8 st_enble: 1; 290 + u8 reserved1: 3; 291 + u8 io_advice_hints_mode: 2; 292 + #else 293 + #error 294 + #endif 295 + u8 reserved2[3]; 296 + /* Logical block markup descriptor */ 297 + #if defined(__BIG_ENDIAN) 298 + u8 acdlu: 1; 299 + u8 reserved3: 1; 300 + u8 rlbsr: 2; 301 + u8 lbm_descriptor_type: 4; 302 + #elif defined(__LITTLE_ENDIAN) 303 + u8 lbm_descriptor_type: 4; 304 + u8 rlbsr: 2; 305 + u8 reserved3: 1; 306 + u8 acdlu: 1; 307 + #else 308 + #error 309 + #endif 310 + u8 params[2]; 311 + u8 reserved4; 312 + u8 reserved5[8]; 313 + }; 314 + 315 + static_assert(sizeof(struct scsi_io_group_descriptor) == 16); 316 + 317 + /* SCSI stream status descriptor */ 318 + struct scsi_stream_status { 319 + #if defined(__BIG_ENDIAN) 320 + u8 perm: 1; 321 + u8 reserved1: 7; 322 + #elif defined(__LITTLE_ENDIAN) 323 + u8 reserved1: 7; 324 + u8 perm: 1; 325 + #else 326 + #error 327 + #endif 328 + u8 reserved2; 329 + __be16 stream_identifier; 330 + #if defined(__BIG_ENDIAN) 331 + u8 reserved3: 2; 332 + u8 rel_lifetime: 6; 333 + #elif defined(__LITTLE_ENDIAN) 334 + u8 rel_lifetime: 6; 335 + u8 reserved3: 2; 336 + #else 337 + #error 338 + #endif 339 + u8 reserved4[3]; 340 + }; 341 + 342 + static_assert(sizeof(struct scsi_stream_status) == 8); 343 + 344 + /* GET STREAM STATUS parameter data */ 345 + struct scsi_stream_status_header { 346 + __be32 len; /* length in bytes of stream_status[] array. */ 347 + u16 reserved; 348 + __be16 number_of_open_streams; 349 + DECLARE_FLEX_ARRAY(struct scsi_stream_status, stream_status); 350 + }; 351 + 352 + static_assert(sizeof(struct scsi_stream_status_header) == 8); 279 353 280 354 /* SPC asymmetric access states */ 281 355 #define SCSI_ACCESS_STATE_OPTIMAL 0x00