1 /* 2 * Channel Subsystem tests 3 * 4 * Copyright (c) 2020 IBM Corp 5 * 6 * Authors: 7 * Pierre Morel <pmorel@linux.ibm.com> 8 * 9 * This code is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License version 2. 11 */ 12 13 #include <libcflat.h> 14 #include <alloc_phys.h> 15 #include <asm/page.h> 16 #include <string.h> 17 #include <interrupt.h> 18 #include <asm/arch_def.h> 19 20 #include <css.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 int ret; 61 int len; 62 63 if (!test_device_sid) { 64 report_skip("No device"); 65 return; 66 } 67 68 ret = css_enable(test_device_sid, IO_SCH_ISC); 69 if (ret) { 70 report(0, "Could not enable the subchannel: %08x", 71 test_device_sid); 72 return; 73 } 74 75 ret = register_io_int_func(css_irq_io); 76 if (ret) { 77 report(0, "Could not register IRQ handler"); 78 return; 79 } 80 81 lowcore_ptr->io_int_param = 0; 82 83 memset(&senseid, 0, sizeof(senseid)); 84 ret = start_single_ccw(test_device_sid, CCW_CMD_SENSE_ID, 85 &senseid, sizeof(senseid), CCW_F_SLI); 86 if (ret) 87 goto error; 88 89 if (wait_and_check_io_completion(test_device_sid) < 0) 90 goto error; 91 92 /* Test transfer completion */ 93 report_prefix_push("ssch transfer completion"); 94 95 ret = css_residual_count(test_device_sid); 96 97 if (ret < 0) { 98 report_info("no valid residual count"); 99 } else if (ret != 0) { 100 len = sizeof(senseid) - ret; 101 if (ret && len < CSS_SENSEID_COMMON_LEN) { 102 report(0, "transferred a too short length: %d", ret); 103 goto error; 104 } else if (ret && len) 105 report_info("transferred a shorter length: %d", len); 106 } 107 108 if (senseid.reserved != 0xff) { 109 report(0, "transferred garbage: 0x%02x", senseid.reserved); 110 goto error; 111 } 112 113 report_prefix_pop(); 114 115 report_info("reserved 0x%02x cu_type 0x%04x cu_model 0x%02x dev_type 0x%04x dev_model 0x%02x", 116 senseid.reserved, senseid.cu_type, senseid.cu_model, 117 senseid.dev_type, senseid.dev_model); 118 119 report(senseid.cu_type == cu_type, "cu_type expected 0x%04x got 0x%04x", 120 (uint16_t) cu_type, senseid.cu_type); 121 122 error: 123 unregister_io_int_func(css_irq_io); 124 } 125 126 static struct { 127 const char *name; 128 void (*func)(void); 129 } tests[] = { 130 { "enumerate (stsch)", test_enumerate }, 131 { "enable (msch)", test_enable }, 132 { "sense (ssch/tsch)", test_sense }, 133 { NULL, NULL } 134 }; 135 136 int main(int argc, char *argv[]) 137 { 138 int i; 139 140 report_prefix_push("Channel Subsystem"); 141 enable_io_isc(0x80 >> IO_SCH_ISC); 142 for (i = 0; tests[i].name; i++) { 143 report_prefix_push(tests[i].name); 144 tests[i].func(); 145 report_prefix_pop(); 146 } 147 report_prefix_pop(); 148 149 return report_summary(); 150 } 151