]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/twa/tw_osl_cam.c
This commit was generated by cvs2svn to compensate for changes in r165670,
[FreeBSD/FreeBSD.git] / sys / dev / twa / tw_osl_cam.c
1 /*
2  * Copyright (c) 2004-05 Applied Micro Circuits Corporation.
3  * Copyright (c) 2004-05 Vinod Kashyap.
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
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
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.
26  *
27  *      $FreeBSD$
28  */
29
30 /*
31  * AMCC'S 3ware driver for 9000 series storage controllers.
32  *
33  * Author: Vinod Kashyap
34  */
35
36
37 /*
38  * FreeBSD CAM related functions.
39  */
40
41
42 #include <dev/twa/tw_osl_includes.h>
43
44 #include <cam/cam.h>
45 #include <cam/cam_ccb.h>
46 #include <cam/cam_sim.h>
47 #include <cam/cam_xpt_sim.h>
48 #include <cam/cam_debug.h>
49 #include <cam/cam_periph.h>
50
51 #include <cam/scsi/scsi_all.h>
52 #include <cam/scsi/scsi_message.h>
53
54 static TW_VOID  twa_action(struct cam_sim *sim, union ccb *ccb);
55 static TW_VOID  twa_poll(struct cam_sim *sim);
56 static TW_VOID  twa_async(TW_VOID *callback_arg, TW_UINT32 code,
57         struct cam_path *path, TW_VOID *arg);
58 static TW_VOID  twa_timeout(TW_VOID *arg);
59 static TW_VOID  twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb);
60
61 static TW_INT32 tw_osli_execute_scsi(struct tw_osli_req_context *req,
62         union ccb *ccb);
63
64
65
66 /*
67  * Function name:       tw_osli_cam_attach
68  * Description:         Attaches the driver to CAM.
69  *
70  * Input:               sc      -- ptr to OSL internal ctlr context
71  * Output:              None
72  * Return value:        0       -- success
73  *                      non-zero-- failure
74  */
75 TW_INT32
76 tw_osli_cam_attach(struct twa_softc *sc)
77 {
78         struct cam_devq         *devq;
79         struct ccb_setasync     csa;
80         TW_INT32                error;
81
82         tw_osli_dbg_dprintf(3, sc, "entered");
83
84         /*
85          * Create the device queue for our SIM.
86          */
87         if ((devq = cam_simq_alloc(TW_OSLI_MAX_NUM_IOS)) == NULL) {
88                 tw_osli_printf(sc, "error = %d",
89                         TW_CL_SEVERITY_ERROR_STRING,
90                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
91                         0x2100,
92                         "Failed to create SIM device queue",
93                         ENOMEM);
94                 return(ENOMEM);
95         }
96
97         /*
98          * Create a SIM entry.  Though we can support TW_OSLI_MAX_NUM_IOS
99          * simultaneous requests, we claim to be able to handle only
100          * (TW_OSLI_MAX_NUM_IOS - 1), so that we always have a request
101          * packet available to service ioctls.
102          */
103         tw_osli_dbg_dprintf(3, sc, "Calling cam_sim_alloc");
104         sc->sim = cam_sim_alloc(twa_action, twa_poll, "twa", sc,
105                         device_get_unit(sc->bus_dev),
106                         TW_OSLI_MAX_NUM_IOS - 1, 1, devq);
107         if (sc->sim == NULL) {
108                 cam_simq_free(devq);
109                 tw_osli_printf(sc, "error = %d",
110                         TW_CL_SEVERITY_ERROR_STRING,
111                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
112                         0x2101,
113                         "Failed to create a SIM entry",
114                         ENOMEM);
115                 return(ENOMEM);
116         }
117
118         /*
119          * Register the bus.
120          */
121         tw_osli_dbg_dprintf(3, sc, "Calling xpt_bus_register");
122         mtx_lock(&Giant);
123         if (xpt_bus_register(sc->sim, 0) != CAM_SUCCESS) {
124                 cam_sim_free(sc->sim, TRUE);
125                 sc->sim = NULL; /* so cam_detach will not try to free it */
126                 tw_osli_printf(sc, "error = %d",
127                         TW_CL_SEVERITY_ERROR_STRING,
128                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
129                         0x2102,
130                         "Failed to register the bus",
131                         ENXIO);
132                 return(ENXIO);
133         }
134
135         tw_osli_dbg_dprintf(3, sc, "Calling xpt_create_path");
136         if (xpt_create_path(&sc->path, NULL,
137                                 cam_sim_path(sc->sim),
138                                 CAM_TARGET_WILDCARD,
139                                 CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
140                 xpt_bus_deregister(cam_sim_path (sc->sim));
141                 /* Passing TRUE to cam_sim_free will free the devq as well. */
142                 cam_sim_free(sc->sim, TRUE);
143                 tw_osli_printf(sc, "error = %d",
144                         TW_CL_SEVERITY_ERROR_STRING,
145                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
146                         0x2103,
147                         "Failed to create path",
148                         ENXIO);
149                 return(ENXIO);
150         }
151
152         tw_osli_dbg_dprintf(3, sc, "Calling xpt_setup_ccb");
153         xpt_setup_ccb(&csa.ccb_h, sc->path, 5);
154         csa.ccb_h.func_code = XPT_SASYNC_CB;
155         csa.event_enable = AC_FOUND_DEVICE | AC_LOST_DEVICE;
156         csa.callback = twa_async;
157         csa.callback_arg = sc;
158         xpt_action((union ccb *)&csa);
159         mtx_unlock(&Giant);
160
161         tw_osli_dbg_dprintf(3, sc, "Calling tw_osli_request_bus_scan");
162         /*
163          * Request a bus scan, so that CAM gets to know of
164          * the logical units that we control.
165          */
166         if ((error = tw_osli_request_bus_scan(sc)))
167                 tw_osli_printf(sc, "error = %d",
168                         TW_CL_SEVERITY_ERROR_STRING,
169                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
170                         0x2104,
171                         "Bus scan request to CAM failed",
172                         error);
173         
174         tw_osli_dbg_dprintf(3, sc, "exiting");
175         return(0);
176 }
177
178
179
180 /*
181  * Function name:       tw_osli_cam_detach
182  * Description:         Detaches the driver from CAM.
183  *
184  * Input:               sc      -- ptr to OSL internal ctlr context
185  * Output:              None
186  * Return value:        None
187  */
188 TW_VOID
189 tw_osli_cam_detach(struct twa_softc *sc)
190 {
191         tw_osli_dbg_dprintf(3, sc, "entered");
192
193         mtx_lock(&Giant);
194         if (sc->path)
195                 xpt_free_path(sc->path);
196         if (sc->sim) {
197                 xpt_bus_deregister(cam_sim_path(sc->sim));
198                 /* Passing TRUE to cam_sim_free will free the devq as well. */
199                 cam_sim_free(sc->sim, TRUE);
200         }
201         mtx_unlock(&Giant);
202 }
203
204
205
206 /*
207  * Function name:       tw_osli_execute_scsi
208  * Description:         Build a fw cmd, based on a CAM style ccb, and
209  *                      send it down.
210  *
211  * Input:               req     -- ptr to OSL internal request context
212  *                      ccb     -- ptr to CAM style ccb
213  * Output:              None
214  * Return value:        0       -- success
215  *                      non-zero-- failure
216  */
217 TW_INT32
218 tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb)
219 {
220         struct twa_softc                *sc = req->ctlr;
221         struct tw_cl_req_packet         *req_pkt;
222         struct tw_cl_scsi_req_packet    *scsi_req;
223         struct ccb_hdr                  *ccb_h = &(ccb->ccb_h);
224         struct ccb_scsiio               *csio = &(ccb->csio);
225         TW_INT32                        error;
226
227         tw_osli_dbg_dprintf(10, sc, "SCSI I/O request 0x%x",
228                 csio->cdb_io.cdb_bytes[0]);
229
230         if (ccb_h->target_id >= TW_CL_MAX_NUM_UNITS) {
231                 tw_osli_dbg_dprintf(3, sc, "Invalid target. PTL = %x %x %x",
232                         ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
233                 ccb_h->status |= CAM_TID_INVALID;
234                 xpt_done(ccb);
235                 return(1);
236         }
237         if (ccb_h->target_lun >= TW_CL_MAX_NUM_LUNS) {
238                 tw_osli_dbg_dprintf(3, sc, "Invalid lun. PTL = %x %x %x",
239                         ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
240                 ccb_h->status |= CAM_LUN_INVALID;
241                 xpt_done(ccb);
242                 return(1);
243         }
244
245         if(ccb_h->flags & CAM_CDB_PHYS) {
246                 tw_osli_printf(sc, "",
247                         TW_CL_SEVERITY_ERROR_STRING,
248                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
249                         0x2105,
250                         "Physical CDB address!");
251                 ccb_h->status = CAM_REQ_CMP_ERR;
252                 xpt_done(ccb);
253                 return(1);
254         }
255
256         /*
257          * We are going to work on this request.  Mark it as enqueued (though
258          * we don't actually queue it...)
259          */
260         ccb_h->status |= CAM_SIM_QUEUED;
261
262         if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
263                 if(ccb_h->flags & CAM_DIR_IN)
264                         req->flags |= TW_OSLI_REQ_FLAGS_DATA_IN;
265                 else
266                         req->flags |= TW_OSLI_REQ_FLAGS_DATA_OUT;
267         }
268
269         /* Build the CL understood request packet for SCSI cmds. */
270         req_pkt = &req->req_pkt;
271         req_pkt->status = 0;
272         req_pkt->tw_osl_callback = tw_osl_complete_io;
273         scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
274         scsi_req->unit = ccb_h->target_id;
275         scsi_req->lun = ccb_h->target_lun;
276         scsi_req->sense_len = 0;
277         scsi_req->sense_data = (TW_UINT8 *)(&csio->sense_data);
278         scsi_req->scsi_status = 0;
279         if(ccb_h->flags & CAM_CDB_POINTER)
280                 scsi_req->cdb = csio->cdb_io.cdb_ptr;
281         else
282                 scsi_req->cdb = csio->cdb_io.cdb_bytes;
283         scsi_req->cdb_len = csio->cdb_len;
284
285         if (!(ccb_h->flags & CAM_DATA_PHYS)) {
286                 /* Virtual data addresses.  Need to convert them... */
287                 tw_osli_dbg_dprintf(3, sc,
288                         "XPT_SCSI_IO: Single virtual address!");
289                 if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
290                         if (csio->dxfer_len > TW_CL_MAX_IO_SIZE) {
291                                 tw_osli_printf(sc, "size = %d",
292                                         TW_CL_SEVERITY_ERROR_STRING,
293                                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
294                                         0x2106,
295                                         "I/O size too big",
296                                         csio->dxfer_len);
297                                 ccb_h->status = CAM_REQ_TOO_BIG;
298                                 xpt_done(ccb);
299                                 return(1);
300                         }
301
302                         if ((req->length = csio->dxfer_len)) {
303                                 req->data = csio->data_ptr;
304                                 scsi_req->sgl_entries = 1;
305                         }
306                 } else {
307                         tw_osli_printf(sc, "",
308                                 TW_CL_SEVERITY_ERROR_STRING,
309                                 TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
310                                 0x2107,
311                                 "XPT_SCSI_IO: Got SGList");
312                         ccb_h->status = CAM_REQ_CMP_ERR;
313                         xpt_done(ccb);
314                         return(1);
315                 }
316         } else {
317                 /* Data addresses are physical. */
318                 tw_osli_printf(sc, "",
319                         TW_CL_SEVERITY_ERROR_STRING,
320                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
321                         0x2108,
322                         "XPT_SCSI_IO: Physical data addresses");
323                 ccb_h->status = CAM_REQ_CMP_ERR;
324                 ccb_h->status |= CAM_RELEASE_SIMQ;
325                 ccb_h->status &= ~CAM_SIM_QUEUED;
326                 xpt_done(ccb);
327                 return(1);
328         }
329
330         ccb_h->timeout_ch = timeout(twa_timeout, req,
331                 (ccb_h->timeout * hz) / 1000);
332         /*
333          * twa_map_load_data_callback will fill in the SGL,
334          * and submit the I/O.
335          */
336         error = tw_osli_map_request(req);
337         return(error);
338 }
339
340
341
342 /*
343  * Function name:       twa_action
344  * Description:         Driver entry point for CAM's use.
345  *
346  * Input:               sim     -- sim corresponding to the ctlr
347  *                      ccb     -- ptr to CAM request
348  * Output:              None
349  * Return value:        None
350  */
351 TW_VOID
352 twa_action(struct cam_sim *sim, union ccb *ccb)
353 {
354         struct twa_softc        *sc = (struct twa_softc *)cam_sim_softc(sim);
355         struct ccb_hdr          *ccb_h = &(ccb->ccb_h);
356
357         switch (ccb_h->func_code) {
358         case XPT_SCSI_IO:       /* SCSI I/O */
359         {
360                 struct tw_osli_req_context      *req;
361
362                 if ((sc->state & TW_OSLI_CTLR_STATE_SIMQ_FROZEN) ||
363                                 ((req = tw_osli_get_request(sc)) == NULL)) {
364                         tw_osli_dbg_dprintf(2, sc,
365                                 "simq frozen/Cannot get request pkt.");
366                         /*
367                          * Freeze the simq to maintain ccb ordering.  The next
368                          * ccb that gets completed will unfreeze the simq.
369                          */
370                         tw_osli_disallow_new_requests(sc);
371                         ccb_h->status |= CAM_REQUEUE_REQ;
372                         xpt_done(ccb);
373                         break;
374                 }
375                 req->req_handle.osl_req_ctxt = req;
376                 req->orig_req = ccb;
377                 if (tw_osli_execute_scsi(req, ccb))
378                         tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
379                 break;
380         }
381
382         case XPT_ABORT:
383                 tw_osli_dbg_dprintf(2, sc, "Abort request.");
384                 ccb_h->status = CAM_UA_ABORT;
385                 xpt_done(ccb);
386                 break;
387
388         case XPT_RESET_BUS:
389                 tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE,
390                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
391                         0x2108, 0x3, TW_CL_SEVERITY_INFO_STRING,
392                         "Received Reset Bus request from CAM",
393                         " ");
394
395                 if (tw_cl_reset_ctlr(&sc->ctlr_handle)) {
396                         tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE,
397                                 TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
398                                 0x2109, 0x1, TW_CL_SEVERITY_ERROR_STRING,
399                                 "Failed to reset bus",
400                                 " ");
401                         ccb_h->status = CAM_REQ_CMP_ERR;
402                 }
403                 else
404                         ccb_h->status = CAM_REQ_CMP;
405
406                 xpt_done(ccb);
407                 break;
408
409         case XPT_SET_TRAN_SETTINGS:
410                 tw_osli_dbg_dprintf(3, sc, "XPT_SET_TRAN_SETTINGS");
411
412                 /*
413                  * This command is not supported, since it's very specific
414                  * to SCSI, and we are doing ATA.
415                  */
416                 ccb_h->status = CAM_FUNC_NOTAVAIL;
417                 xpt_done(ccb);
418                 break;
419
420         case XPT_GET_TRAN_SETTINGS: 
421         {
422                 struct ccb_trans_settings       *cts = &ccb->cts;
423                 struct ccb_trans_settings_scsi *scsi =
424                     &cts->proto_specific.scsi;
425                 struct ccb_trans_settings_spi *spi =
426                     &cts->xport_specific.spi;
427
428                 cts->protocol = PROTO_SCSI;
429                 cts->protocol_version = SCSI_REV_2;
430                 cts->transport = XPORT_SPI;
431                 cts->transport_version = 2;
432
433                 spi->valid = CTS_SPI_VALID_DISC;
434                 spi->flags = CTS_SPI_FLAGS_DISC_ENB;
435                 scsi->valid = CTS_SCSI_VALID_TQ;
436                 scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
437                 tw_osli_dbg_dprintf(3, sc, "XPT_GET_TRAN_SETTINGS");
438                 ccb_h->status = CAM_REQ_CMP;
439                 xpt_done(ccb);
440                 break;
441         }
442
443         case XPT_CALC_GEOMETRY:
444                 tw_osli_dbg_dprintf(3, sc, "XPT_CALC_GEOMETRY");
445                 cam_calc_geometry(&ccb->ccg, 1/* extended */);
446                 xpt_done(ccb);
447                 break;
448
449         case XPT_PATH_INQ:    /* Path inquiry -- get twa properties */
450         {
451                 struct ccb_pathinq      *path_inq = &ccb->cpi;
452
453                 tw_osli_dbg_dprintf(3, sc, "XPT_PATH_INQ request");
454
455                 path_inq->version_num = 1;
456                 path_inq->hba_inquiry = 0;
457                 path_inq->target_sprt = 0;
458                 path_inq->hba_misc = 0;
459                 path_inq->hba_eng_cnt = 0;
460                 path_inq->max_target = TW_CL_MAX_NUM_UNITS;
461                 path_inq->max_lun = TW_CL_MAX_NUM_LUNS - 1;
462                 path_inq->unit_number = cam_sim_unit(sim);
463                 path_inq->bus_id = cam_sim_bus(sim);
464                 path_inq->initiator_id = TW_CL_MAX_NUM_UNITS;
465                 path_inq->base_transfer_speed = 100000;
466                 strncpy(path_inq->sim_vid, "FreeBSD", SIM_IDLEN);
467                 strncpy(path_inq->hba_vid, "3ware", HBA_IDLEN);
468                 strncpy(path_inq->dev_name, cam_sim_name(sim), DEV_IDLEN);
469                 path_inq->transport = XPORT_SPI;
470                 path_inq->transport_version = 2;
471                 path_inq->protocol = PROTO_SCSI;
472                 path_inq->protocol_version = SCSI_REV_2;
473                 ccb_h->status = CAM_REQ_CMP;
474                 xpt_done(ccb);
475                 break;
476         }
477
478         default:
479                 tw_osli_dbg_dprintf(3, sc, "func_code = %x", ccb_h->func_code);
480                 ccb_h->status = CAM_REQ_INVALID;
481                 xpt_done(ccb);
482                 break;
483         }
484 }
485
486
487
488 /*
489  * Function name:       twa_poll
490  * Description:         Driver entry point called when interrupts are not
491  *                      available.
492  *
493  * Input:               sim     -- sim corresponding to the controller
494  * Output:              None
495  * Return value:        None
496  */
497 TW_VOID
498 twa_poll(struct cam_sim *sim)
499 {
500         struct twa_softc *sc = (struct twa_softc *)(cam_sim_softc(sim));
501
502         tw_osli_dbg_dprintf(3, sc, "entering; sc = %p", sc);
503         /*
504          * It's been observed that twa_poll can get called (from
505          * dashutdown --> xpt_polled_action) even when interrupts are
506          * active, in which case, the ISR might clear the interrupt,
507          * leaving the call to tw_cl_interrupt below, no way of determining
508          * that the response from firmware is ready, resulting in
509          * tw_cl_deferred_interrupt never getting called.  To cover this case,
510          * we will make the call to tw_cl_deferred_interrupt not dependent
511          * on the return value from tw_cl_interrupt.
512          */
513         tw_cl_interrupt(&(sc->ctlr_handle));
514         tw_cl_deferred_interrupt(&(sc->ctlr_handle));
515         tw_osli_dbg_dprintf(3, sc, "exiting; sc = %p", sc);
516 }
517
518
519
520 /*
521  * Function name:       twa_async
522  * Description:         Driver entry point for CAM to notify driver of special
523  *                      events.  We don't use this for now.
524  *
525  * Input:               callback_arg    -- ptr to per ctlr structure
526  *                      code            -- code associated with the event
527  *                      path            -- cam path
528  *                      arg             -- 
529  * Output:              None
530  * Return value:        0       -- success
531  *                      non-zero-- failure
532  */
533 TW_VOID
534 twa_async(TW_VOID *callback_arg, TW_UINT32 code, 
535         struct cam_path *path, TW_VOID *arg)
536 {
537 #ifdef TW_OSL_DEBUG
538         struct twa_softc *sc = (struct twa_softc *)callback_arg;
539 #endif /* TW_OSL_DEBUG */
540
541         tw_osli_dbg_dprintf(3, sc, "sc = %p, code = %x, path = %p, arg = %p",
542                 sc, code, path, arg);
543 }
544
545
546
547 /*
548  * Function name:       twa_timeout
549  * Description:         Driver entry point for being alerted on a request
550  *                      timing out.
551  *
552  * Input:               arg     -- ptr to timed out request
553  * Output:              None
554  * Return value:        None
555  */
556 static TW_VOID
557 twa_timeout(TW_VOID *arg)
558 {
559         struct tw_osli_req_context      *req =
560                 (struct tw_osli_req_context *)arg;
561
562         tw_cl_create_event(&(req->ctlr->ctlr_handle), TW_CL_TRUE,
563                 TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
564                 0x210B, 0x1, TW_CL_SEVERITY_ERROR_STRING,
565                 "Request timed out!",
566                 "request = %p", req);
567         tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle));
568 }
569
570
571
572 /*
573  * Function name:       tw_osli_request_bus_scan
574  * Description:         Requests CAM for a scan of the bus.
575  *
576  * Input:               sc      -- ptr to per ctlr structure
577  * Output:              None
578  * Return value:        0       -- success
579  *                      non-zero-- failure
580  */
581 TW_INT32
582 tw_osli_request_bus_scan(struct twa_softc *sc)
583 {
584         struct cam_path *path;
585         union ccb       *ccb;
586
587         tw_osli_dbg_dprintf(3, sc, "entering");
588
589         /* If we get here before sc->sim is initialized, return an error. */
590         if (!(sc->sim))
591                 return(ENXIO);
592         if ((ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK)) == NULL)
593                 return(ENOMEM);
594         bzero(ccb, sizeof(union ccb));
595         mtx_lock(&Giant);
596         if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->sim),
597                 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP)
598                 return(EIO);
599
600         xpt_setup_ccb(&ccb->ccb_h, path, 5);
601         ccb->ccb_h.func_code = XPT_SCAN_BUS;
602         ccb->ccb_h.cbfcnp = twa_bus_scan_cb;
603         ccb->crcn.flags = CAM_FLAG_NONE;
604         xpt_action(ccb);
605         mtx_unlock(&Giant);
606         return(0);
607 }
608
609
610
611 /*
612  * Function name:       twa_bus_scan_cb
613  * Description:         Callback from CAM on a bus scan request.
614  *
615  * Input:               periph  -- we don't use this
616  *                      ccb     -- bus scan request ccb that we sent to CAM
617  * Output:              None
618  * Return value:        None
619  */
620 static TW_VOID
621 twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb)
622 {
623         tw_osli_dbg_printf(3, "entering");
624
625         if (ccb->ccb_h.status != CAM_REQ_CMP)
626                 printf("cam_scan_callback: failure status = %x\n",
627                         ccb->ccb_h.status);
628         else
629                 tw_osli_dbg_printf(3, "success");
630
631         xpt_free_path(ccb->ccb_h.path);
632         free(ccb, M_TEMP);
633 }
634
635
636
637 /*
638  * Function name:       tw_osli_allow_new_requests
639  * Description:         Sets the appropriate status bits in a ccb such that,
640  *                      when the ccb is completed by a call to xpt_done,
641  *                      CAM knows that it's ok to unfreeze the flow of new
642  *                      requests to this controller, if the flow is frozen.
643  *
644  * Input:               sc      -- ptr to OSL internal ctlr context
645  *                      ccb     -- ptr to CAM request
646  * Output:              None
647  * Return value:        None
648  */
649 TW_VOID
650 tw_osli_allow_new_requests(struct twa_softc *sc, TW_VOID *ccb)
651 {
652         ((union ccb *)(ccb))->ccb_h.status |= CAM_RELEASE_SIMQ;
653         sc->state &= ~TW_OSLI_CTLR_STATE_SIMQ_FROZEN;
654 }
655
656
657
658 /*
659  * Function name:       tw_osli_disallow_new_requests
660  * Description:         Calls the appropriate CAM function, so as to freeze
661  *                      the flow of new requests from CAM to this controller.
662  *
663  * Input:               sc      -- ptr to OSL internal ctlr context
664  * Output:              None
665  * Return value:        None
666  */
667 TW_VOID
668 tw_osli_disallow_new_requests(struct twa_softc *sc)
669 {
670         mtx_lock(&Giant);
671         xpt_freeze_simq(sc->sim, 1);
672         mtx_unlock(&Giant);
673         sc->state |= TW_OSLI_CTLR_STATE_SIMQ_FROZEN;
674 }
675
676
677
678 /*
679  * Function name:       tw_osl_ctlr_busy
680  * Description:         CL calls this function on cmd queue full or otherwise,
681  *                      when it is too busy to accept new requests.
682  *
683  * Input:               ctlr_handle     -- ptr to controller handle
684  *                      req_handle      -- ptr to request handle sent by OSL.
685  * Output:              None
686  * Return value:        None
687  */
688 TW_VOID
689 tw_osl_ctlr_busy(struct tw_cl_ctlr_handle *ctlr_handle,
690         struct tw_cl_req_handle *req_handle)
691 {
692         tw_osli_disallow_new_requests(ctlr_handle->osl_ctlr_ctxt);
693 }
694
695
696
697 /*
698  * Function name:       tw_osl_scan_bus
699  * Description:         CL calls this function to request for a bus scan.
700  *
701  * Input:               ctlr_handle     -- ptr to controller handle
702  * Output:              None
703  * Return value:        None
704  */
705 TW_VOID
706 tw_osl_scan_bus(struct tw_cl_ctlr_handle *ctlr_handle)
707 {
708         struct twa_softc        *sc = ctlr_handle->osl_ctlr_ctxt;
709         TW_INT32                error;
710
711         if ((error = tw_osli_request_bus_scan(sc)))
712                 tw_osli_printf(sc, "error = %d",
713                         TW_CL_SEVERITY_ERROR_STRING,
714                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
715                         0x2109,
716                         "Bus scan request to CAM failed",
717                         error);
718 }
719
720
721
722 /*
723  * Function name:       tw_osl_complete_io
724  * Description:         Called to complete CAM scsi requests.
725  *
726  * Input:               req_handle      -- ptr to request handle
727  * Output:              None
728  * Return value:        None
729  */
730 TW_VOID
731 tw_osl_complete_io(struct tw_cl_req_handle *req_handle)
732 {
733         struct tw_osli_req_context      *req = req_handle->osl_req_ctxt;
734         struct tw_cl_req_packet         *req_pkt =
735                 (struct tw_cl_req_packet *)(&req->req_pkt);
736         struct tw_cl_scsi_req_packet    *scsi_req;
737         struct twa_softc                *sc = req->ctlr;
738         union ccb                       *ccb = (union ccb *)(req->orig_req);
739
740         tw_osli_dbg_dprintf(10, sc, "entering");
741
742         if (req->state != TW_OSLI_REQ_STATE_BUSY)
743                 tw_osli_printf(sc, "request = %p, status = %d",
744                         TW_CL_SEVERITY_ERROR_STRING,
745                         TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
746                         0x210A,
747                         "Unposted command completed!!",
748                         req, req->state);
749
750         /*
751          * Remove request from the busy queue.  Just mark it complete.
752          * There's no need to move it into the complete queue as we are
753          * going to be done with it right now.
754          */
755         req->state = TW_OSLI_REQ_STATE_COMPLETE;
756         tw_osli_req_q_remove_item(req, TW_OSLI_BUSY_Q);
757
758         tw_osli_unmap_request(req);
759
760         untimeout(twa_timeout, req, ccb->ccb_h.timeout_ch);
761         if (req->error_code) {
762                 /* This request never got submitted to the firmware. */
763                 if (req->error_code == EBUSY) {
764                         /*
765                          * Cmd queue is full, or the Common Layer is out of
766                          * resources.  The simq will already have been frozen
767                          * by CL's call to tw_osl_ctlr_busy, and this will
768                          * maintain ccb ordering.  The next ccb that gets
769                          * completed will unfreeze the simq.
770                          */
771                         ccb->ccb_h.status |= CAM_REQUEUE_REQ;
772                 }
773                 else if (req->error_code == EFBIG)
774                         ccb->ccb_h.status = CAM_REQ_TOO_BIG;
775                 else
776                         ccb->ccb_h.status = CAM_REQ_CMP_ERR;
777         } else {
778                 scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
779                 if (req_pkt->status == TW_CL_ERR_REQ_SUCCESS)
780                         ccb->ccb_h.status = CAM_REQ_CMP;
781                 else {
782                         if (req_pkt->status & TW_CL_ERR_REQ_INVALID_TARGET)
783                                 ccb->ccb_h.status |= CAM_TID_INVALID;
784                         else if (req_pkt->status & TW_CL_ERR_REQ_INVALID_LUN)
785                                 ccb->ccb_h.status |= CAM_LUN_INVALID;
786                         else if (req_pkt->status & TW_CL_ERR_REQ_SCSI_ERROR)
787                                 ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
788                         else if (req_pkt->status & TW_CL_ERR_REQ_BUS_RESET)
789                                 ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
790                         /*
791                          * If none of the above errors occurred, simply
792                          * mark completion error.
793                          */
794                         if (ccb->ccb_h.status == 0)
795                                 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
796
797                         if (req_pkt->status & TW_CL_ERR_REQ_AUTO_SENSE_VALID) {
798                                 ccb->csio.sense_len = scsi_req->sense_len;
799                                 ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
800                         }
801                 }
802
803                 ccb->csio.scsi_status = scsi_req->scsi_status;
804                 /* If simq is frozen, unfreeze it. */
805                 if (sc->state & TW_OSLI_CTLR_STATE_SIMQ_FROZEN)
806                         tw_osli_allow_new_requests(sc, (TW_VOID *)ccb);
807         }
808
809         ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
810         xpt_done(ccb);
811         if (! req->error_code)
812                  /* twa_action will free the request otherwise */
813                 tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
814 }
815