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