scsi_pt.c revision 302408
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 293350 2016-01-07 20:22:55Z kib $");
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	bzero(&cpi, sizeof(cpi));
279	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
280	cpi.ccb_h.func_code = XPT_PATH_INQ;
281	xpt_action((union ccb *)&cpi);
282
283	cam_periph_unlock(periph);
284
285	make_dev_args_init(&args);
286	args.mda_devsw = &pt_cdevsw;
287	args.mda_unit = periph->unit_number;
288	args.mda_uid = UID_ROOT;
289	args.mda_gid = GID_OPERATOR;
290	args.mda_mode = 0600;
291	args.mda_si_drv1 = periph;
292	error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name,
293	    periph->unit_number);
294	if (error != 0) {
295		cam_periph_lock(periph);
296		return (CAM_REQ_CMP_ERR);
297	}
298
299	softc->device_stats = devstat_new_entry("pt",
300			  periph->unit_number, 0,
301			  DEVSTAT_NO_BLOCKSIZE,
302			  SID_TYPE(&cgd->inq_data) |
303			  XPORT_DEVSTAT_TYPE(cpi.transport),
304			  DEVSTAT_PRIORITY_OTHER);
305
306	cam_periph_lock(periph);
307
308	/*
309	 * Add async callbacks for bus reset and
310	 * bus device reset calls.  I don't bother
311	 * checking if this fails as, in most cases,
312	 * the system will function just fine without
313	 * them and the only alternative would be to
314	 * not attach the device on failure.
315	 */
316	xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
317			   ptasync, periph, periph->path);
318
319	/* Tell the user we've attached to the device */
320	xpt_announce_periph(periph, NULL);
321
322	return(CAM_REQ_CMP);
323}
324
325static void
326ptoninvalidate(struct cam_periph *periph)
327{
328	struct pt_softc *softc;
329
330	softc = (struct pt_softc *)periph->softc;
331
332	/*
333	 * De-register any async callbacks.
334	 */
335	xpt_register_async(0, ptasync, periph, periph->path);
336
337	softc->flags |= PT_FLAG_DEVICE_INVALID;
338
339	/*
340	 * Return all queued I/O with ENXIO.
341	 * XXX Handle any transactions queued to the card
342	 *     with XPT_ABORT_CCB.
343	 */
344	bioq_flush(&softc->bio_queue, NULL, ENXIO);
345}
346
347static void
348ptdtor(struct cam_periph *periph)
349{
350	struct pt_softc *softc;
351
352	softc = (struct pt_softc *)periph->softc;
353
354	devstat_remove_entry(softc->device_stats);
355	cam_periph_unlock(periph);
356	destroy_dev(softc->dev);
357	cam_periph_lock(periph);
358	free(softc, M_DEVBUF);
359}
360
361static void
362ptasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
363{
364	struct cam_periph *periph;
365
366	periph = (struct cam_periph *)callback_arg;
367	switch (code) {
368	case AC_FOUND_DEVICE:
369	{
370		struct ccb_getdev *cgd;
371		cam_status status;
372
373		cgd = (struct ccb_getdev *)arg;
374		if (cgd == NULL)
375			break;
376
377		if (cgd->protocol != PROTO_SCSI)
378			break;
379		if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED)
380			break;
381		if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
382			break;
383
384		/*
385		 * Allocate a peripheral instance for
386		 * this device and start the probe
387		 * process.
388		 */
389		status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
390					  ptstart, "pt", CAM_PERIPH_BIO,
391					  path, ptasync,
392					  AC_FOUND_DEVICE, cgd);
393
394		if (status != CAM_REQ_CMP
395		 && status != CAM_REQ_INPROG)
396			printf("ptasync: Unable to attach to new device "
397				"due to status 0x%x\n", status);
398		break;
399	}
400	case AC_SENT_BDR:
401	case AC_BUS_RESET:
402	{
403		struct pt_softc *softc;
404		struct ccb_hdr *ccbh;
405
406		softc = (struct pt_softc *)periph->softc;
407		/*
408		 * Don't fail on the expected unit attention
409		 * that will occur.
410		 */
411		softc->flags |= PT_FLAG_RETRY_UA;
412		LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
413			ccbh->ccb_state |= PT_CCB_RETRY_UA;
414	}
415	/* FALLTHROUGH */
416	default:
417		cam_periph_async(periph, code, path, arg);
418		break;
419	}
420}
421
422static void
423ptstart(struct cam_periph *periph, union ccb *start_ccb)
424{
425	struct pt_softc *softc;
426	struct bio *bp;
427
428	softc = (struct pt_softc *)periph->softc;
429
430	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n"));
431
432	/*
433	 * See if there is a buf with work for us to do..
434	 */
435	bp = bioq_first(&softc->bio_queue);
436	if (bp == NULL) {
437		xpt_release_ccb(start_ccb);
438	} else {
439		bioq_remove(&softc->bio_queue, bp);
440
441		devstat_start_transaction_bio(softc->device_stats, bp);
442
443		scsi_send_receive(&start_ccb->csio,
444				  /*retries*/4,
445				  ptdone,
446				  MSG_SIMPLE_Q_TAG,
447				  bp->bio_cmd == BIO_READ,
448				  /*byte2*/0,
449				  bp->bio_bcount,
450				  bp->bio_data,
451				  /*sense_len*/SSD_FULL_SIZE,
452				  /*timeout*/softc->io_timeout);
453
454		start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
455
456		/*
457		 * Block out any asynchronous callbacks
458		 * while we touch the pending ccb list.
459		 */
460		LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
461				 periph_links.le);
462
463		start_ccb->ccb_h.ccb_bp = bp;
464		bp = bioq_first(&softc->bio_queue);
465
466		xpt_action(start_ccb);
467
468		if (bp != NULL) {
469			/* Have more work to do, so ensure we stay scheduled */
470			xpt_schedule(periph, CAM_PRIORITY_NORMAL);
471		}
472	}
473}
474
475static void
476ptdone(struct cam_periph *periph, union ccb *done_ccb)
477{
478	struct pt_softc *softc;
479	struct ccb_scsiio *csio;
480
481	softc = (struct pt_softc *)periph->softc;
482
483	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptdone\n"));
484
485	csio = &done_ccb->csio;
486	switch (csio->ccb_h.ccb_state) {
487	case PT_CCB_BUFFER_IO:
488	case PT_CCB_BUFFER_IO_UA:
489	{
490		struct bio *bp;
491
492		bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
493		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
494			int error;
495			int sf;
496
497			if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
498				sf = SF_RETRY_UA;
499			else
500				sf = 0;
501
502			error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
503			if (error == ERESTART) {
504				/*
505				 * A retry was scheuled, so
506				 * just return.
507				 */
508				return;
509			}
510			if (error != 0) {
511				if (error == ENXIO) {
512					/*
513					 * Catastrophic error.  Mark our device
514					 * as invalid.
515					 */
516					xpt_print(periph->path,
517					    "Invalidating device\n");
518					softc->flags |= PT_FLAG_DEVICE_INVALID;
519				}
520
521				/*
522				 * return all queued I/O with EIO, so that
523				 * the client can retry these I/Os in the
524				 * proper order should it attempt to recover.
525				 */
526				bioq_flush(&softc->bio_queue, NULL, EIO);
527				bp->bio_error = error;
528				bp->bio_resid = bp->bio_bcount;
529				bp->bio_flags |= BIO_ERROR;
530			} else {
531				bp->bio_resid = csio->resid;
532				bp->bio_error = 0;
533				if (bp->bio_resid != 0) {
534					/* Short transfer ??? */
535					bp->bio_flags |= BIO_ERROR;
536				}
537			}
538			if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
539				cam_release_devq(done_ccb->ccb_h.path,
540						 /*relsim_flags*/0,
541						 /*reduction*/0,
542						 /*timeout*/0,
543						 /*getcount_only*/0);
544		} else {
545			bp->bio_resid = csio->resid;
546			if (bp->bio_resid != 0)
547				bp->bio_flags |= BIO_ERROR;
548		}
549
550		/*
551		 * Block out any asynchronous callbacks
552		 * while we touch the pending ccb list.
553		 */
554		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
555
556		biofinish(bp, softc->device_stats, 0);
557		break;
558	}
559	}
560	xpt_release_ccb(done_ccb);
561}
562
563static int
564pterror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
565{
566	struct pt_softc	  *softc;
567	struct cam_periph *periph;
568
569	periph = xpt_path_periph(ccb->ccb_h.path);
570	softc = (struct pt_softc *)periph->softc;
571
572	return(cam_periph_error(ccb, cam_flags, sense_flags,
573				&softc->saved_ccb));
574}
575
576static int
577ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
578{
579	struct cam_periph *periph;
580	struct pt_softc *softc;
581	int error = 0;
582
583	periph = (struct cam_periph *)dev->si_drv1;
584	softc = (struct pt_softc *)periph->softc;
585
586	cam_periph_lock(periph);
587
588	switch(cmd) {
589	case PTIOCGETTIMEOUT:
590		if (softc->io_timeout >= 1000)
591			*(int *)addr = softc->io_timeout / 1000;
592		else
593			*(int *)addr = 0;
594		break;
595	case PTIOCSETTIMEOUT:
596		if (*(int *)addr < 1) {
597			error = EINVAL;
598			break;
599		}
600
601		softc->io_timeout = *(int *)addr * 1000;
602
603		break;
604	default:
605		error = cam_periph_ioctl(periph, cmd, addr, pterror);
606		break;
607	}
608
609	cam_periph_unlock(periph);
610
611	return(error);
612}
613
614void
615scsi_send_receive(struct ccb_scsiio *csio, u_int32_t retries,
616		  void (*cbfcnp)(struct cam_periph *, union ccb *),
617		  u_int tag_action, int readop, u_int byte2,
618		  u_int32_t xfer_len, u_int8_t *data_ptr, u_int8_t sense_len,
619		  u_int32_t timeout)
620{
621	struct scsi_send_receive *scsi_cmd;
622
623	scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
624	scsi_cmd->opcode = readop ? RECEIVE : SEND;
625	scsi_cmd->byte2 = byte2;
626	scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
627	scsi_cmd->control = 0;
628
629	cam_fill_csio(csio,
630		      retries,
631		      cbfcnp,
632		      /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
633		      tag_action,
634		      data_ptr,
635		      xfer_len,
636		      sense_len,
637		      sizeof(*scsi_cmd),
638		      timeout);
639}
640