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