]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/cam/scsi/scsi_pass.c
MFC r288420: Make pass, sg and targ drivers respect HBA's maxio.
[FreeBSD/stable/10.git] / sys / cam / scsi / scsi_pass.c
1 /*-
2  * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
3  * Copyright (c) 1997, 1998, 1999 Kenneth D. Merry.
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  *    without modification, immediately at the beginning of the file.
12  * 2. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission.
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 FOR
19  * 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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/types.h>
35 #include <sys/bio.h>
36 #include <sys/malloc.h>
37 #include <sys/fcntl.h>
38 #include <sys/conf.h>
39 #include <sys/errno.h>
40 #include <sys/devicestat.h>
41 #include <sys/proc.h>
42 #include <sys/taskqueue.h>
43
44 #include <cam/cam.h>
45 #include <cam/cam_ccb.h>
46 #include <cam/cam_periph.h>
47 #include <cam/cam_queue.h>
48 #include <cam/cam_xpt_periph.h>
49 #include <cam/cam_debug.h>
50 #include <cam/cam_sim.h>
51 #include <cam/cam_compat.h>
52
53 #include <cam/scsi/scsi_all.h>
54 #include <cam/scsi/scsi_pass.h>
55
56 typedef enum {
57         PASS_FLAG_OPEN                  = 0x01,
58         PASS_FLAG_LOCKED                = 0x02,
59         PASS_FLAG_INVALID               = 0x04,
60         PASS_FLAG_INITIAL_PHYSPATH      = 0x08
61 } pass_flags;
62
63 typedef enum {
64         PASS_STATE_NORMAL
65 } pass_state;
66
67 typedef enum {
68         PASS_CCB_BUFFER_IO
69 } pass_ccb_types;
70
71 #define ccb_type        ppriv_field0
72 #define ccb_bp          ppriv_ptr1
73
74 struct pass_softc {
75         pass_state       state;
76         pass_flags       flags;
77         u_int8_t         pd_type;
78         union ccb        saved_ccb;
79         int              open_count;
80         u_int            maxio;
81         struct devstat  *device_stats;
82         struct cdev     *dev;
83         struct cdev     *alias_dev;
84         struct task      add_physpath_task;
85 };
86
87
88 static  d_open_t        passopen;
89 static  d_close_t       passclose;
90 static  d_ioctl_t       passioctl;
91 static  d_ioctl_t       passdoioctl;
92
93 static  periph_init_t   passinit;
94 static  periph_ctor_t   passregister;
95 static  periph_oninv_t  passoninvalidate;
96 static  periph_dtor_t   passcleanup;
97 static void             pass_add_physpath(void *context, int pending);
98 static  void            passasync(void *callback_arg, u_int32_t code,
99                                   struct cam_path *path, void *arg);
100 static  int             passerror(union ccb *ccb, u_int32_t cam_flags, 
101                                   u_int32_t sense_flags);
102 static  int             passsendccb(struct cam_periph *periph, union ccb *ccb,
103                                     union ccb *inccb);
104
105 static struct periph_driver passdriver =
106 {
107         passinit, "pass",
108         TAILQ_HEAD_INITIALIZER(passdriver.units), /* generation */ 0
109 };
110
111 PERIPHDRIVER_DECLARE(pass, passdriver);
112
113 static struct cdevsw pass_cdevsw = {
114         .d_version =    D_VERSION,
115         .d_flags =      D_TRACKCLOSE,
116         .d_open =       passopen,
117         .d_close =      passclose,
118         .d_ioctl =      passioctl,
119         .d_name =       "pass",
120 };
121
122 static void
123 passinit(void)
124 {
125         cam_status status;
126
127         /*
128          * Install a global async callback.  This callback will
129          * receive async callbacks like "new device found".
130          */
131         status = xpt_register_async(AC_FOUND_DEVICE, passasync, NULL, NULL);
132
133         if (status != CAM_REQ_CMP) {
134                 printf("pass: Failed to attach master async callback "
135                        "due to status 0x%x!\n", status);
136         }
137
138 }
139
140 static void
141 passdevgonecb(void *arg)
142 {
143         struct cam_periph *periph;
144         struct mtx *mtx;
145         struct pass_softc *softc;
146         int i;
147
148         periph = (struct cam_periph *)arg;
149         mtx = cam_periph_mtx(periph);
150         mtx_lock(mtx);
151
152         softc = (struct pass_softc *)periph->softc;
153         KASSERT(softc->open_count >= 0, ("Negative open count %d",
154                 softc->open_count));
155
156         /*
157          * When we get this callback, we will get no more close calls from
158          * devfs.  So if we have any dangling opens, we need to release the
159          * reference held for that particular context.
160          */
161         for (i = 0; i < softc->open_count; i++)
162                 cam_periph_release_locked(periph);
163
164         softc->open_count = 0;
165
166         /*
167          * Release the reference held for the device node, it is gone now.
168          */
169         cam_periph_release_locked(periph);
170
171         /*
172          * We reference the lock directly here, instead of using
173          * cam_periph_unlock().  The reason is that the final call to
174          * cam_periph_release_locked() above could result in the periph
175          * getting freed.  If that is the case, dereferencing the periph
176          * with a cam_periph_unlock() call would cause a page fault.
177          */
178         mtx_unlock(mtx);
179 }
180
181 static void
182 passoninvalidate(struct cam_periph *periph)
183 {
184         struct pass_softc *softc;
185
186         softc = (struct pass_softc *)periph->softc;
187
188         /*
189          * De-register any async callbacks.
190          */
191         xpt_register_async(0, passasync, periph, periph->path);
192
193         softc->flags |= PASS_FLAG_INVALID;
194
195         /*
196          * Tell devfs this device has gone away, and ask for a callback
197          * when it has cleaned up its state.
198          */
199         destroy_dev_sched_cb(softc->dev, passdevgonecb, periph);
200
201         /*
202          * XXX Return all queued I/O with ENXIO.
203          * XXX Handle any transactions queued to the card
204          *     with XPT_ABORT_CCB.
205          */
206 }
207
208 static void
209 passcleanup(struct cam_periph *periph)
210 {
211         struct pass_softc *softc;
212
213         softc = (struct pass_softc *)periph->softc;
214
215         devstat_remove_entry(softc->device_stats);
216
217         cam_periph_unlock(periph);
218         taskqueue_drain(taskqueue_thread, &softc->add_physpath_task);
219
220         cam_periph_lock(periph);
221
222         free(softc, M_DEVBUF);
223 }
224
225 static void
226 pass_add_physpath(void *context, int pending)
227 {
228         struct cam_periph *periph;
229         struct pass_softc *softc;
230         char *physpath;
231
232         /*
233          * If we have one, create a devfs alias for our
234          * physical path.
235          */
236         periph = context;
237         softc = periph->softc;
238         physpath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK);
239         cam_periph_lock(periph);
240         if (periph->flags & CAM_PERIPH_INVALID) {
241                 cam_periph_unlock(periph);
242                 goto out;
243         }
244         if (xpt_getattr(physpath, MAXPATHLEN,
245                         "GEOM::physpath", periph->path) == 0
246          && strlen(physpath) != 0) {
247
248                 cam_periph_unlock(periph);
249                 make_dev_physpath_alias(MAKEDEV_WAITOK, &softc->alias_dev,
250                                         softc->dev, softc->alias_dev, physpath);
251                 cam_periph_lock(periph);
252         }
253
254         /*
255          * Now that we've made our alias, we no longer have to have a
256          * reference to the device.
257          */
258         if ((softc->flags & PASS_FLAG_INITIAL_PHYSPATH) == 0) {
259                 softc->flags |= PASS_FLAG_INITIAL_PHYSPATH;
260                 cam_periph_unlock(periph);
261                 dev_rel(softc->dev);
262         }
263         else
264                 cam_periph_unlock(periph);
265
266 out:
267         free(physpath, M_DEVBUF);
268 }
269
270 static void
271 passasync(void *callback_arg, u_int32_t code,
272           struct cam_path *path, void *arg)
273 {
274         struct cam_periph *periph;
275
276         periph = (struct cam_periph *)callback_arg;
277
278         switch (code) {
279         case AC_FOUND_DEVICE:
280         {
281                 struct ccb_getdev *cgd;
282                 cam_status status;
283  
284                 cgd = (struct ccb_getdev *)arg;
285                 if (cgd == NULL)
286                         break;
287
288                 /*
289                  * Allocate a peripheral instance for
290                  * this device and start the probe
291                  * process.
292                  */
293                 status = cam_periph_alloc(passregister, passoninvalidate,
294                                           passcleanup, NULL, "pass",
295                                           CAM_PERIPH_BIO, path,
296                                           passasync, AC_FOUND_DEVICE, cgd);
297
298                 if (status != CAM_REQ_CMP
299                  && status != CAM_REQ_INPROG) {
300                         const struct cam_status_entry *entry;
301
302                         entry = cam_fetch_status_entry(status);
303
304                         printf("passasync: Unable to attach new device "
305                                "due to status %#x: %s\n", status, entry ?
306                                entry->status_text : "Unknown");
307                 }
308
309                 break;
310         }
311         case AC_ADVINFO_CHANGED:
312         {
313                 uintptr_t buftype;
314
315                 buftype = (uintptr_t)arg;
316                 if (buftype == CDAI_TYPE_PHYS_PATH) {
317                         struct pass_softc *softc;
318
319                         softc = (struct pass_softc *)periph->softc;
320                         taskqueue_enqueue(taskqueue_thread,
321                                           &softc->add_physpath_task);
322                 }
323                 break;
324         }
325         default:
326                 cam_periph_async(periph, code, path, arg);
327                 break;
328         }
329 }
330
331 static cam_status
332 passregister(struct cam_periph *periph, void *arg)
333 {
334         struct pass_softc *softc;
335         struct ccb_getdev *cgd;
336         struct ccb_pathinq cpi;
337         int    no_tags;
338
339         cgd = (struct ccb_getdev *)arg;
340         if (cgd == NULL) {
341                 printf("%s: no getdev CCB, can't register device\n", __func__);
342                 return(CAM_REQ_CMP_ERR);
343         }
344
345         softc = (struct pass_softc *)malloc(sizeof(*softc),
346                                             M_DEVBUF, M_NOWAIT);
347
348         if (softc == NULL) {
349                 printf("%s: Unable to probe new device. "
350                        "Unable to allocate softc\n", __func__);
351                 return(CAM_REQ_CMP_ERR);
352         }
353
354         bzero(softc, sizeof(*softc));
355         softc->state = PASS_STATE_NORMAL;
356         if (cgd->protocol == PROTO_SCSI || cgd->protocol == PROTO_ATAPI)
357                 softc->pd_type = SID_TYPE(&cgd->inq_data);
358         else if (cgd->protocol == PROTO_SATAPM)
359                 softc->pd_type = T_ENCLOSURE;
360         else
361                 softc->pd_type = T_DIRECT;
362
363         periph->softc = softc;
364
365         bzero(&cpi, sizeof(cpi));
366         xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
367         cpi.ccb_h.func_code = XPT_PATH_INQ;
368         xpt_action((union ccb *)&cpi);
369
370         if (cpi.maxio == 0)
371                 softc->maxio = DFLTPHYS;        /* traditional default */
372         else if (cpi.maxio > MAXPHYS)
373                 softc->maxio = MAXPHYS;         /* for safety */
374         else
375                 softc->maxio = cpi.maxio;       /* real value */
376
377         /*
378          * We pass in 0 for a blocksize, since we don't 
379          * know what the blocksize of this device is, if 
380          * it even has a blocksize.
381          */
382         cam_periph_unlock(periph);
383         no_tags = (cgd->inq_data.flags & SID_CmdQue) == 0;
384         softc->device_stats = devstat_new_entry("pass",
385                           periph->unit_number, 0,
386                           DEVSTAT_NO_BLOCKSIZE
387                           | (no_tags ? DEVSTAT_NO_ORDERED_TAGS : 0),
388                           softc->pd_type |
389                           XPORT_DEVSTAT_TYPE(cpi.transport) |
390                           DEVSTAT_TYPE_PASS,
391                           DEVSTAT_PRIORITY_PASS);
392
393         /*
394          * Acquire a reference to the periph before we create the devfs
395          * instance for it.  We'll release this reference once the devfs
396          * instance has been freed.
397          */
398         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
399                 xpt_print(periph->path, "%s: lost periph during "
400                           "registration!\n", __func__);
401                 cam_periph_lock(periph);
402                 return (CAM_REQ_CMP_ERR);
403         }
404
405         /* Register the device */
406         softc->dev = make_dev(&pass_cdevsw, periph->unit_number,
407                               UID_ROOT, GID_OPERATOR, 0600, "%s%d",
408                               periph->periph_name, periph->unit_number);
409
410         /*
411          * Now that we have made the devfs instance, hold a reference to it
412          * until the task queue has run to setup the physical path alias.
413          * That way devfs won't get rid of the device before we add our
414          * alias.
415          */
416         dev_ref(softc->dev);
417
418         cam_periph_lock(periph);
419         softc->dev->si_drv1 = periph;
420
421         TASK_INIT(&softc->add_physpath_task, /*priority*/0,
422                   pass_add_physpath, periph);
423
424         /*
425          * See if physical path information is already available.
426          */
427         taskqueue_enqueue(taskqueue_thread, &softc->add_physpath_task);
428
429         /*
430          * Add an async callback so that we get notified if
431          * this device goes away or its physical path
432          * (stored in the advanced info data of the EDT) has
433          * changed.
434          */
435         xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
436                            passasync, periph, periph->path);
437
438         if (bootverbose)
439                 xpt_announce_periph(periph, NULL);
440
441         return(CAM_REQ_CMP);
442 }
443
444 static int
445 passopen(struct cdev *dev, int flags, int fmt, struct thread *td)
446 {
447         struct cam_periph *periph;
448         struct pass_softc *softc;
449         int error;
450
451         periph = (struct cam_periph *)dev->si_drv1;
452         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
453                 return (ENXIO);
454
455         cam_periph_lock(periph);
456
457         softc = (struct pass_softc *)periph->softc;
458
459         if (softc->flags & PASS_FLAG_INVALID) {
460                 cam_periph_release_locked(periph);
461                 cam_periph_unlock(periph);
462                 return(ENXIO);
463         }
464
465         /*
466          * Don't allow access when we're running at a high securelevel.
467          */
468         error = securelevel_gt(td->td_ucred, 1);
469         if (error) {
470                 cam_periph_release_locked(periph);
471                 cam_periph_unlock(periph);
472                 return(error);
473         }
474
475         /*
476          * Only allow read-write access.
477          */
478         if (((flags & FWRITE) == 0) || ((flags & FREAD) == 0)) {
479                 cam_periph_release_locked(periph);
480                 cam_periph_unlock(periph);
481                 return(EPERM);
482         }
483
484         /*
485          * We don't allow nonblocking access.
486          */
487         if ((flags & O_NONBLOCK) != 0) {
488                 xpt_print(periph->path, "can't do nonblocking access\n");
489                 cam_periph_release_locked(periph);
490                 cam_periph_unlock(periph);
491                 return(EINVAL);
492         }
493
494         softc->open_count++;
495
496         cam_periph_unlock(periph);
497
498         return (error);
499 }
500
501 static int
502 passclose(struct cdev *dev, int flag, int fmt, struct thread *td)
503 {
504         struct  cam_periph *periph;
505         struct  pass_softc *softc;
506         struct mtx *mtx;
507
508         periph = (struct cam_periph *)dev->si_drv1;
509         if (periph == NULL)
510                 return (ENXIO); 
511         mtx = cam_periph_mtx(periph);
512         mtx_lock(mtx);
513
514         softc = periph->softc;
515         softc->open_count--;
516
517         cam_periph_release_locked(periph);
518
519         /*
520          * We reference the lock directly here, instead of using
521          * cam_periph_unlock().  The reason is that the call to
522          * cam_periph_release_locked() above could result in the periph
523          * getting freed.  If that is the case, dereferencing the periph
524          * with a cam_periph_unlock() call would cause a page fault.
525          *
526          * cam_periph_release() avoids this problem using the same method,
527          * but we're manually acquiring and dropping the lock here to
528          * protect the open count and avoid another lock acquisition and
529          * release.
530          */
531         mtx_unlock(mtx);
532
533         return (0);
534 }
535
536 static int
537 passioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
538 {
539         int error;
540
541         if ((error = passdoioctl(dev, cmd, addr, flag, td)) == ENOTTY) {
542                 error = cam_compat_ioctl(dev, cmd, addr, flag, td, passdoioctl);
543         }
544         return (error);
545 }
546
547 static int
548 passdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
549 {
550         struct  cam_periph *periph;
551         struct  pass_softc *softc;
552         int     error;
553         uint32_t priority;
554
555         periph = (struct cam_periph *)dev->si_drv1;
556         if (periph == NULL)
557                 return(ENXIO);
558
559         cam_periph_lock(periph);
560         softc = (struct pass_softc *)periph->softc;
561
562         error = 0;
563
564         switch (cmd) {
565
566         case CAMIOCOMMAND:
567         {
568                 union ccb *inccb;
569                 union ccb *ccb;
570                 int ccb_malloced;
571
572                 inccb = (union ccb *)addr;
573
574                 /*
575                  * Some CCB types, like scan bus and scan lun can only go
576                  * through the transport layer device.
577                  */
578                 if (inccb->ccb_h.func_code & XPT_FC_XPT_ONLY) {
579                         xpt_print(periph->path, "CCB function code %#x is "
580                             "restricted to the XPT device\n",
581                             inccb->ccb_h.func_code);
582                         error = ENODEV;
583                         break;
584                 }
585
586                 /* Compatibility for RL/priority-unaware code. */
587                 priority = inccb->ccb_h.pinfo.priority;
588                 if (priority <= CAM_PRIORITY_OOB)
589                     priority += CAM_PRIORITY_OOB + 1;
590
591                 /*
592                  * Non-immediate CCBs need a CCB from the per-device pool
593                  * of CCBs, which is scheduled by the transport layer.
594                  * Immediate CCBs and user-supplied CCBs should just be
595                  * malloced.
596                  */
597                 if ((inccb->ccb_h.func_code & XPT_FC_QUEUED)
598                  && ((inccb->ccb_h.func_code & XPT_FC_USER_CCB) == 0)) {
599                         ccb = cam_periph_getccb(periph, priority);
600                         ccb_malloced = 0;
601                 } else {
602                         ccb = xpt_alloc_ccb_nowait();
603
604                         if (ccb != NULL)
605                                 xpt_setup_ccb(&ccb->ccb_h, periph->path,
606                                               priority);
607                         ccb_malloced = 1;
608                 }
609
610                 if (ccb == NULL) {
611                         xpt_print(periph->path, "unable to allocate CCB\n");
612                         error = ENOMEM;
613                         break;
614                 }
615
616                 error = passsendccb(periph, ccb, inccb);
617
618                 if (ccb_malloced)
619                         xpt_free_ccb(ccb);
620                 else
621                         xpt_release_ccb(ccb);
622
623                 break;
624         }
625         default:
626                 error = cam_periph_ioctl(periph, cmd, addr, passerror);
627                 break;
628         }
629
630         cam_periph_unlock(periph);
631         return(error);
632 }
633
634 /*
635  * Generally, "ccb" should be the CCB supplied by the kernel.  "inccb"
636  * should be the CCB that is copied in from the user.
637  */
638 static int
639 passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
640 {
641         struct pass_softc *softc;
642         struct cam_periph_map_info mapinfo;
643         xpt_opcode fc;
644         int error;
645
646         softc = (struct pass_softc *)periph->softc;
647
648         /*
649          * There are some fields in the CCB header that need to be
650          * preserved, the rest we get from the user.
651          */
652         xpt_merge_ccb(ccb, inccb);
653
654         /*
655          * Let cam_periph_mapmem do a sanity check on the data pointer format.
656          * Even if no data transfer is needed, it's a cheap check and it
657          * simplifies the code.
658          */
659         fc = ccb->ccb_h.func_code;
660         if ((fc == XPT_SCSI_IO) || (fc == XPT_ATA_IO) || (fc == XPT_SMP_IO)
661          || (fc == XPT_DEV_MATCH) || (fc == XPT_DEV_ADVINFO)) {
662                 bzero(&mapinfo, sizeof(mapinfo));
663
664                 /*
665                  * cam_periph_mapmem calls into proc and vm functions that can
666                  * sleep as well as trigger I/O, so we can't hold the lock.
667                  * Dropping it here is reasonably safe.
668                  */
669                 cam_periph_unlock(periph);
670                 error = cam_periph_mapmem(ccb, &mapinfo, softc->maxio);
671                 cam_periph_lock(periph);
672
673                 /*
674                  * cam_periph_mapmem returned an error, we can't continue.
675                  * Return the error to the user.
676                  */
677                 if (error)
678                         return(error);
679         } else
680                 /* Ensure that the unmap call later on is a no-op. */
681                 mapinfo.num_bufs_used = 0;
682
683         /*
684          * If the user wants us to perform any error recovery, then honor
685          * that request.  Otherwise, it's up to the user to perform any
686          * error recovery.
687          */
688         cam_periph_runccb(ccb, passerror, /* cam_flags */ CAM_RETRY_SELTO,
689             /* sense_flags */ ((ccb->ccb_h.flags & CAM_PASS_ERR_RECOVER) ?
690              SF_RETRY_UA : SF_NO_RECOVERY) | SF_NO_PRINT,
691             softc->device_stats);
692
693         cam_periph_unmapmem(ccb, &mapinfo);
694
695         ccb->ccb_h.cbfcnp = NULL;
696         ccb->ccb_h.periph_priv = inccb->ccb_h.periph_priv;
697         bcopy(ccb, inccb, sizeof(union ccb));
698
699         return(0);
700 }
701
702 static int
703 passerror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
704 {
705         struct cam_periph *periph;
706         struct pass_softc *softc;
707
708         periph = xpt_path_periph(ccb->ccb_h.path);
709         softc = (struct pass_softc *)periph->softc;
710         
711         return(cam_periph_error(ccb, cam_flags, sense_flags, 
712                                  &softc->saved_ccb));
713 }