1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Channel Subsystem tests 4 * 5 * Copyright (c) 2020 IBM Corp 6 * 7 * Authors: 8 * Pierre Morel <pmorel@linux.ibm.com> 9 */ 10 11 #include <libcflat.h> 12 #include <alloc_phys.h> 13 #include <asm/page.h> 14 #include <string.h> 15 #include <interrupt.h> 16 #include <asm/arch_def.h> 17 18 #include <malloc_io.h> 19 #include <css.h> 20 #include <asm/barrier.h> 21 22 #define DEFAULT_CU_TYPE 0x3832 /* virtio-ccw */ 23 static unsigned long cu_type = DEFAULT_CU_TYPE; 24 25 static int test_device_sid; 26 static struct senseid *senseid; 27 28 static void test_enumerate(void) 29 { 30 test_device_sid = css_enumerate(); 31 if (test_device_sid & SCHID_ONE) { 32 report(1, "Schid of first I/O device: 0x%08x", test_device_sid); 33 return; 34 } 35 report(0, "No I/O device found"); 36 } 37 38 static void test_enable(void) 39 { 40 int cc; 41 42 if (!test_device_sid) { 43 report_skip("No device"); 44 return; 45 } 46 47 cc = css_enable(test_device_sid, IO_SCH_ISC); 48 49 report(cc == 0, "Enable subchannel %08x", test_device_sid); 50 } 51 52 /* 53 * test_sense 54 * Pre-requisites: 55 * - We need the test device as the first recognized 56 * device by the enumeration. 57 */ 58 static void test_sense(void) 59 { 60 struct ccw1 *ccw; 61 int ret; 62 int len; 63 64 if (!test_device_sid) { 65 report_skip("No device"); 66 return; 67 } 68 69 ret = css_enable(test_device_sid, IO_SCH_ISC); 70 if (ret) { 71 report(0, "Could not enable the subchannel: %08x", 72 test_device_sid); 73 return; 74 } 75 76 ret = register_io_int_func(css_irq_io); 77 if (ret) { 78 report(0, "Could not register IRQ handler"); 79 return; 80 } 81 82 lowcore_ptr->io_int_param = 0; 83 84 senseid = alloc_io_mem(sizeof(*senseid), 0); 85 if (!senseid) { 86 report(0, "Allocation of senseid"); 87 goto error_senseid; 88 } 89 90 ccw = ccw_alloc(CCW_CMD_SENSE_ID, senseid, sizeof(*senseid), CCW_F_SLI); 91 if (!ccw) { 92 report(0, "Allocation of CCW"); 93 goto error_ccw; 94 } 95 96 ret = start_ccw1_chain(test_device_sid, ccw); 97 if (ret) { 98 report(0, "Starting CCW chain"); 99 goto error; 100 } 101 102 if (wait_and_check_io_completion(test_device_sid) < 0) 103 goto error; 104 105 /* Test transfer completion */ 106 report_prefix_push("ssch transfer completion"); 107 108 ret = css_residual_count(test_device_sid); 109 110 if (ret < 0) { 111 report_info("no valid residual count"); 112 } else if (ret != 0) { 113 len = sizeof(*senseid) - ret; 114 if (ret && len < CSS_SENSEID_COMMON_LEN) { 115 report(0, "transferred a too short length: %d", ret); 116 goto error; 117 } else if (ret && len) 118 report_info("transferred a shorter length: %d", len); 119 } 120 121 if (senseid->reserved != 0xff) { 122 report(0, "transferred garbage: 0x%02x", senseid->reserved); 123 goto error; 124 } 125 126 report_prefix_pop(); 127 128 report_info("reserved 0x%02x cu_type 0x%04x cu_model 0x%02x dev_type 0x%04x dev_model 0x%02x", 129 senseid->reserved, senseid->cu_type, senseid->cu_model, 130 senseid->dev_type, senseid->dev_model); 131 132 report(senseid->cu_type == cu_type, "cu_type expected 0x%04x got 0x%04x", 133 (uint16_t)cu_type, senseid->cu_type); 134 135 error: 136 free_io_mem(ccw, sizeof(*ccw)); 137 error_ccw: 138 free_io_mem(senseid, sizeof(*senseid)); 139 error_senseid: 140 unregister_io_int_func(css_irq_io); 141 } 142 143 static struct { 144 const char *name; 145 void (*func)(void); 146 } tests[] = { 147 { "enumerate (stsch)", test_enumerate }, 148 { "enable (msch)", test_enable }, 149 { "sense (ssch/tsch)", test_sense }, 150 { NULL, NULL } 151 }; 152 153 int main(int argc, char *argv[]) 154 { 155 int i; 156 157 report_prefix_push("Channel Subsystem"); 158 enable_io_isc(0x80 >> IO_SCH_ISC); 159 for (i = 0; tests[i].name; i++) { 160 report_prefix_push(tests[i].name); 161 tests[i].func(); 162 report_prefix_pop(); 163 } 164 report_prefix_pop(); 165 166 return report_summary(); 167 } 168