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

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since cbffdb7f was cbffdb7f, checked in by Joel Sherrill <joel.sherrill@…>, on 03/07/12 at 22:14:13

Separate RTEMS Specific Files from Those Direct from FreeBSD

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