source: rtems-libbsd/rtemsbsd/src/rtems-bsd-cam.c @ 8420b94

4.115-freebsd-12freebsd-9.3
Last change on this file since 8420b94 was 8420b94, checked in by Jennifer Averett <jennifer.averett@…>, on May 8, 2012 at 2:14:42 PM

Modified copyright on rtems-bsd-xxx files to be consistant with FreeBSD copyright.

  • Property mode set to 100644
File size: 11.2 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup rtems_bsd_rtems
5 *
6 * @brief TODO.
7 */
8
9/*
10 * Copyright (c) 2009-2012 embedded brains GmbH. 
11 * All rights reserved.
12 *
13 *  embedded brains GmbH
14 *  Obere Lagerstr. 30
15 *  82178 Puchheim
16 *  Germany
17 *  <rtems@embedded-brains.de>
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 *    notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 *    notice, this list of conditions and the following disclaimer in the
26 *    documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41#include <freebsd/machine/rtems-bsd-config.h>
42
43#include <freebsd/sys/param.h>
44#include <freebsd/sys/systm.h>
45#include <freebsd/sys/malloc.h>
46#include <freebsd/sys/kernel.h>
47#include <freebsd/sys/lock.h>
48#include <freebsd/sys/mutex.h>
49#include <freebsd/sys/condvar.h>
50
51#include <freebsd/cam/cam.h>
52#include <freebsd/cam/cam_ccb.h>
53#include <freebsd/cam/cam_sim.h>
54#include <freebsd/cam/cam_xpt.h>
55#include <freebsd/cam/cam_xpt_sim.h>
56#include <freebsd/cam/cam_debug.h>
57
58#include <freebsd/cam/scsi/scsi_all.h>
59
60#include <rtems/media.h>
61#include <rtems/libio.h>
62#include <rtems/diskdevs.h>
63
64#define BSD_CAM_DEVQ_DUMMY ((struct cam_devq *) 0xdeadbeef)
65
66#define BSD_SCSI_TAG 0
67
68#define BSD_SCSI_RETRIES 4
69
70#define BSD_SCSI_TIMEOUT (60 * 1000)
71
72#define BSD_SCSI_MIN_COMMAND_SIZE 10
73
74MALLOC_DEFINE(M_CAMSIM, "CAM SIM", "CAM SIM buffers");
75
76static void
77rtems_bsd_sim_set_state(struct cam_sim *sim, enum bsd_sim_state state)
78{
79        sim->state = state;
80}
81
82static void
83rtems_bsd_sim_set_state_and_notify(struct cam_sim *sim, enum bsd_sim_state state)
84{
85        sim->state = state;
86        cv_broadcast(&sim->state_changed);
87}
88
89static void
90rtems_bsd_sim_wait_for_state(struct cam_sim *sim, enum bsd_sim_state state)
91{
92        while (sim->state != state) {
93                cv_wait(&sim->state_changed, sim->mtx);
94        }
95}
96
97static void
98rtems_bsd_sim_wait_for_state_and_cancel_ccb(struct cam_sim *sim, enum bsd_sim_state state)
99{
100        while (sim->state != state) {
101                if (sim->state != BSD_SIM_BUSY) {
102                        cv_wait(&sim->state_changed, sim->mtx);
103                } else {
104                        sim->ccb.ccb_h.status = CAM_SEL_TIMEOUT;
105                        (*sim->ccb.ccb_h.cbfcnp)(NULL, &sim->ccb);
106                }
107        }
108}
109
110static void
111rtems_bsd_ccb_callback(struct cam_periph *periph, union ccb *ccb)
112{
113        struct cam_sim *sim = ccb->ccb_h.sim;
114
115        BSD_ASSERT(periph == NULL && sim->state == BSD_SIM_INIT_BUSY);
116
117        rtems_bsd_sim_set_state_and_notify(sim, BSD_SIM_INIT_READY);
118}
119
120static rtems_status_code
121rtems_bsd_ccb_action(union ccb *ccb)
122{
123        rtems_status_code sc = RTEMS_SUCCESSFUL;
124        struct cam_sim *sim = ccb->ccb_h.sim;
125
126        mtx_lock(sim->mtx);
127
128        BSD_ASSERT(sim->state == BSD_SIM_INIT);
129        rtems_bsd_sim_set_state(sim, BSD_SIM_INIT_BUSY);
130        (*sim->sim_action)(sim, ccb);
131        rtems_bsd_sim_wait_for_state(sim, BSD_SIM_INIT_READY);
132        if (ccb->ccb_h.status != CAM_REQ_CMP) {
133                sc = RTEMS_IO_ERROR;
134        }
135        rtems_bsd_sim_set_state(sim, BSD_SIM_INIT);
136
137        mtx_unlock(sim->mtx);
138
139        return sc;
140}
141
142static rtems_status_code
143rtems_bsd_scsi_inquiry(union ccb *ccb, struct scsi_inquiry_data *inq_data)
144{
145        memset(inq_data, 0, sizeof(*inq_data));
146
147        scsi_inquiry(
148                &ccb->csio,
149                BSD_SCSI_RETRIES,
150                rtems_bsd_ccb_callback,
151                BSD_SCSI_TAG,
152                (u_int8_t *) inq_data,
153                sizeof(*inq_data) - 1,
154                FALSE,
155                0,
156                SSD_MIN_SIZE,
157                BSD_SCSI_TIMEOUT
158        );
159
160        return rtems_bsd_ccb_action(ccb);
161}
162
163static rtems_status_code
164rtems_bsd_scsi_test_unit_ready(union ccb *ccb)
165{
166        scsi_test_unit_ready(
167                &ccb->csio,
168                BSD_SCSI_RETRIES,
169                rtems_bsd_ccb_callback,
170                BSD_SCSI_TAG,
171                SSD_FULL_SIZE,
172                BSD_SCSI_TIMEOUT
173        );
174
175        return rtems_bsd_ccb_action(ccb);
176}
177
178static rtems_status_code
179rtems_bsd_scsi_read_capacity(union ccb *ccb, uint32_t *block_count, uint32_t *block_size)
180{
181        rtems_status_code sc = RTEMS_SUCCESSFUL;
182        struct scsi_read_capacity_data rdcap;
183
184        memset(&rdcap, 0, sizeof(rdcap));
185
186        scsi_read_capacity(
187                &ccb->csio,
188                BSD_SCSI_RETRIES,
189                rtems_bsd_ccb_callback,
190                BSD_SCSI_TAG,
191                &rdcap,
192                SSD_FULL_SIZE,
193                BSD_SCSI_TIMEOUT
194        );
195
196        sc = rtems_bsd_ccb_action(ccb);
197        if (sc != RTEMS_SUCCESSFUL) {
198                return RTEMS_IO_ERROR;
199        }
200
201        *block_size = scsi_4btoul(rdcap.length);
202        *block_count = scsi_4btoul(rdcap.addr) + 1;
203
204        return RTEMS_SUCCESSFUL;
205}
206
207static void
208rtems_bsd_csio_callback(struct cam_periph *periph, union ccb *ccb)
209{
210        rtems_status_code sc = RTEMS_SUCCESSFUL;
211        bool done = false;
212        struct cam_sim *sim = ccb->ccb_h.sim;
213
214        BSD_ASSERT(periph == NULL && sim->state == BSD_SIM_BUSY);
215
216        if (ccb->ccb_h.status == CAM_REQ_CMP) {
217                rtems_blkdev_sg_buffer *sg = ccb->csio.sg_current;
218
219                if (sg != ccb->csio.sg_end) {
220                        scsi_read_write(
221                                &ccb->csio,
222                                BSD_SCSI_RETRIES,
223                                rtems_bsd_csio_callback,
224                                BSD_SCSI_TAG,
225                                ccb->csio.readop,
226                                0,
227                                BSD_SCSI_MIN_COMMAND_SIZE,
228                                sg->block,
229                                sg->length / 512, /* FIXME */
230                                sg->buffer,
231                                sg->length,
232                                SSD_FULL_SIZE,
233                                BSD_SCSI_TIMEOUT
234                        );
235                        ccb->csio.sg_current = sg + 1;
236                        (*sim->sim_action)(sim, ccb);
237                } else {
238                        done = true;
239                }
240        } else if (ccb->ccb_h.status == CAM_SEL_TIMEOUT) {
241                sc = RTEMS_UNSATISFIED;
242                done = true;
243        } else {
244                sc = RTEMS_IO_ERROR;
245                done = true;
246        }
247
248        if (done) {
249                ccb->csio.req->req_done(ccb->csio.req->done_arg, sc);
250                rtems_bsd_sim_set_state_and_notify(sim, BSD_SIM_IDLE);
251        }
252}
253
254static int rtems_bsd_sim_disk_read_write(struct cam_sim *sim, rtems_blkdev_request *req)
255{
256        mtx_lock(sim->mtx);
257
258        rtems_bsd_sim_wait_for_state(sim, BSD_SIM_IDLE);
259        rtems_bsd_sim_set_state(sim, BSD_SIM_BUSY);
260
261        switch (req->req) {
262                case RTEMS_BLKDEV_REQ_READ:
263                        sim->ccb.csio.readop = TRUE;
264                        break;
265                case RTEMS_BLKDEV_REQ_WRITE:
266                        sim->ccb.csio.readop = FALSE;
267                        break;
268                default:
269                        mtx_unlock(sim->mtx);
270                        return -1;
271        }
272
273        sim->ccb.csio.sg_current = req->bufs;
274        sim->ccb.csio.sg_end = req->bufs + req->bufnum;
275        sim->ccb.csio.req = req;
276
277        sim->ccb.ccb_h.status = CAM_REQ_CMP;
278
279        rtems_bsd_csio_callback(NULL, &sim->ccb);
280
281        mtx_unlock(sim->mtx);
282
283        return 0;
284}
285
286static int rtems_bsd_sim_disk_ioctl(rtems_disk_device *dd, uint32_t req, void *arg)
287{
288        struct cam_sim *sim = rtems_disk_get_driver_data(dd);
289
290        if (req == RTEMS_BLKIO_REQUEST) {
291                rtems_blkdev_request *r = arg;
292
293                return rtems_bsd_sim_disk_read_write(sim, r);
294        } else if (req == RTEMS_BLKIO_DELETED) {
295                mtx_lock(sim->mtx);
296
297                free(sim->disk, M_RTEMS_HEAP);
298                sim->disk = NULL;
299                rtems_bsd_sim_set_state_and_notify(sim, BSD_SIM_DELETED);
300
301                mtx_unlock(sim->mtx);
302
303                return 0;
304        } else {
305                return rtems_blkdev_ioctl(dd, req, arg);
306        }
307}
308
309static void
310rtems_bsd_sim_disk_initialized(struct cam_sim *sim, char *disk)
311{
312        mtx_lock(sim->mtx);
313
314        sim->disk = disk;
315        rtems_bsd_sim_set_state_and_notify(sim, BSD_SIM_IDLE);
316
317        mtx_unlock(sim->mtx);
318}
319
320static rtems_status_code
321rtems_bsd_sim_attach_worker(rtems_media_state state, const char *src, char **dest, void *arg)
322{
323        rtems_status_code sc = RTEMS_SUCCESSFUL;
324        struct cam_sim *sim = arg;
325        char *disk = NULL;
326
327        if (state == RTEMS_MEDIA_STATE_READY) {
328                unsigned retries = 0;
329
330                struct scsi_inquiry_data inq_data;
331                uint32_t block_count = 0;
332                uint32_t block_size = 0;
333
334                disk = rtems_media_create_path("/dev", src, cam_sim_unit(sim));
335                if (disk == NULL) {
336                        BSD_PRINTF("OOPS: create path failed\n");
337                        goto error;
338                }
339
340                sc = rtems_bsd_scsi_inquiry(&sim->ccb, &inq_data);
341                if (sc != RTEMS_SUCCESSFUL) {
342                        BSD_PRINTF("OOPS: inquiry failed\n");
343                        goto error;
344                }
345                scsi_print_inquiry(&inq_data);
346
347                for (retries = 0; retries <= 3; ++retries) {
348                        sc = rtems_bsd_scsi_test_unit_ready(&sim->ccb);
349                        if (sc == RTEMS_SUCCESSFUL) {
350                                break;
351                        }
352                }
353                if (sc != RTEMS_SUCCESSFUL) {
354                        BSD_PRINTF("OOPS: test unit ready failed\n");
355                        goto error;
356                }
357
358                sc = rtems_bsd_scsi_read_capacity(&sim->ccb, &block_count, &block_size);
359                if (sc != RTEMS_SUCCESSFUL) {
360                        BSD_PRINTF("OOPS: read capacity failed\n");
361                        goto error;
362                }
363
364                BSD_PRINTF("read capacity: block count %u, block size %u\n", block_count, block_size);
365
366                sc = rtems_blkdev_create(disk, block_size, block_count, rtems_bsd_sim_disk_ioctl, sim);
367                if (sc != RTEMS_SUCCESSFUL) {
368                        goto error;
369                }
370
371                /* FIXME */
372#if 0
373                rtems_disk_device *dd = rtems_disk_obtain(dev);
374                dd->block_size *= 64;
375                rtems_disk_release(dd);
376#endif
377
378                rtems_bsd_sim_disk_initialized(sim, disk);
379
380                *dest = strdup(disk, M_RTEMS_HEAP);
381        }
382
383        return RTEMS_SUCCESSFUL;
384
385error:
386
387        free(disk, M_RTEMS_HEAP);
388
389        rtems_bsd_sim_disk_initialized(sim, NULL);
390
391        return RTEMS_IO_ERROR;
392}
393
394struct cam_sim *
395cam_sim_alloc(
396        sim_action_func sim_action,
397        sim_poll_func sim_poll,
398        const char *sim_name,
399        void *softc,
400        u_int32_t unit,
401        struct mtx *mtx,
402        int max_dev_transactions,
403        int max_tagged_dev_transactions,
404        struct cam_devq *queue
405)
406{
407        rtems_status_code sc = RTEMS_SUCCESSFUL;
408        struct cam_sim *sim = NULL;
409
410        if (mtx == NULL) {
411                return NULL;
412        }
413
414        sim = malloc(sizeof(*sim), M_CAMSIM, M_NOWAIT | M_ZERO);
415        if (sim == NULL) {
416                return NULL;
417        }
418
419        sim->sim_action = sim_action;
420        sim->sim_poll = sim_poll;
421        sim->sim_name = sim_name;
422        sim->softc = softc;
423        sim->mtx = mtx;
424        sim->unit_number = unit;
425        sim->ccb.ccb_h.sim = sim;
426
427        cv_init(&sim->state_changed, "SIM state changed");
428
429        sc = rtems_media_server_disk_attach(sim_name, rtems_bsd_sim_attach_worker, sim);
430        BSD_ASSERT_SC(sc);
431
432        return sim;
433}
434
435void
436cam_sim_free(struct cam_sim *sim, int free_devq)
437{
438        rtems_status_code sc = RTEMS_SUCCESSFUL;
439
440        /*
441         * The umass_detach() cancels all transfers via
442         * usbd_transfer_unsetup().  This prevents also the start of new
443         * transfers since the transfer descriptors will be removed.  Started
444         * transfers that are not in the transferring state will be canceled
445         * and the callbacks will be not called.  Thus it is necessary to do
446         * this here if we are in the BUSY state.
447         */
448        rtems_bsd_sim_wait_for_state_and_cancel_ccb(sim, BSD_SIM_IDLE);
449
450        if (sim->disk != NULL) {
451                sc = rtems_media_server_disk_detach(sim->disk);
452                BSD_ASSERT_SC(sc);
453
454                rtems_bsd_sim_wait_for_state(sim, BSD_SIM_DELETED);
455        }
456
457        cv_destroy(&sim->state_changed);
458        free(sim, M_CAMSIM);
459}
460
461struct cam_devq *
462cam_simq_alloc(u_int32_t max_sim_transactions)
463{
464        return BSD_CAM_DEVQ_DUMMY;
465}
466
467void
468cam_simq_free(struct cam_devq *devq)
469{
470        BSD_ASSERT(devq == BSD_CAM_DEVQ_DUMMY);
471}
472
473void
474xpt_done(union ccb *done_ccb)
475{
476        (*done_ccb->ccb_h.cbfcnp)(NULL, done_ccb);
477}
478
479int32_t
480xpt_bus_register(struct cam_sim *sim, device_t parent, u_int32_t bus)
481{
482        /*
483         * We ignore this bus stuff completely.  This is easier than removing
484         * the calls from "umass.c".
485         */
486
487        return CAM_SUCCESS;
488}
489
490int32_t
491xpt_bus_deregister(path_id_t pathid)
492{
493        /*
494         * We ignore this bus stuff completely.  This is easier than removing
495         * the calls from "umass.c".
496         */
497
498        return CAM_REQ_CMP;
499}
Note: See TracBrowser for help on using the repository browser.