Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /*- |
2 | * Copyright (c) 2000 Michael Smith | |
3 | * Copyright (c) 2000 BSDi | |
4 | * All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
1fcd0ba2 | 10 | * notice, this list of conditions and the following disclaimer. |
984263bc | 11 | * 2. Redistributions in binary form must reproduce the above copyright |
1fcd0ba2 SW |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. | |
984263bc MD |
14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
25 | * SUCH DAMAGE. | |
1fcd0ba2 SW |
26 | */ |
27 | /*- | |
984263bc MD |
28 | * Copyright (c) 2002 Eric Moore |
29 | * Copyright (c) 2002 LSI Logic Corporation | |
30 | * All rights reserved. | |
31 | * | |
32 | * Redistribution and use in source and binary forms, with or without | |
33 | * modification, are permitted provided that the following conditions | |
34 | * are met: | |
35 | * 1. Redistributions of source code must retain the above copyright | |
1fcd0ba2 | 36 | * notice, this list of conditions and the following disclaimer. |
984263bc | 37 | * 2. Redistributions in binary form must reproduce the above copyright |
1fcd0ba2 SW |
38 | * notice, this list of conditions and the following disclaimer in the |
39 | * documentation and/or other materials provided with the distribution. | |
984263bc | 40 | * 3. The party using or redistributing the source code and binary forms |
1fcd0ba2 SW |
41 | * agrees to the disclaimer below and the terms and conditions set forth |
42 | * herein. | |
984263bc MD |
43 | * |
44 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
45 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
46 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
47 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
48 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
49 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
50 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
52 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
53 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
54 | * SUCH DAMAGE. | |
55 | * | |
9d2581a4 | 56 | * $FreeBSD: src/sys/dev/amr/amr_cam.c,v 1.29 2011/11/07 06:44:47 ed Exp $ |
984263bc MD |
57 | */ |
58 | ||
59 | #include <sys/param.h> | |
60 | #include <sys/systm.h> | |
984263bc | 61 | #include <sys/kernel.h> |
1fcd0ba2 | 62 | #include <sys/module.h> |
984263bc | 63 | |
1fcd0ba2 | 64 | #include <sys/bio.h> |
984263bc MD |
65 | #include <sys/bus.h> |
66 | #include <sys/conf.h> | |
984263bc MD |
67 | #include <sys/stat.h> |
68 | ||
1f2de5d4 MD |
69 | #include <bus/cam/cam.h> |
70 | #include <bus/cam/cam_ccb.h> | |
71 | #include <bus/cam/cam_sim.h> | |
72 | #include <bus/cam/cam_xpt.h> | |
73 | #include <bus/cam/cam_xpt_sim.h> | |
74 | #include <bus/cam/cam_debug.h> | |
75 | #include <bus/cam/scsi/scsi_all.h> | |
76 | #include <bus/cam/scsi/scsi_message.h> | |
984263bc | 77 | |
1fcd0ba2 SW |
78 | #include <dev/raid/amr/amrreg.h> |
79 | #include <dev/raid/amr/amrvar.h> | |
984263bc | 80 | |
1fcd0ba2 SW |
81 | static int amr_cam_probe(device_t dev); |
82 | static int amr_cam_attach(device_t dev); | |
83 | static int amr_cam_detach(device_t dev); | |
84 | static void amr_cam_action(struct cam_sim *sim, union ccb *ccb); | |
85 | static void amr_cam_poll(struct cam_sim *sim); | |
86 | static void amr_cam_complete(struct amr_command *ac); | |
87 | static int amr_cam_command(struct amr_softc *sc, struct amr_command **acp); | |
984263bc | 88 | |
1fcd0ba2 | 89 | static devclass_t amr_pass_devclass; |
984263bc | 90 | |
1fcd0ba2 SW |
91 | static device_method_t amr_pass_methods[] = { |
92 | DEVMETHOD(device_probe, amr_cam_probe), | |
93 | DEVMETHOD(device_attach, amr_cam_attach), | |
94 | DEVMETHOD(device_detach, amr_cam_detach), | |
d3c9c58e | 95 | DEVMETHOD_END |
1fcd0ba2 SW |
96 | }; |
97 | ||
98 | static driver_t amr_pass_driver = { | |
99 | "amrp", | |
100 | amr_pass_methods, | |
101 | 0 | |
102 | }; | |
103 | ||
aa2b9d05 | 104 | DRIVER_MODULE(amrp, amr, amr_pass_driver, amr_pass_devclass, NULL, NULL); |
9d2581a4 | 105 | MODULE_VERSION(amrp, 1); |
5f8f1c95 | 106 | MODULE_DEPEND(amrp, amr, 1, 1, 1); |
1fcd0ba2 SW |
107 | MODULE_DEPEND(amrp, cam, 1, 1, 1); |
108 | ||
1fcd0ba2 | 109 | /*********************************************************************** |
984263bc MD |
110 | * Enqueue/dequeue functions |
111 | */ | |
112 | static __inline void | |
113 | amr_enqueue_ccb(struct amr_softc *sc, union ccb *ccb) | |
114 | { | |
1fcd0ba2 SW |
115 | |
116 | TAILQ_INSERT_TAIL(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe); | |
984263bc MD |
117 | } |
118 | ||
119 | static __inline void | |
120 | amr_requeue_ccb(struct amr_softc *sc, union ccb *ccb) | |
121 | { | |
1fcd0ba2 SW |
122 | |
123 | TAILQ_INSERT_HEAD(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe); | |
984263bc MD |
124 | } |
125 | ||
126 | static __inline union ccb * | |
127 | amr_dequeue_ccb(struct amr_softc *sc) | |
128 | { | |
1fcd0ba2 | 129 | union ccb *ccb; |
984263bc | 130 | |
1fcd0ba2 SW |
131 | if ((ccb = (union ccb *)TAILQ_FIRST(&sc->amr_cam_ccbq)) != NULL) |
132 | TAILQ_REMOVE(&sc->amr_cam_ccbq, &ccb->ccb_h, sim_links.tqe); | |
133 | return(ccb); | |
134 | } | |
135 | ||
136 | static int | |
137 | amr_cam_probe(device_t dev) | |
138 | { | |
139 | return (0); | |
984263bc MD |
140 | } |
141 | ||
142 | /******************************************************************************** | |
143 | * Attach our 'real' SCSI channels to CAM | |
144 | */ | |
1fcd0ba2 SW |
145 | static int |
146 | amr_cam_attach(device_t dev) | |
984263bc | 147 | { |
1fcd0ba2 SW |
148 | struct amr_softc *sc; |
149 | struct cam_devq *devq; | |
150 | int chn, error; | |
984263bc | 151 | |
1fcd0ba2 SW |
152 | sc = device_get_softc(dev); |
153 | ||
154 | /* initialise the ccb queue */ | |
155 | TAILQ_INIT(&sc->amr_cam_ccbq); | |
156 | ||
157 | /* | |
158 | * Allocate a devq for all our channels combined. This should | |
159 | * allow for the maximum number of SCSI commands we will accept | |
160 | * at one time. Save the pointer in the softc so we can find it later | |
161 | * during detach. | |
162 | */ | |
163 | if ((devq = cam_simq_alloc(AMR_MAX_SCSI_CMDS)) == NULL) | |
164 | return(ENOMEM); | |
165 | sc->amr_cam_devq = devq; | |
166 | ||
167 | /* | |
168 | * Iterate over our channels, registering them with CAM | |
169 | */ | |
170 | for (chn = 0; chn < sc->amr_maxchan; chn++) { | |
171 | ||
172 | /* allocate a sim */ | |
173 | if ((sc->amr_cam_sim[chn] = cam_sim_alloc(amr_cam_action, | |
174 | amr_cam_poll, "amr", sc, device_get_unit(sc->amr_dev), | |
175 | &sc->amr_list_lock, 1, AMR_MAX_SCSI_CMDS, devq)) == NULL) { | |
720762e1 | 176 | cam_simq_release(devq); |
1fcd0ba2 SW |
177 | device_printf(sc->amr_dev, "CAM SIM attach failed\n"); |
178 | return(ENOMEM); | |
179 | } | |
180 | ||
181 | /* register the bus ID so we can get it later */ | |
182 | lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); | |
183 | error = xpt_bus_register(sc->amr_cam_sim[chn], chn); | |
184 | lockmgr(&sc->amr_list_lock, LK_RELEASE); | |
185 | if (error) { | |
186 | device_printf(sc->amr_dev, | |
187 | "CAM XPT bus registration failed\n"); | |
188 | return(ENXIO); | |
189 | } | |
984263bc | 190 | } |
1fcd0ba2 SW |
191 | /* |
192 | * XXX we should scan the config and work out which devices are | |
193 | * actually protected. | |
194 | */ | |
195 | sc->amr_cam_command = amr_cam_command; | |
196 | return(0); | |
984263bc MD |
197 | } |
198 | ||
199 | /******************************************************************************** | |
200 | * Disconnect ourselves from CAM | |
201 | */ | |
1fcd0ba2 SW |
202 | static int |
203 | amr_cam_detach(device_t dev) | |
984263bc | 204 | { |
1fcd0ba2 SW |
205 | struct amr_softc *sc; |
206 | int chn; | |
207 | ||
208 | sc = device_get_softc(dev); | |
209 | lockmgr(&sc->amr_list_lock, LK_EXCLUSIVE); | |
210 | for (chn = 0; chn < sc->amr_maxchan; chn++) { | |
211 | /* | |
212 | * If a sim was allocated for this channel, free it | |
213 | */ | |
214 | if (sc->amr_cam_sim[chn] != NULL) { | |
215 | xpt_bus_deregister(cam_sim_path(sc->amr_cam_sim[chn])); | |
216 | cam_sim_free(sc->amr_cam_sim[chn]); | |
217 | } | |
984263bc | 218 | } |
1fcd0ba2 SW |
219 | lockmgr(&sc->amr_list_lock, LK_RELEASE); |
220 | ||
720762e1 SW |
221 | /* Now free the devq */ |
222 | if (sc->amr_cam_devq != NULL) | |
223 | cam_simq_release(sc->amr_cam_devq); | |
224 | ||
1fcd0ba2 | 225 | return (0); |
984263bc MD |
226 | } |
227 | ||
1fcd0ba2 SW |
228 | /*********************************************************************** |
229 | *********************************************************************** | |
230 | CAM passthrough interface | |
231 | *********************************************************************** | |
232 | ***********************************************************************/ | |
984263bc | 233 | |
1fcd0ba2 | 234 | /*********************************************************************** |
984263bc MD |
235 | * Handle a request for action from CAM |
236 | */ | |
237 | static void | |
238 | amr_cam_action(struct cam_sim *sim, union ccb *ccb) | |
239 | { | |
1fcd0ba2 SW |
240 | struct amr_softc *sc = cam_sim_softc(sim); |
241 | ||
242 | switch(ccb->ccb_h.func_code) { | |
243 | ||
244 | /* | |
245 | * Perform SCSI I/O to a physical device. | |
246 | */ | |
247 | case XPT_SCSI_IO: | |
248 | { | |
249 | struct ccb_hdr *ccbh = &ccb->ccb_h; | |
250 | struct ccb_scsiio *csio = &ccb->csio; | |
251 | ||
252 | /* Validate the CCB */ | |
253 | ccbh->status = CAM_REQ_INPROG; | |
254 | ||
255 | /* check the CDB length */ | |
256 | if (csio->cdb_len > AMR_MAX_EXTCDB_LEN) | |
257 | ccbh->status = CAM_REQ_INVALID; | |
258 | ||
259 | if ((csio->cdb_len > AMR_MAX_CDB_LEN) && | |
260 | (sc->support_ext_cdb == 0)) | |
261 | ccbh->status = CAM_REQ_INVALID; | |
262 | ||
263 | /* check that the CDB pointer is not to a physical address */ | |
264 | if ((ccbh->flags & CAM_CDB_POINTER) && | |
265 | (ccbh->flags & CAM_CDB_PHYS)) | |
266 | ccbh->status = CAM_REQ_INVALID; | |
267 | /* | |
268 | * if there is data transfer, it must be to/from a virtual | |
269 | * address | |
270 | */ | |
271 | if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { | |
272 | if (ccbh->flags & CAM_DATA_PHYS) | |
273 | /* we can't map it */ | |
274 | ccbh->status = CAM_REQ_INVALID; | |
275 | if (ccbh->flags & CAM_SCATTER_VALID) | |
276 | /* we want to do the s/g setup */ | |
277 | ccbh->status = CAM_REQ_INVALID; | |
278 | } | |
279 | ||
280 | /* | |
281 | * If the command is to a LUN other than 0, fail it. | |
282 | * This is probably incorrect, but during testing the | |
283 | * firmware did not seem to respect the LUN field, and thus | |
284 | * devices appear echoed. | |
285 | */ | |
286 | if (csio->ccb_h.target_lun != 0) | |
287 | ccbh->status = CAM_DEV_NOT_THERE; | |
288 | ||
289 | /* if we're happy with the request, queue it for attention */ | |
290 | if (ccbh->status == CAM_REQ_INPROG) { | |
291 | ||
292 | /* save the channel number in the ccb */ | |
293 | csio->ccb_h.sim_priv.entries[0].field= cam_sim_bus(sim); | |
294 | ||
295 | amr_enqueue_ccb(sc, ccb); | |
296 | amr_startio(sc); | |
297 | return; | |
298 | } | |
299 | break; | |
300 | } | |
301 | ||
302 | case XPT_CALC_GEOMETRY: | |
303 | { | |
304 | cam_calc_geometry(&ccb->ccg, /*extended*/1); | |
305 | break; | |
984263bc MD |
306 | } |
307 | ||
308 | /* | |
1fcd0ba2 | 309 | * Return path stats. Some of these should probably be amended. |
984263bc | 310 | */ |
1fcd0ba2 SW |
311 | case XPT_PATH_INQ: |
312 | { | |
313 | struct ccb_pathinq *cpi = & ccb->cpi; | |
314 | ||
315 | debug(3, "XPT_PATH_INQ"); | |
316 | cpi->version_num = 1; /* XXX??? */ | |
317 | cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; | |
318 | cpi->target_sprt = 0; | |
319 | cpi->hba_misc = PIM_NOBUSRESET|PIM_SEQSCAN; | |
320 | cpi->hba_eng_cnt = 0; | |
321 | cpi->max_target = AMR_MAX_TARGETS; | |
322 | cpi->max_lun = 0 /* AMR_MAX_LUNS*/; | |
323 | cpi->initiator_id = 7; /* XXX variable? */ | |
324 | strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); | |
325 | strncpy(cpi->hba_vid, "LSI", HBA_IDLEN); | |
326 | strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); | |
327 | cpi->unit_number = cam_sim_unit(sim); | |
328 | cpi->bus_id = cam_sim_bus(sim); | |
329 | cpi->base_transfer_speed = 132 * 1024; /* XXX */ | |
330 | cpi->transport = XPORT_SPI; | |
331 | cpi->transport_version = 2; | |
332 | cpi->protocol = PROTO_SCSI; | |
333 | cpi->protocol_version = SCSI_REV_2; | |
334 | cpi->ccb_h.status = CAM_REQ_CMP; | |
984263bc | 335 | |
1fcd0ba2 SW |
336 | break; |
337 | } | |
984263bc | 338 | |
1fcd0ba2 SW |
339 | case XPT_RESET_BUS: |
340 | { | |
341 | struct ccb_pathinq *cpi = & ccb->cpi; | |
984263bc | 342 | |
1fcd0ba2 SW |
343 | debug(1, "XPT_RESET_BUS"); |
344 | cpi->ccb_h.status = CAM_REQ_CMP; | |
345 | break; | |
984263bc | 346 | } |
984263bc | 347 | |
1fcd0ba2 SW |
348 | case XPT_RESET_DEV: |
349 | { | |
350 | debug(1, "XPT_RESET_DEV"); | |
351 | ccb->ccb_h.status = CAM_REQ_CMP; | |
352 | break; | |
353 | } | |
984263bc | 354 | |
1fcd0ba2 SW |
355 | case XPT_GET_TRAN_SETTINGS: |
356 | { | |
357 | struct ccb_trans_settings *cts = &(ccb->cts); | |
984263bc | 358 | |
1fcd0ba2 SW |
359 | debug(3, "XPT_GET_TRAN_SETTINGS"); |
360 | ||
361 | struct ccb_trans_settings_scsi *scsi; | |
362 | struct ccb_trans_settings_spi *spi; | |
363 | ||
364 | scsi = &cts->proto_specific.scsi; | |
365 | spi = &cts->xport_specific.spi; | |
366 | ||
367 | cts->protocol = PROTO_SCSI; | |
368 | cts->protocol_version = SCSI_REV_2; | |
369 | cts->transport = XPORT_SPI; | |
370 | cts->transport_version = 2; | |
371 | ||
372 | if (cts->type == CTS_TYPE_USER_SETTINGS) { | |
373 | ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; | |
374 | break; | |
375 | } | |
376 | ||
377 | spi->flags = CTS_SPI_FLAGS_DISC_ENB; | |
378 | spi->bus_width = MSG_EXT_WDTR_BUS_32_BIT; | |
379 | spi->sync_period = 6; /* 40MHz how wide is this bus? */ | |
380 | spi->sync_offset = 31; /* How to extract this from board? */ | |
381 | ||
382 | spi->valid = CTS_SPI_VALID_SYNC_RATE | |
383 | | CTS_SPI_VALID_SYNC_OFFSET | |
384 | | CTS_SPI_VALID_BUS_WIDTH | |
385 | | CTS_SPI_VALID_DISC; | |
386 | scsi->valid = CTS_SCSI_VALID_TQ; | |
387 | ccb->ccb_h.status = CAM_REQ_CMP; | |
388 | break; | |
984263bc | 389 | } |
1fcd0ba2 SW |
390 | |
391 | case XPT_SET_TRAN_SETTINGS: | |
392 | debug(3, "XPT_SET_TRAN_SETTINGS"); | |
f19fcfb0 PA |
393 | ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; |
394 | break; | |
1fcd0ba2 SW |
395 | |
396 | ||
397 | /* | |
398 | * Reject anything else as unsupported. | |
399 | */ | |
400 | default: | |
401 | /* we can't do this */ | |
402 | ccb->ccb_h.status = CAM_REQ_INVALID; | |
403 | break; | |
f19fcfb0 PA |
404 | } |
405 | ||
1fcd0ba2 SW |
406 | KKASSERT(lockstatus(&sc->amr_list_lock, curthread) != 0); |
407 | xpt_done(ccb); | |
984263bc MD |
408 | } |
409 | ||
1fcd0ba2 SW |
410 | /*********************************************************************** |
411 | * Convert a CAM CCB off the top of the CCB queue to a passthrough SCSI | |
412 | * command. | |
984263bc | 413 | */ |
1fcd0ba2 | 414 | static int |
984263bc MD |
415 | amr_cam_command(struct amr_softc *sc, struct amr_command **acp) |
416 | { | |
1fcd0ba2 SW |
417 | struct amr_command *ac; |
418 | struct amr_passthrough *ap; | |
419 | struct amr_ext_passthrough *aep; | |
420 | struct ccb_scsiio *csio; | |
421 | int bus, target, error; | |
422 | ||
423 | error = 0; | |
424 | ac = NULL; | |
425 | ap = NULL; | |
426 | aep = NULL; | |
427 | ||
428 | /* check to see if there is a ccb for us to work with */ | |
429 | if ((csio = (struct ccb_scsiio *)amr_dequeue_ccb(sc)) == NULL) | |
8f706258 | 430 | goto out; |
984263bc | 431 | |
1fcd0ba2 SW |
432 | /* get bus/target, XXX validate against protected devices? */ |
433 | bus = csio->ccb_h.sim_priv.entries[0].field; | |
434 | target = csio->ccb_h.target_id; | |
984263bc | 435 | |
1fcd0ba2 SW |
436 | /* |
437 | * Build a passthrough command. | |
438 | */ | |
984263bc | 439 | |
1fcd0ba2 SW |
440 | /* construct command */ |
441 | if ((ac = amr_alloccmd(sc)) == NULL) { | |
442 | error = ENOMEM; | |
443 | goto out; | |
444 | } | |
984263bc | 445 | |
1fcd0ba2 SW |
446 | /* construct passthrough */ |
447 | if (sc->support_ext_cdb ) { | |
448 | aep = &ac->ac_ccb->ccb_epthru; | |
449 | aep->ap_timeout = 2; | |
450 | aep->ap_ars = 1; | |
451 | aep->ap_request_sense_length = 14; | |
452 | aep->ap_islogical = 0; | |
453 | aep->ap_channel = bus; | |
454 | aep->ap_scsi_id = target; | |
455 | aep->ap_logical_drive_no = csio->ccb_h.target_lun; | |
456 | aep->ap_cdb_length = csio->cdb_len; | |
457 | aep->ap_data_transfer_length = csio->dxfer_len; | |
458 | if (csio->ccb_h.flags & CAM_CDB_POINTER) { | |
459 | bcopy(csio->cdb_io.cdb_ptr, aep->ap_cdb, csio->cdb_len); | |
460 | } else { | |
461 | bcopy(csio->cdb_io.cdb_bytes, aep->ap_cdb, | |
462 | csio->cdb_len); | |
463 | } | |
464 | /* | |
465 | * we leave the data s/g list and s/g count to the map routine | |
466 | * later | |
467 | */ | |
468 | ||
469 | debug(2, " COMMAND %x/%d+%d to %d:%d:%d", aep->ap_cdb[0], | |
470 | aep->ap_cdb_length, csio->dxfer_len, aep->ap_channel, | |
471 | aep->ap_scsi_id, aep->ap_logical_drive_no); | |
984263bc | 472 | |
984263bc | 473 | } else { |
1fcd0ba2 SW |
474 | ap = &ac->ac_ccb->ccb_pthru; |
475 | ap->ap_timeout = 0; | |
476 | ap->ap_ars = 1; | |
477 | ap->ap_request_sense_length = 14; | |
478 | ap->ap_islogical = 0; | |
479 | ap->ap_channel = bus; | |
480 | ap->ap_scsi_id = target; | |
481 | ap->ap_logical_drive_no = csio->ccb_h.target_lun; | |
482 | ap->ap_cdb_length = csio->cdb_len; | |
483 | ap->ap_data_transfer_length = csio->dxfer_len; | |
484 | if (csio->ccb_h.flags & CAM_CDB_POINTER) { | |
485 | bcopy(csio->cdb_io.cdb_ptr, ap->ap_cdb, csio->cdb_len); | |
486 | } else { | |
487 | bcopy(csio->cdb_io.cdb_bytes, ap->ap_cdb, | |
488 | csio->cdb_len); | |
489 | } | |
490 | /* | |
491 | * we leave the data s/g list and s/g count to the map routine | |
492 | * later | |
493 | */ | |
494 | ||
495 | debug(2, " COMMAND %x/%d+%d to %d:%d:%d", ap->ap_cdb[0], | |
496 | ap->ap_cdb_length, csio->dxfer_len, ap->ap_channel, | |
497 | ap->ap_scsi_id, ap->ap_logical_drive_no); | |
984263bc | 498 | } |
984263bc | 499 | |
1fcd0ba2 | 500 | ac->ac_flags |= AMR_CMD_CCB; |
984263bc | 501 | |
1fcd0ba2 SW |
502 | ac->ac_data = csio->data_ptr; |
503 | ac->ac_length = csio->dxfer_len; | |
504 | if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) | |
505 | ac->ac_flags |= AMR_CMD_DATAIN; | |
506 | if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) | |
507 | ac->ac_flags |= AMR_CMD_DATAOUT; | |
984263bc | 508 | |
1fcd0ba2 SW |
509 | ac->ac_private = csio; |
510 | ac->ac_complete = amr_cam_complete; | |
511 | if ( sc->support_ext_cdb ) { | |
512 | ac->ac_mailbox.mb_command = AMR_CMD_EXTPASS; | |
513 | } else { | |
514 | ac->ac_mailbox.mb_command = AMR_CMD_PASS; | |
515 | } | |
984263bc | 516 | |
1fcd0ba2 SW |
517 | out: |
518 | if (error != 0) { | |
519 | if (ac != NULL) | |
520 | amr_releasecmd(ac); | |
521 | if (csio != NULL) | |
522 | /* put it back and try again later */ | |
523 | amr_requeue_ccb(sc, (union ccb *)csio); | |
984263bc | 524 | } |
1fcd0ba2 SW |
525 | *acp = ac; |
526 | return(error); | |
984263bc MD |
527 | } |
528 | ||
1fcd0ba2 SW |
529 | /*********************************************************************** |
530 | * Check for interrupt status | |
984263bc MD |
531 | */ |
532 | static void | |
1fcd0ba2 | 533 | amr_cam_poll(struct cam_sim *sim) |
984263bc | 534 | { |
984263bc | 535 | |
1fcd0ba2 SW |
536 | amr_done(cam_sim_softc(sim)); |
537 | } | |
984263bc | 538 | |
1fcd0ba2 SW |
539 | /********************************************************************** |
540 | * Handle completion of a command submitted via CAM. | |
541 | */ | |
542 | static void | |
543 | amr_cam_complete(struct amr_command *ac) | |
544 | { | |
545 | struct amr_passthrough *ap; | |
546 | struct amr_ext_passthrough *aep; | |
547 | struct ccb_scsiio *csio; | |
548 | struct scsi_inquiry_data *inq; | |
549 | int scsi_status, cdb0; | |
23abaded AHJ |
550 | #ifdef AMR_DEBUG |
551 | char hexstr[HEX_NCPYLEN(16)]; | |
552 | #endif | |
1fcd0ba2 SW |
553 | |
554 | ap = &ac->ac_ccb->ccb_pthru; | |
555 | aep = &ac->ac_ccb->ccb_epthru; | |
556 | csio = (struct ccb_scsiio *)ac->ac_private; | |
557 | inq = (struct scsi_inquiry_data *)csio->data_ptr; | |
558 | ||
559 | if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS) | |
560 | scsi_status = aep->ap_scsi_status; | |
561 | else | |
562 | scsi_status = ap->ap_scsi_status; | |
563 | debug(1, "status 0x%x AP scsi_status 0x%x", ac->ac_status, | |
564 | scsi_status); | |
565 | ||
566 | /* Make sure the status is sane */ | |
567 | if ((ac->ac_status != AMR_STATUS_SUCCESS) && (scsi_status == 0)) { | |
568 | csio->ccb_h.status = CAM_REQ_CMP_ERR; | |
569 | goto out; | |
984263bc | 570 | } |
1fcd0ba2 SW |
571 | |
572 | /* | |
573 | * Hide disks from CAM so that they're not picked up and treated as | |
574 | * 'normal' disks. | |
575 | * | |
576 | * If the configuration provides a mechanism to mark a disk a "not | |
577 | * managed", we could add handling for that to allow disks to be | |
578 | * selectively visible. | |
579 | */ | |
984263bc MD |
580 | |
581 | /* handle passthrough SCSI status */ | |
1fcd0ba2 SW |
582 | switch(scsi_status) { |
583 | case 0: /* completed OK */ | |
584 | if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS) | |
585 | cdb0 = aep->ap_cdb[0]; | |
586 | else | |
587 | cdb0 = ap->ap_cdb[0]; | |
588 | if ((cdb0 == INQUIRY) && (SID_TYPE(inq) == T_DIRECT)) | |
589 | inq->device = (inq->device & 0xe0) | T_NODEVICE; | |
590 | csio->ccb_h.status = CAM_REQ_CMP; | |
591 | break; | |
984263bc MD |
592 | |
593 | case 0x02: | |
1fcd0ba2 SW |
594 | csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; |
595 | csio->scsi_status = SCSI_STATUS_CHECK_COND; | |
596 | if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS) | |
597 | bcopy(aep->ap_request_sense_area, &csio->sense_data, | |
598 | AMR_MAX_REQ_SENSE_LEN); | |
599 | else | |
600 | bcopy(ap->ap_request_sense_area, &csio->sense_data, | |
601 | AMR_MAX_REQ_SENSE_LEN); | |
602 | csio->sense_len = AMR_MAX_REQ_SENSE_LEN; | |
603 | csio->ccb_h.status |= CAM_AUTOSNS_VALID; | |
604 | break; | |
984263bc MD |
605 | |
606 | case 0x08: | |
1fcd0ba2 SW |
607 | csio->ccb_h.status = CAM_SCSI_BUSY; |
608 | break; | |
984263bc MD |
609 | |
610 | case 0xf0: | |
611 | case 0xf4: | |
612 | default: | |
1fcd0ba2 SW |
613 | /* |
614 | * Non-zero LUNs are already filtered, so there's no need | |
615 | * to return CAM_DEV_NOT_THERE. | |
616 | */ | |
617 | csio->ccb_h.status = CAM_SEL_TIMEOUT; | |
618 | break; | |
984263bc | 619 | } |
1fcd0ba2 SW |
620 | |
621 | out: | |
622 | if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) | |
23abaded AHJ |
623 | debug(2, "%s\n", hexncpy(csio->data_ptr, imin(csio->dxfer_len, 16), |
624 | hexstr, HEX_NCPYLEN(imin(csio->dxfer_len, 16)), " ")); | |
1fcd0ba2 SW |
625 | |
626 | lockmgr(&ac->ac_sc->amr_list_lock, LK_EXCLUSIVE); | |
627 | xpt_done((union ccb *)csio); | |
628 | amr_releasecmd(ac); | |
629 | lockmgr(&ac->ac_sc->amr_list_lock, LK_RELEASE); | |
984263bc | 630 | } |