1 /*- 2 * Copyright (c) 2020-2021 Emmanuel Vadot <manu@FreeBSD.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 18 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 20 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 #include <sys/param.h> 28 #include <sys/kernel.h> 29 #include <sys/systm.h> 30 #include <sys/malloc.h> 31 #include <sys/mutex.h> 32 33 #include <cam/cam.h> 34 #include <cam/cam_ccb.h> 35 #include <cam/cam_debug.h> 36 #include <cam/cam_sim.h> 37 #include <cam/cam_xpt_sim.h> 38 #include <cam/mmc/mmc_sim.h> 39 40 #include "mmc_sim_if.h" 41 42 static void 43 mmc_cam_default_poll(struct cam_sim *sim) 44 { 45 struct mmc_sim *mmc_sim; 46 47 mmc_sim = cam_sim_softc(sim); 48 MMC_SIM_CAM_POLL(mmc_sim->dev); 49 } 50 51 static void 52 mmc_sim_task(void *arg, int pending) 53 { 54 struct mmc_sim *mmc_sim; 55 struct ccb_trans_settings *cts; 56 int rv; 57 58 mmc_sim = arg; 59 60 if (mmc_sim->ccb == NULL) 61 return; 62 63 cts = &mmc_sim->ccb->cts; 64 switch (mmc_sim->ccb->ccb_h.func_code) { 65 case XPT_MMC_GET_TRAN_SETTINGS: 66 rv = MMC_SIM_GET_TRAN_SETTINGS(mmc_sim->dev, &cts->proto_specific.mmc); 67 if (rv != 0) 68 mmc_sim->ccb->ccb_h.status = CAM_REQ_INVALID; 69 else 70 mmc_sim->ccb->ccb_h.status = CAM_REQ_CMP; 71 break; 72 case XPT_MMC_SET_TRAN_SETTINGS: 73 rv = MMC_SIM_SET_TRAN_SETTINGS(mmc_sim->dev, &cts->proto_specific.mmc); 74 if (rv != 0) 75 mmc_sim->ccb->ccb_h.status = CAM_REQ_INVALID; 76 else 77 mmc_sim->ccb->ccb_h.status = CAM_REQ_CMP; 78 break; 79 default: 80 panic("Unsupported ccb func %x\n", mmc_sim->ccb->ccb_h.func_code); 81 break; 82 } 83 84 xpt_done(mmc_sim->ccb); 85 mmc_sim->ccb = NULL; 86 } 87 88 89 static void 90 mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb) 91 { 92 struct mmc_sim *mmc_sim; 93 struct ccb_trans_settings_mmc mmc; 94 int rv; 95 96 mmc_sim = cam_sim_softc(sim); 97 98 mtx_assert(&mmc_sim->mtx, MA_OWNED); 99 100 if (mmc_sim->ccb != NULL) { 101 ccb->ccb_h.status = CAM_BUSY; 102 xpt_done(ccb); 103 return; 104 } 105 106 switch (ccb->ccb_h.func_code) { 107 case XPT_PATH_INQ: 108 rv = MMC_SIM_GET_TRAN_SETTINGS(mmc_sim->dev, &mmc); 109 if (rv != 0) { 110 ccb->ccb_h.status = CAM_REQ_INVALID; 111 } else { 112 mmc_path_inq(&ccb->cpi, "Deglitch Networks", 113 sim, mmc.host_max_data); 114 } 115 break; 116 case XPT_GET_TRAN_SETTINGS: 117 { 118 struct ccb_trans_settings *cts = &ccb->cts; 119 120 rv = MMC_SIM_GET_TRAN_SETTINGS(mmc_sim->dev, &cts->proto_specific.mmc); 121 if (rv != 0) 122 ccb->ccb_h.status = CAM_REQ_INVALID; 123 else { 124 cts->protocol = PROTO_MMCSD; 125 cts->protocol_version = 1; 126 cts->transport = XPORT_MMCSD; 127 cts->transport_version = 1; 128 cts->xport_specific.valid = 0; 129 ccb->ccb_h.status = CAM_REQ_CMP; 130 } 131 break; 132 } 133 case XPT_MMC_GET_TRAN_SETTINGS: 134 { 135 ccb->ccb_h.status = CAM_SIM_QUEUED; 136 mmc_sim->ccb = ccb; 137 taskqueue_enqueue(taskqueue_thread, &mmc_sim->sim_task); 138 return; 139 /* NOTREACHED */ 140 break; 141 } 142 case XPT_SET_TRAN_SETTINGS: 143 { 144 struct ccb_trans_settings *cts = &ccb->cts; 145 146 rv = MMC_SIM_SET_TRAN_SETTINGS(mmc_sim->dev, &cts->proto_specific.mmc); 147 if (rv != 0) 148 ccb->ccb_h.status = CAM_REQ_INVALID; 149 else 150 ccb->ccb_h.status = CAM_REQ_CMP; 151 break; 152 } 153 case XPT_MMC_SET_TRAN_SETTINGS: 154 { 155 ccb->ccb_h.status = CAM_SIM_QUEUED; 156 mmc_sim->ccb = ccb; 157 taskqueue_enqueue(taskqueue_thread, &mmc_sim->sim_task); 158 return; 159 /* NOTREACHED */ 160 break; 161 } 162 case XPT_RESET_BUS: 163 ccb->ccb_h.status = CAM_REQ_CMP; 164 break; 165 case XPT_MMC_IO: 166 { 167 rv = MMC_SIM_CAM_REQUEST(mmc_sim->dev, ccb); 168 if (rv != 0) 169 ccb->ccb_h.status = CAM_SIM_QUEUED; 170 return; 171 /* NOTREACHED */ 172 break; 173 } 174 default: 175 ccb->ccb_h.status = CAM_REQ_INVALID; 176 break; 177 } 178 xpt_done(ccb); 179 return; 180 } 181 182 int 183 mmc_cam_sim_alloc(device_t dev, const char *name, struct mmc_sim *mmc_sim) 184 { 185 kobjop_desc_t kobj_desc; 186 kobj_method_t *kobj_method; 187 188 mmc_sim->dev = dev; 189 190 if ((mmc_sim->devq = cam_simq_alloc(1)) == NULL) { 191 goto fail; 192 } 193 194 snprintf(mmc_sim->name, sizeof(mmc_sim->name), "%s_sim", name); 195 mtx_init(&mmc_sim->mtx, mmc_sim->name, NULL, MTX_DEF); 196 197 /* Provide sim_poll hook only if the device has the poll method. */ 198 kobj_desc = &mmc_sim_cam_poll_desc; 199 kobj_method = kobj_lookup_method(((kobj_t)dev)->ops->cls, NULL, 200 kobj_desc); 201 mmc_sim->sim = cam_sim_alloc(mmc_cam_sim_default_action, 202 kobj_method == &kobj_desc->deflt ? NULL : mmc_cam_default_poll, 203 mmc_sim->name, mmc_sim, device_get_unit(dev), 204 &mmc_sim->mtx, 1, 1, mmc_sim->devq); 205 206 if (mmc_sim->sim == NULL) { 207 cam_simq_free(mmc_sim->devq); 208 device_printf(dev, "cannot allocate CAM SIM\n"); 209 goto fail; 210 } 211 212 mtx_lock(&mmc_sim->mtx); 213 if (xpt_bus_register(mmc_sim->sim, dev, 0) != 0) { 214 device_printf(dev, "cannot register SCSI pass-through bus\n"); 215 cam_sim_free(mmc_sim->sim, FALSE); 216 cam_simq_free(mmc_sim->devq); 217 mtx_unlock(&mmc_sim->mtx); 218 goto fail; 219 } 220 221 mtx_unlock(&mmc_sim->mtx); 222 TASK_INIT(&mmc_sim->sim_task, 0, mmc_sim_task, mmc_sim); 223 224 return (0); 225 226 fail: 227 mmc_cam_sim_free(mmc_sim); 228 return (1); 229 } 230 231 void 232 mmc_cam_sim_free(struct mmc_sim *mmc_sim) 233 { 234 235 if (mmc_sim->sim != NULL) { 236 mtx_lock(&mmc_sim->mtx); 237 xpt_bus_deregister(cam_sim_path(mmc_sim->sim)); 238 cam_sim_free(mmc_sim->sim, FALSE); 239 mtx_unlock(&mmc_sim->mtx); 240 } 241 242 if (mmc_sim->devq != NULL) 243 cam_simq_free(mmc_sim->devq); 244 } 245 246 void 247 mmc_cam_sim_discover(struct mmc_sim *mmc_sim) 248 { 249 250 mmccam_start_discovery(mmc_sim->sim); 251 } 252