xref: /freebsd/sys/cam/scsi/scsi_pt.c (revision 5f4c09dd85bff675e0ca63c55ea3c517e0fddfcc)
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
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
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
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
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
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
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
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
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
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
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
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
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
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