kernel: Remove most definitions of CDEV_MAJOR.
[dragonfly.git] / sys / bus / cam / scsi / scsi_pt.c
1 /*
2  * Implementation of SCSI Processor Target Peripheral driver for CAM.
3  *
4  * Copyright (c) 1998 Justin T. Gibbs.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/cam/scsi/scsi_pt.c,v 1.17 2000/01/17 06:27:37 mjacob Exp $
29  */
30
31 #include <sys/param.h>
32 #include <sys/queue.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/types.h>
36 #include <sys/buf.h>
37 #include <sys/devicestat.h>
38 #include <sys/malloc.h>
39 #include <sys/conf.h>
40 #include <sys/ptio.h>
41 #include <sys/buf2.h>
42 #include <sys/thread2.h>
43
44 #include "../cam.h"
45 #include "../cam_ccb.h"
46 #include "../cam_extend.h"
47 #include "../cam_periph.h"
48 #include "../cam_xpt_periph.h"
49 #include "../cam_debug.h"
50
51 #include "scsi_all.h"
52 #include "scsi_message.h"
53 #include "scsi_pt.h"
54
55 #include "opt_pt.h"
56
57 typedef enum {
58         PT_STATE_PROBE,
59         PT_STATE_NORMAL
60 } pt_state;
61
62 typedef enum {
63         PT_FLAG_NONE            = 0x00,
64         PT_FLAG_OPEN            = 0x01,
65         PT_FLAG_DEVICE_INVALID  = 0x02,
66         PT_FLAG_RETRY_UA        = 0x04
67 } pt_flags;
68
69 typedef enum {
70         PT_CCB_BUFFER_IO        = 0x01,
71         PT_CCB_WAITING          = 0x02,
72         PT_CCB_RETRY_UA         = 0x04,
73         PT_CCB_BUFFER_IO_UA     = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
74 } pt_ccb_state;
75
76 /* Offsets into our private area for storing information */
77 #define ccb_state       ppriv_field0
78 #define ccb_bio         ppriv_ptr1
79
80 struct pt_softc {
81         struct   bio_queue_head bio_queue;
82         struct   devstat device_stats;
83         LIST_HEAD(, ccb_hdr) pending_ccbs;
84         pt_state state;
85         pt_flags flags; 
86         union    ccb saved_ccb;
87         int      io_timeout;
88         cdev_t   dev;
89 };
90
91 static  d_open_t        ptopen;
92 static  d_close_t       ptclose;
93 static  d_strategy_t    ptstrategy;
94 static  periph_init_t   ptinit;
95 static  void            ptasync(void *callback_arg, u_int32_t code,
96                                 struct cam_path *path, void *arg);
97 static  periph_ctor_t   ptctor;
98 static  periph_oninv_t  ptoninvalidate;
99 static  periph_dtor_t   ptdtor;
100 static  periph_start_t  ptstart;
101 static  void            ptdone(struct cam_periph *periph,
102                                union ccb *done_ccb);
103 static  d_ioctl_t       ptioctl;
104 static  int             pterror(union ccb *ccb, u_int32_t cam_flags,
105                                 u_int32_t sense_flags);
106
107 void    scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
108                           void (*cbfcnp)(struct cam_periph *, union ccb *),
109                           u_int tag_action, int readop, u_int byte2,
110                           u_int32_t xfer_len, u_int8_t *data_ptr,
111                           u_int8_t sense_len, u_int32_t timeout);
112
113 static struct periph_driver ptdriver =
114 {
115         ptinit, "pt",
116         TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
117 };
118
119 PERIPHDRIVER_DECLARE(pt, ptdriver);
120
121 static struct dev_ops pt_ops = {
122         { "pt", 0, 0 },
123         .d_open =       ptopen,
124         .d_close =      ptclose,
125         .d_read =       physread,
126         .d_write =      physwrite,
127         .d_ioctl =      ptioctl,
128         .d_strategy =   ptstrategy,
129 };
130
131 static struct extend_array *ptperiphs;
132
133 #ifndef SCSI_PT_DEFAULT_TIMEOUT
134 #define SCSI_PT_DEFAULT_TIMEOUT         60
135 #endif
136
137 static int
138 ptopen(struct dev_open_args *ap)
139 {
140         cdev_t dev = ap->a_head.a_dev;
141         struct cam_periph *periph;
142         struct pt_softc *softc;
143         int unit;
144         int error = 0;
145
146         unit = minor(dev);
147         periph = cam_extend_get(ptperiphs, unit);
148         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
149                 return (ENXIO); 
150
151         softc = (struct pt_softc *)periph->softc;
152
153         cam_periph_lock(periph);
154         if (softc->flags & PT_FLAG_DEVICE_INVALID) {
155                 cam_periph_unlock(periph);
156                 cam_periph_release(periph);
157                 return(ENXIO);
158         }
159
160         if ((softc->flags & PT_FLAG_OPEN) == 0)
161                 softc->flags |= PT_FLAG_OPEN;
162         else {
163                 error = EBUSY;
164                 cam_periph_release(periph);
165         }
166
167         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
168             ("ptopen: dev=%s\n", devtoname(dev)));
169
170         cam_periph_unlock(periph);
171         return (error);
172 }
173
174 static int
175 ptclose(struct dev_close_args *ap)
176 {
177         cdev_t dev = ap->a_head.a_dev;
178         struct  cam_periph *periph;
179         struct  pt_softc *softc;
180         int     unit;
181
182         unit = minor(dev);
183         periph = cam_extend_get(ptperiphs, unit);
184         if (periph == NULL)
185                 return (ENXIO); 
186
187         softc = (struct pt_softc *)periph->softc;
188
189         cam_periph_lock(periph);
190
191         softc->flags &= ~PT_FLAG_OPEN;
192         cam_periph_unlock(periph);
193         cam_periph_release(periph);
194         return (0);
195 }
196
197 /*
198  * Actually translate the requested transfer into one the physical driver
199  * can understand.  The transfer is described by a buf and will include
200  * only one physical transfer.
201  */
202 static int
203 ptstrategy(struct dev_strategy_args *ap)
204 {
205         cdev_t dev = ap->a_head.a_dev;
206         struct bio *bio = ap->a_bio;
207         struct buf *bp = bio->bio_buf;
208         struct cam_periph *periph;
209         struct pt_softc *softc;
210         u_int  unit;
211         
212         unit = minor(dev);
213         periph = cam_extend_get(ptperiphs, unit);
214         if (periph == NULL) {
215                 bp->b_error = ENXIO;
216                 goto bad;               
217         }
218         cam_periph_lock(periph);
219         softc = (struct pt_softc *)periph->softc;
220
221         /*
222          * If the device has been made invalid, error out
223          */
224         if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
225                 cam_periph_unlock(periph);
226                 bp->b_error = ENXIO;
227                 goto bad;
228         }
229         
230         /*
231          * Place it in the queue of disk activities for this disk
232          */
233         bioq_insert_tail(&softc->bio_queue, bio);
234         
235         /*
236          * Schedule ourselves for performing the work.
237          */
238         xpt_schedule(periph, /* XXX priority */1);
239         cam_periph_unlock(periph);
240
241         return(0);
242 bad:
243         bp->b_flags |= B_ERROR;
244
245         /*
246          * Correctly set the buf to indicate a completed xfer
247          */
248         bp->b_resid = bp->b_bcount;
249         biodone(bio);
250         return(0);
251 }
252
253 static void
254 ptinit(void)
255 {
256         cam_status status;
257
258         /*
259          * Create our extend array for storing the devices we attach to.
260          */
261         ptperiphs = cam_extend_new();
262         if (ptperiphs == NULL) {
263                 kprintf("pt: Failed to alloc extend array!\n");
264                 return;
265         }
266         
267         /*
268          * Install a global async callback.  This callback will
269          * receive async callbacks like "new device found".
270          */
271         status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL);
272
273         if (status != CAM_REQ_CMP) {
274                 kprintf("pt: Failed to attach master async callback "
275                        "due to status 0x%x!\n", status);
276         }
277 }
278
279 static cam_status
280 ptctor(struct cam_periph *periph, void *arg)
281 {
282         struct pt_softc *softc;
283         struct ccb_getdev *cgd;
284
285         cgd = (struct ccb_getdev *)arg;
286         if (periph == NULL) {
287                 kprintf("ptregister: periph was NULL!!\n");
288                 return(CAM_REQ_CMP_ERR);
289         }
290
291         if (cgd == NULL) {
292                 kprintf("ptregister: no getdev CCB, can't register device\n");
293                 return(CAM_REQ_CMP_ERR);
294         }
295
296         softc = kmalloc(sizeof(*softc), M_DEVBUF, M_INTWAIT | M_ZERO);
297         LIST_INIT(&softc->pending_ccbs);
298         softc->state = PT_STATE_NORMAL;
299         bioq_init(&softc->bio_queue);
300
301         softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
302
303         periph->softc = softc;
304         
305         cam_periph_unlock(periph);
306         cam_extend_set(ptperiphs, periph->unit_number, periph);
307
308         devstat_add_entry(&softc->device_stats, "pt",
309                           periph->unit_number, 0,
310                           DEVSTAT_NO_BLOCKSIZE,
311                           SID_TYPE(&cgd->inq_data) | DEVSTAT_TYPE_IF_SCSI,
312                           DEVSTAT_PRIORITY_OTHER);
313
314         make_dev(&pt_ops, periph->unit_number, UID_ROOT,
315                   GID_OPERATOR, 0600, "%s%d", periph->periph_name,
316                   periph->unit_number);
317         cam_periph_lock(periph);
318         /*
319          * Add async callbacks for bus reset and
320          * bus device reset calls.  I don't bother
321          * checking if this fails as, in most cases,
322          * the system will function just fine without
323          * them and the only alternative would be to
324          * not attach the device on failure.
325          */
326         xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
327                            ptasync, periph, periph->path);
328
329         /* Tell the user we've attached to the device */
330         xpt_announce_periph(periph, NULL);
331
332         return(CAM_REQ_CMP);
333 }
334
335 static void
336 ptoninvalidate(struct cam_periph *periph)
337 {
338         struct pt_softc *softc;
339         struct bio *q_bio;
340         struct buf *q_bp;
341
342         softc = (struct pt_softc *)periph->softc;
343
344         /*
345          * De-register any async callbacks.
346          */
347         xpt_register_async(0, ptasync, periph, periph->path);
348
349         softc->flags |= PT_FLAG_DEVICE_INVALID;
350
351         /*
352          * Return all queued I/O with ENXIO.
353          * XXX Handle any transactions queued to the card
354          *     with XPT_ABORT_CCB.
355          */
356         while ((q_bio = bioq_first(&softc->bio_queue)) != NULL){
357                 bioq_remove(&softc->bio_queue, q_bio);
358                 q_bp = q_bio->bio_buf;
359                 q_bp->b_resid = q_bp->b_bcount;
360                 q_bp->b_error = ENXIO;
361                 q_bp->b_flags |= B_ERROR;
362                 biodone(q_bio);
363         }
364
365         xpt_print(periph->path, "lost device\n");
366 }
367
368 static void
369 ptdtor(struct cam_periph *periph)
370 {
371         struct pt_softc *softc;
372
373         softc = (struct pt_softc *)periph->softc;
374
375         devstat_remove_entry(&softc->device_stats);
376
377         cam_extend_release(ptperiphs, periph->unit_number);
378         xpt_print(periph->path, "removing device entry\n");
379         dev_ops_remove_minor(&pt_ops, periph->unit_number);
380         kfree(softc, M_DEVBUF);
381 }
382
383 static void
384 ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
385 {
386         struct cam_periph *periph;
387
388         periph = (struct cam_periph *)callback_arg;
389         switch (code) {
390         case AC_FOUND_DEVICE:
391         {
392                 struct ccb_getdev *cgd;
393                 cam_status status;
394  
395                 cgd = (struct ccb_getdev *)arg;
396                 if (cgd == NULL)
397                         break;
398
399                 if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
400                         break;
401
402                 /*
403                  * Allocate a peripheral instance for
404                  * this device and start the probe
405                  * process.
406                  */
407                 status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
408                                           ptstart, "pt", CAM_PERIPH_BIO,
409                                           cgd->ccb_h.path, ptasync,
410                                           AC_FOUND_DEVICE, cgd);
411
412                 if (status != CAM_REQ_CMP
413                  && status != CAM_REQ_INPROG)
414                         kprintf("ptasync: Unable to attach to new device "
415                                 "due to status 0x%x\n", status);
416                 break;
417         }
418         case AC_SENT_BDR:
419         case AC_BUS_RESET:
420         {
421                 struct pt_softc *softc;
422                 struct ccb_hdr *ccbh;
423
424                 softc = (struct pt_softc *)periph->softc;
425                 /*
426                  * Don't fail on the expected unit attention
427                  * that will occur.
428                  */
429                 softc->flags |= PT_FLAG_RETRY_UA;
430                 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
431                         ccbh->ccb_state |= PT_CCB_RETRY_UA;
432                 /* FALLTHROUGH */
433         }
434         default:
435                 cam_periph_async(periph, code, path, arg);
436                 break;
437         }
438 }
439
440 static void
441 ptstart(struct cam_periph *periph, union ccb *start_ccb)
442 {
443         struct pt_softc *softc;
444         struct buf *bp;
445         struct bio *bio;
446
447         softc = (struct pt_softc *)periph->softc;
448
449         /*
450          * See if there is a buf with work for us to do..
451          */
452         bio = bioq_first(&softc->bio_queue);
453         if (periph->immediate_priority <= periph->pinfo.priority) {
454                 CAM_DEBUG_PRINT(CAM_DEBUG_SUBTRACE,
455                                 ("queuing for immediate ccb\n"));
456                 start_ccb->ccb_h.ccb_state = PT_CCB_WAITING;
457                 SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
458                                   periph_links.sle);
459                 periph->immediate_priority = CAM_PRIORITY_NONE;
460                 wakeup(&periph->ccb_list);
461         } else if (bio == NULL) {
462                 xpt_release_ccb(start_ccb);
463         } else {
464                 bioq_remove(&softc->bio_queue, bio);
465                 bp = bio->bio_buf;
466
467                 devstat_start_transaction(&softc->device_stats);
468
469                 scsi_send_receive(&start_ccb->csio,
470                                   /*retries*/4,
471                                   ptdone,
472                                   MSG_SIMPLE_Q_TAG,
473                                   (bp->b_cmd == BUF_CMD_READ),
474                                   /*byte2*/0,
475                                   bp->b_bcount,
476                                   bp->b_data,
477                                   /*sense_len*/SSD_FULL_SIZE,
478                                   /*timeout*/softc->io_timeout);
479
480                 start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
481
482                 /*
483                  * Block out any asyncronous callbacks
484                  * while we touch the pending ccb list.
485                  */
486                 LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
487                                  periph_links.le);
488
489                 start_ccb->ccb_h.ccb_bio = bio;
490                 bio = bioq_first(&softc->bio_queue);
491
492                 xpt_action(start_ccb);
493                 
494                 if (bio != NULL) {
495                         /* Have more work to do, so ensure we stay scheduled */
496                         xpt_schedule(periph, /* XXX priority */1);
497                 }
498         }
499 }
500
501 static void
502 ptdone(struct cam_periph *periph, union ccb *done_ccb)
503 {
504         struct pt_softc *softc;
505         struct ccb_scsiio *csio;
506
507         softc = (struct pt_softc *)periph->softc;
508         csio = &done_ccb->csio;
509         switch (csio->ccb_h.ccb_state) {
510         case PT_CCB_BUFFER_IO:
511         case PT_CCB_BUFFER_IO_UA:
512         {
513                 struct buf *bp;
514                 struct bio *bio;
515
516                 bio = (struct bio *)done_ccb->ccb_h.ccb_bio;
517                 bp = bio->bio_buf;
518
519                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
520                         int error;
521                         int sf;
522                         
523                         if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
524                                 sf = SF_RETRY_UA;
525                         else
526                                 sf = 0;
527
528                         error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
529                         if (error == ERESTART) {
530                                 /*
531                                  * A retry was scheuled, so
532                                  * just return.
533                                  */
534                                 return;
535                         }
536                         if (error != 0) {
537                                 struct buf *q_bp;
538                                 struct bio *q_bio;
539
540                                 if (error == ENXIO) {
541                                         /*
542                                          * Catastrophic error.  Mark our device
543                                          * as invalid.
544                                          */
545                                         xpt_print(periph->path,
546                                             "Invalidating device\n");
547                                         softc->flags |= PT_FLAG_DEVICE_INVALID;
548                                 }
549
550                                 /*
551                                  * return all queued I/O with EIO, so that
552                                  * the client can retry these I/Os in the
553                                  * proper order should it attempt to recover.
554                                  */
555                                 while ((q_bio = bioq_first(&softc->bio_queue))
556                                         != NULL) {
557                                         bioq_remove(&softc->bio_queue, q_bio);
558                                         q_bp = q_bio->bio_buf;
559                                         q_bp->b_resid = q_bp->b_bcount;
560                                         q_bp->b_error = EIO;
561                                         q_bp->b_flags |= B_ERROR;
562                                         biodone(q_bio);
563                                 }
564                                 bp->b_error = error;
565                                 bp->b_resid = bp->b_bcount;
566                                 bp->b_flags |= B_ERROR;
567                         } else {
568                                 bp->b_resid = csio->resid;
569                                 bp->b_error = 0;
570                                 if (bp->b_resid != 0) {
571                                         /* Short transfer ??? */
572                                         bp->b_flags |= B_ERROR;
573                                 }
574                         }
575                         if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
576                                 cam_release_devq(done_ccb->ccb_h.path,
577                                                  /*relsim_flags*/0,
578                                                  /*reduction*/0,
579                                                  /*timeout*/0,
580                                                  /*getcount_only*/0);
581                 } else {
582                         bp->b_resid = csio->resid;
583                         if (bp->b_resid != 0)
584                                 bp->b_flags |= B_ERROR;
585                 }
586
587                 /*
588                  * Block out any asyncronous callbacks
589                  * while we touch the pending ccb list.
590                  */
591                 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
592
593                 devstat_end_transaction_buf(&softc->device_stats, bp);
594                 biodone(bio);
595                 break;
596         }
597         case PT_CCB_WAITING:
598                 /* Caller will release the CCB */
599                 wakeup(&done_ccb->ccb_h.cbfcnp);
600                 return;
601         }
602         xpt_release_ccb(done_ccb);
603 }
604
605 static int
606 pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
607 {
608         struct pt_softc   *softc;
609         struct cam_periph *periph;
610
611         periph = xpt_path_periph(ccb->ccb_h.path);
612         softc = (struct pt_softc *)periph->softc;
613
614         return(cam_periph_error(ccb, cam_flags, sense_flags,
615                                 &softc->saved_ccb));
616 }
617
618 static int
619 ptioctl(struct dev_ioctl_args *ap)
620 {
621         cdev_t dev = ap->a_head.a_dev;
622         caddr_t addr = ap->a_data;
623         struct cam_periph *periph;
624         struct pt_softc *softc;
625         int unit;
626         int error = 0;
627
628         unit = minor(dev);
629         periph = cam_extend_get(ptperiphs, unit);
630
631         if (periph == NULL)
632                 return(ENXIO);
633
634         softc = (struct pt_softc *)periph->softc;
635
636         cam_periph_lock(periph);
637
638         switch(ap->a_cmd) {
639         case PTIOCGETTIMEOUT:
640                 if (softc->io_timeout >= 1000)
641                         *(int *)addr = softc->io_timeout / 1000;
642                 else
643                         *(int *)addr = 0;
644                 break;
645         case PTIOCSETTIMEOUT:
646                 if (*(int *)addr < 1) {
647                         error = EINVAL;
648                         break;
649                 }
650
651                 softc->io_timeout = *(int *)addr * 1000;
652
653                 break;
654         default:
655                 error = cam_periph_ioctl(periph, ap->a_cmd, addr, pterror);
656                 break;
657         }
658
659         cam_periph_unlock(periph);
660
661         return(error);
662 }
663
664 void
665 scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
666                   void (*cbfcnp)(struct cam_periph *, union ccb *),
667                   u_int tag_action, int readop, u_int byte2,
668                   u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
669                   u_int32_t timeout)
670 {
671         struct scsi_send_receive *scsi_cmd;
672
673         scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
674         scsi_cmd->opcode = readop ? RECEIVE : SEND;
675         scsi_cmd->byte2 = byte2;
676         scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
677         scsi_cmd->control = 0;
678
679         cam_fill_csio(csio,
680                       retries,
681                       cbfcnp,
682                       /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
683                       tag_action,
684                       data_ptr,
685                       xfer_len,
686                       sense_len,
687                       sizeof(*scsi_cmd),
688                       timeout);
689 }