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