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