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