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/param.h>
27 #include <sys/kernel.h>
28 #include <sys/systm.h>
29 #include <sys/malloc.h>
30 #include <sys/mutex.h>
31
32 #include <cam/cam.h>
33 #include <cam/cam_ccb.h>
34 #include <cam/cam_debug.h>
35 #include <cam/cam_sim.h>
36 #include <cam/cam_xpt_sim.h>
37 #include <cam/mmc/mmc_sim.h>
38
39 #include "mmc_sim_if.h"
40
41 static void
mmc_cam_default_poll(struct cam_sim * sim)42 mmc_cam_default_poll(struct cam_sim *sim)
43 {
44 struct mmc_sim *mmc_sim;
45
46 mmc_sim = cam_sim_softc(sim);
47 MMC_SIM_CAM_POLL(mmc_sim->dev);
48 }
49
50 static void
mmc_sim_task(void * arg,int pending)51 mmc_sim_task(void *arg, int pending)
52 {
53 struct mmc_sim *mmc_sim;
54 struct ccb_trans_settings *cts;
55 int rv;
56
57 mmc_sim = arg;
58
59 if (mmc_sim->ccb == NULL)
60 return;
61
62 cts = &mmc_sim->ccb->cts;
63 switch (mmc_sim->ccb->ccb_h.func_code) {
64 case XPT_MMC_GET_TRAN_SETTINGS:
65 rv = MMC_SIM_GET_TRAN_SETTINGS(mmc_sim->dev, &cts->proto_specific.mmc);
66 if (rv != 0)
67 mmc_sim->ccb->ccb_h.status = CAM_REQ_INVALID;
68 else
69 mmc_sim->ccb->ccb_h.status = CAM_REQ_CMP;
70 break;
71 case XPT_MMC_SET_TRAN_SETTINGS:
72 rv = MMC_SIM_SET_TRAN_SETTINGS(mmc_sim->dev, &cts->proto_specific.mmc);
73 if (rv != 0)
74 mmc_sim->ccb->ccb_h.status = CAM_REQ_INVALID;
75 else
76 mmc_sim->ccb->ccb_h.status = CAM_REQ_CMP;
77 break;
78 default:
79 panic("Unsupported ccb func %x\n", mmc_sim->ccb->ccb_h.func_code);
80 break;
81 }
82
83 xpt_done(mmc_sim->ccb);
84 mmc_sim->ccb = NULL;
85 }
86
87
88 static void
mmc_cam_sim_default_action(struct cam_sim * sim,union ccb * ccb)89 mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb)
90 {
91 struct mmc_sim *mmc_sim;
92 struct ccb_trans_settings_mmc mmc;
93 int rv;
94
95 mmc_sim = cam_sim_softc(sim);
96
97 mtx_assert(&mmc_sim->mtx, MA_OWNED);
98
99 if (mmc_sim->ccb != NULL) {
100 ccb->ccb_h.status = CAM_BUSY;
101 xpt_done(ccb);
102 return;
103 }
104
105 switch (ccb->ccb_h.func_code) {
106 case XPT_PATH_INQ:
107 rv = MMC_SIM_GET_TRAN_SETTINGS(mmc_sim->dev, &mmc);
108 if (rv != 0) {
109 ccb->ccb_h.status = CAM_REQ_INVALID;
110 } else {
111 mmc_path_inq(&ccb->cpi, "Deglitch Networks",
112 sim, mmc.host_max_data);
113 }
114 break;
115 case XPT_GET_TRAN_SETTINGS:
116 {
117 struct ccb_trans_settings *cts = &ccb->cts;
118
119 rv = MMC_SIM_GET_TRAN_SETTINGS(mmc_sim->dev, &cts->proto_specific.mmc);
120 if (rv != 0)
121 ccb->ccb_h.status = CAM_REQ_INVALID;
122 else {
123 cts->protocol = PROTO_MMCSD;
124 cts->protocol_version = 1;
125 cts->transport = XPORT_MMCSD;
126 cts->transport_version = 1;
127 cts->xport_specific.valid = 0;
128 ccb->ccb_h.status = CAM_REQ_CMP;
129 }
130 break;
131 }
132 case XPT_MMC_GET_TRAN_SETTINGS:
133 {
134 ccb->ccb_h.status = CAM_SIM_QUEUED;
135 mmc_sim->ccb = ccb;
136 taskqueue_enqueue(taskqueue_thread, &mmc_sim->sim_task);
137 return;
138 /* NOTREACHED */
139 break;
140 }
141 case XPT_SET_TRAN_SETTINGS:
142 {
143 struct ccb_trans_settings *cts = &ccb->cts;
144
145 rv = MMC_SIM_SET_TRAN_SETTINGS(mmc_sim->dev, &cts->proto_specific.mmc);
146 if (rv != 0)
147 ccb->ccb_h.status = CAM_REQ_INVALID;
148 else
149 ccb->ccb_h.status = CAM_REQ_CMP;
150 break;
151 }
152 case XPT_MMC_SET_TRAN_SETTINGS:
153 {
154 ccb->ccb_h.status = CAM_SIM_QUEUED;
155 mmc_sim->ccb = ccb;
156 taskqueue_enqueue(taskqueue_thread, &mmc_sim->sim_task);
157 return;
158 /* NOTREACHED */
159 break;
160 }
161 case XPT_RESET_BUS:
162 ccb->ccb_h.status = CAM_REQ_CMP;
163 break;
164 case XPT_MMC_IO:
165 {
166 rv = MMC_SIM_CAM_REQUEST(mmc_sim->dev, ccb);
167 if (rv != 0)
168 ccb->ccb_h.status = CAM_SIM_QUEUED;
169 return;
170 /* NOTREACHED */
171 break;
172 }
173 default:
174 ccb->ccb_h.status = CAM_REQ_INVALID;
175 break;
176 }
177 xpt_done(ccb);
178 return;
179 }
180
181 int
mmc_cam_sim_alloc(device_t dev,const char * name,struct mmc_sim * mmc_sim)182 mmc_cam_sim_alloc(device_t dev, const char *name, struct mmc_sim *mmc_sim)
183 {
184 kobjop_desc_t kobj_desc;
185 kobj_method_t *kobj_method;
186
187 mmc_sim->dev = dev;
188
189 if ((mmc_sim->devq = cam_simq_alloc(1)) == NULL) {
190 goto fail;
191 }
192
193 snprintf(mmc_sim->name, sizeof(mmc_sim->name), "%s_sim", name);
194 mtx_init(&mmc_sim->mtx, mmc_sim->name, NULL, MTX_DEF);
195
196 /* Provide sim_poll hook only if the device has the poll method. */
197 kobj_desc = &mmc_sim_cam_poll_desc;
198 kobj_method = kobj_lookup_method(((kobj_t)dev)->ops->cls, NULL,
199 kobj_desc);
200 mmc_sim->sim = cam_sim_alloc(mmc_cam_sim_default_action,
201 kobj_method == &kobj_desc->deflt ? NULL : mmc_cam_default_poll,
202 mmc_sim->name, mmc_sim, device_get_unit(dev),
203 &mmc_sim->mtx, 1, 1, mmc_sim->devq);
204
205 if (mmc_sim->sim == NULL) {
206 cam_simq_free(mmc_sim->devq);
207 device_printf(dev, "cannot allocate CAM SIM\n");
208 goto fail;
209 }
210
211 mtx_lock(&mmc_sim->mtx);
212 if (xpt_bus_register(mmc_sim->sim, dev, 0) != 0) {
213 device_printf(dev, "cannot register SCSI pass-through bus\n");
214 cam_sim_free(mmc_sim->sim, FALSE);
215 cam_simq_free(mmc_sim->devq);
216 mtx_unlock(&mmc_sim->mtx);
217 goto fail;
218 }
219
220 mtx_unlock(&mmc_sim->mtx);
221 TASK_INIT(&mmc_sim->sim_task, 0, mmc_sim_task, mmc_sim);
222
223 return (0);
224
225 fail:
226 mmc_cam_sim_free(mmc_sim);
227 return (1);
228 }
229
230 void
mmc_cam_sim_free(struct mmc_sim * mmc_sim)231 mmc_cam_sim_free(struct mmc_sim *mmc_sim)
232 {
233
234 if (mmc_sim->sim != NULL) {
235 mtx_lock(&mmc_sim->mtx);
236 xpt_bus_deregister(cam_sim_path(mmc_sim->sim));
237 cam_sim_free(mmc_sim->sim, FALSE);
238 mtx_unlock(&mmc_sim->mtx);
239 }
240
241 if (mmc_sim->devq != NULL)
242 cam_simq_free(mmc_sim->devq);
243 }
244
245 void
mmc_cam_sim_discover(struct mmc_sim * mmc_sim)246 mmc_cam_sim_discover(struct mmc_sim *mmc_sim)
247 {
248
249 mmccam_start_discovery(mmc_sim->sim);
250 }
251