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
54typedef enum {
55	PT_STATE_PROBE,
56	PT_STATE_NORMAL
57} pt_state;
58
59typedef 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
66typedef 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
76struct 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
86static	d_open_t	ptopen;
87static	d_close_t	ptclose;
88static	d_strategy_t	ptstrategy;
89static	periph_init_t	ptinit;
90static	void		ptasync(void *callback_arg, uint32_t code,
91				struct cam_path *path, void *arg);
92static	periph_ctor_t	ptctor;
93static	periph_oninv_t	ptoninvalidate;
94static	periph_dtor_t	ptdtor;
95static	periph_start_t	ptstart;
96static	void		ptdone(struct cam_periph *periph,
97			       union ccb *done_ccb);
98static	d_ioctl_t	ptioctl;
99static  int		pterror(union ccb *ccb, uint32_t cam_flags,
100				uint32_t sense_flags);
101
102void	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
108static struct periph_driver ptdriver =
109{
110	ptinit, "pt",
111	TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
112};
113
114PERIPHDRIVER_DECLARE(pt, ptdriver);
115
116static 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
132static int
133ptopen(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
166static int
167ptclose(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 */
188static void
189ptstrategy(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
226static void
227ptinit(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
243static cam_status
244ptctor(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
319static void
320ptoninvalidate(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
341static void
342ptdtor(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
355static void
356ptasync(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
416static void
417ptstart(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
469static void
470ptdone(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
557static int
558pterror(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
564static int
565ptioctl(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
602void
603scsi_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