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