1898b0535SWarner Losh /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3bec9534dSPedro F. Giffuni *
476babe50SJustin T. Gibbs * Implementation of SCSI Processor Target Peripheral driver for CAM.
576babe50SJustin T. Gibbs *
676babe50SJustin T. Gibbs * Copyright (c) 1998 Justin T. Gibbs.
776babe50SJustin T. Gibbs * All rights reserved.
876babe50SJustin T. Gibbs *
976babe50SJustin T. Gibbs * Redistribution and use in source and binary forms, with or without
1076babe50SJustin T. Gibbs * modification, are permitted provided that the following conditions
1176babe50SJustin T. Gibbs * are met:
1276babe50SJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright
1376babe50SJustin T. Gibbs * notice, this list of conditions, and the following disclaimer,
1476babe50SJustin T. Gibbs * without modification, immediately at the beginning of the file.
1576babe50SJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products
1676babe50SJustin T. Gibbs * derived from this software without specific prior written permission.
1776babe50SJustin T. Gibbs *
1876babe50SJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1976babe50SJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2076babe50SJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2176babe50SJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2276babe50SJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2376babe50SJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2476babe50SJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2576babe50SJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2676babe50SJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2776babe50SJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2876babe50SJustin T. Gibbs * SUCH DAMAGE.
2976babe50SJustin T. Gibbs */
3076babe50SJustin T. Gibbs
3176babe50SJustin T. Gibbs #include <sys/param.h>
3276babe50SJustin T. Gibbs #include <sys/queue.h>
3376babe50SJustin T. Gibbs #include <sys/systm.h>
3476babe50SJustin T. Gibbs #include <sys/kernel.h>
3576babe50SJustin T. Gibbs #include <sys/types.h>
369626b608SPoul-Henning Kamp #include <sys/bio.h>
3776babe50SJustin T. Gibbs #include <sys/devicestat.h>
3876babe50SJustin T. Gibbs #include <sys/malloc.h>
3976babe50SJustin T. Gibbs #include <sys/conf.h>
403ece1bd2SKenneth D. Merry #include <sys/ptio.h>
4176babe50SJustin T. Gibbs
4276babe50SJustin T. Gibbs #include <cam/cam.h>
4376babe50SJustin T. Gibbs #include <cam/cam_ccb.h>
4476babe50SJustin T. Gibbs #include <cam/cam_periph.h>
4576babe50SJustin T. Gibbs #include <cam/cam_xpt_periph.h>
4676babe50SJustin T. Gibbs #include <cam/cam_debug.h>
4776babe50SJustin T. Gibbs
4876babe50SJustin T. Gibbs #include <cam/scsi/scsi_all.h>
4976babe50SJustin T. Gibbs #include <cam/scsi/scsi_message.h>
5076babe50SJustin T. Gibbs #include <cam/scsi/scsi_pt.h>
5176babe50SJustin T. Gibbs
523ece1bd2SKenneth D. Merry #include "opt_pt.h"
533ece1bd2SKenneth D. Merry
5476babe50SJustin T. Gibbs typedef enum {
5576babe50SJustin T. Gibbs PT_STATE_PROBE,
5676babe50SJustin T. Gibbs PT_STATE_NORMAL
5776babe50SJustin T. Gibbs } pt_state;
5876babe50SJustin T. Gibbs
5976babe50SJustin T. Gibbs typedef enum {
6076babe50SJustin T. Gibbs PT_FLAG_NONE = 0x00,
6176babe50SJustin T. Gibbs PT_FLAG_OPEN = 0x01,
6276babe50SJustin T. Gibbs PT_FLAG_DEVICE_INVALID = 0x02,
6376babe50SJustin T. Gibbs PT_FLAG_RETRY_UA = 0x04
6476babe50SJustin T. Gibbs } pt_flags;
6576babe50SJustin T. Gibbs
6676babe50SJustin T. Gibbs typedef enum {
6776babe50SJustin T. Gibbs PT_CCB_BUFFER_IO = 0x01,
6876babe50SJustin T. Gibbs PT_CCB_RETRY_UA = 0x04,
6976babe50SJustin T. Gibbs PT_CCB_BUFFER_IO_UA = PT_CCB_BUFFER_IO|PT_CCB_RETRY_UA
7076babe50SJustin T. Gibbs } pt_ccb_state;
7176babe50SJustin T. Gibbs
7276babe50SJustin T. Gibbs /* Offsets into our private area for storing information */
7376babe50SJustin T. Gibbs #define ccb_state ppriv_field0
7476babe50SJustin T. Gibbs #define ccb_bp ppriv_ptr1
7576babe50SJustin T. Gibbs
7676babe50SJustin T. Gibbs struct pt_softc {
778177437dSPoul-Henning Kamp struct bio_queue_head bio_queue;
78a9d2245eSPoul-Henning Kamp struct devstat *device_stats;
79e3975643SJake Burkholder LIST_HEAD(, ccb_hdr) pending_ccbs;
8076babe50SJustin T. Gibbs pt_state state;
8176babe50SJustin T. Gibbs pt_flags flags;
823ece1bd2SKenneth D. Merry int io_timeout;
8389c9c53dSPoul-Henning Kamp struct cdev *dev;
8476babe50SJustin T. Gibbs };
8576babe50SJustin T. Gibbs
8676babe50SJustin T. Gibbs static d_open_t ptopen;
8776babe50SJustin T. Gibbs static d_close_t ptclose;
8876babe50SJustin T. Gibbs static d_strategy_t ptstrategy;
8976babe50SJustin T. Gibbs static periph_init_t ptinit;
90*7c5d20a6SWarner Losh static void ptasync(void *callback_arg, uint32_t code,
9176babe50SJustin T. Gibbs struct cam_path *path, void *arg);
9276babe50SJustin T. Gibbs static periph_ctor_t ptctor;
93ee9c90c7SKenneth D. Merry static periph_oninv_t ptoninvalidate;
9476babe50SJustin T. Gibbs static periph_dtor_t ptdtor;
9576babe50SJustin T. Gibbs static periph_start_t ptstart;
9676babe50SJustin T. Gibbs static void ptdone(struct cam_periph *periph,
9776babe50SJustin T. Gibbs union ccb *done_ccb);
983ece1bd2SKenneth D. Merry static d_ioctl_t ptioctl;
99*7c5d20a6SWarner Losh static int pterror(union ccb *ccb, uint32_t cam_flags,
100*7c5d20a6SWarner Losh uint32_t sense_flags);
10176babe50SJustin T. Gibbs
102*7c5d20a6SWarner Losh void scsi_send_receive(struct ccb_scsiio *csio, uint32_t retries,
10376babe50SJustin T. Gibbs void (*cbfcnp)(struct cam_periph *, union ccb *),
10476babe50SJustin T. Gibbs u_int tag_action, int readop, u_int byte2,
105*7c5d20a6SWarner Losh uint32_t xfer_len, uint8_t *data_ptr,
106*7c5d20a6SWarner Losh uint8_t sense_len, uint32_t timeout);
10776babe50SJustin T. Gibbs
10876babe50SJustin T. Gibbs static struct periph_driver ptdriver =
10976babe50SJustin T. Gibbs {
11076babe50SJustin T. Gibbs ptinit, "pt",
11176babe50SJustin T. Gibbs TAILQ_HEAD_INITIALIZER(ptdriver.units), /* generation */ 0
11276babe50SJustin T. Gibbs };
11376babe50SJustin T. Gibbs
1140b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(pt, ptdriver);
11576babe50SJustin T. Gibbs
1164e2f199eSPoul-Henning Kamp static struct cdevsw pt_cdevsw = {
117dc08ffecSPoul-Henning Kamp .d_version = D_VERSION,
1182b83592fSScott Long .d_flags = 0,
1197ac40f5fSPoul-Henning Kamp .d_open = ptopen,
1207ac40f5fSPoul-Henning Kamp .d_close = ptclose,
1217ac40f5fSPoul-Henning Kamp .d_read = physread,
1227ac40f5fSPoul-Henning Kamp .d_write = physwrite,
1237ac40f5fSPoul-Henning Kamp .d_ioctl = ptioctl,
1247ac40f5fSPoul-Henning Kamp .d_strategy = ptstrategy,
1257ac40f5fSPoul-Henning Kamp .d_name = "pt",
12676babe50SJustin T. Gibbs };
12776babe50SJustin T. Gibbs
1283ece1bd2SKenneth D. Merry #ifndef SCSI_PT_DEFAULT_TIMEOUT
1293ece1bd2SKenneth D. Merry #define SCSI_PT_DEFAULT_TIMEOUT 60
1303ece1bd2SKenneth D. Merry #endif
1313ece1bd2SKenneth D. Merry
13276babe50SJustin T. Gibbs static int
ptopen(struct cdev * dev,int flags,int fmt,struct thread * td)13389c9c53dSPoul-Henning Kamp ptopen(struct cdev *dev, int flags, int fmt, struct thread *td)
13476babe50SJustin T. Gibbs {
13576babe50SJustin T. Gibbs struct cam_periph *periph;
13676babe50SJustin T. Gibbs struct pt_softc *softc;
1372b83592fSScott Long int error = 0;
13876babe50SJustin T. Gibbs
139e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1;
14099e7a4adSScott Long if (cam_periph_acquire(periph) != 0)
14176babe50SJustin T. Gibbs return (ENXIO);
14276babe50SJustin T. Gibbs
14376babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc;
14476babe50SJustin T. Gibbs
1452b83592fSScott Long cam_periph_lock(periph);
146ee9c90c7SKenneth D. Merry if (softc->flags & PT_FLAG_DEVICE_INVALID) {
147c552ebe1SKenneth D. Merry cam_periph_release_locked(periph);
1482b83592fSScott Long cam_periph_unlock(periph);
149ee9c90c7SKenneth D. Merry return(ENXIO);
150ee9c90c7SKenneth D. Merry }
151ee9c90c7SKenneth D. Merry
1522b83592fSScott Long if ((softc->flags & PT_FLAG_OPEN) == 0)
1532b83592fSScott Long softc->flags |= PT_FLAG_OPEN;
1542b83592fSScott Long else {
1552b83592fSScott Long error = EBUSY;
1562b83592fSScott Long cam_periph_release(periph);
15722b9c86cSKenneth D. Merry }
15822b9c86cSKenneth D. Merry
1592b83592fSScott Long CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1602b83592fSScott Long ("ptopen: dev=%s\n", devtoname(dev)));
16176babe50SJustin T. Gibbs
16276babe50SJustin T. Gibbs cam_periph_unlock(periph);
16376babe50SJustin T. Gibbs return (error);
16476babe50SJustin T. Gibbs }
16576babe50SJustin T. Gibbs
16676babe50SJustin T. Gibbs static int
ptclose(struct cdev * dev,int flag,int fmt,struct thread * td)16789c9c53dSPoul-Henning Kamp ptclose(struct cdev *dev, int flag, int fmt, struct thread *td)
16876babe50SJustin T. Gibbs {
16976babe50SJustin T. Gibbs struct cam_periph *periph;
17076babe50SJustin T. Gibbs struct pt_softc *softc;
17176babe50SJustin T. Gibbs
172e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1;
17376babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc;
17476babe50SJustin T. Gibbs
1752b83592fSScott Long cam_periph_lock(periph);
17676babe50SJustin T. Gibbs
17776babe50SJustin T. Gibbs softc->flags &= ~PT_FLAG_OPEN;
178c552ebe1SKenneth D. Merry cam_periph_release_locked(periph);
17976babe50SJustin T. Gibbs cam_periph_unlock(periph);
18076babe50SJustin T. Gibbs return (0);
18176babe50SJustin T. Gibbs }
18276babe50SJustin T. Gibbs
18376babe50SJustin T. Gibbs /*
18476babe50SJustin T. Gibbs * Actually translate the requested transfer into one the physical driver
18576babe50SJustin T. Gibbs * can understand. The transfer is described by a buf and will include
18676babe50SJustin T. Gibbs * only one physical transfer.
18776babe50SJustin T. Gibbs */
18876babe50SJustin T. Gibbs static void
ptstrategy(struct bio * bp)1898177437dSPoul-Henning Kamp ptstrategy(struct bio *bp)
19076babe50SJustin T. Gibbs {
19176babe50SJustin T. Gibbs struct cam_periph *periph;
19276babe50SJustin T. Gibbs struct pt_softc *softc;
19376babe50SJustin T. Gibbs
194e2a5fdf9SNate Lawson periph = (struct cam_periph *)bp->bio_dev->si_drv1;
195b63170f8SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount;
19676babe50SJustin T. Gibbs if (periph == NULL) {
197b63170f8SPoul-Henning Kamp biofinish(bp, NULL, ENXIO);
198b63170f8SPoul-Henning Kamp return;
19976babe50SJustin T. Gibbs }
2002b83592fSScott Long cam_periph_lock(periph);
20176babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc;
20276babe50SJustin T. Gibbs
20376babe50SJustin T. Gibbs /*
20476babe50SJustin T. Gibbs * If the device has been made invalid, error out
20576babe50SJustin T. Gibbs */
20676babe50SJustin T. Gibbs if ((softc->flags & PT_FLAG_DEVICE_INVALID)) {
2072b83592fSScott Long cam_periph_unlock(periph);
208b63170f8SPoul-Henning Kamp biofinish(bp, NULL, ENXIO);
209b63170f8SPoul-Henning Kamp return;
21076babe50SJustin T. Gibbs }
21176babe50SJustin T. Gibbs
21276babe50SJustin T. Gibbs /*
21376babe50SJustin T. Gibbs * Place it in the queue of disk activities for this disk
21476babe50SJustin T. Gibbs */
2158177437dSPoul-Henning Kamp bioq_insert_tail(&softc->bio_queue, bp);
21676babe50SJustin T. Gibbs
21776babe50SJustin T. Gibbs /*
21876babe50SJustin T. Gibbs * Schedule ourselves for performing the work.
21976babe50SJustin T. Gibbs */
220bbfa4aa1SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_NORMAL);
2212b83592fSScott Long cam_periph_unlock(periph);
22276babe50SJustin T. Gibbs
22376babe50SJustin T. Gibbs return;
22476babe50SJustin T. Gibbs }
22576babe50SJustin T. Gibbs
22676babe50SJustin T. Gibbs static void
ptinit(void)22776babe50SJustin T. Gibbs ptinit(void)
22876babe50SJustin T. Gibbs {
22976babe50SJustin T. Gibbs cam_status status;
23076babe50SJustin T. Gibbs
23176babe50SJustin T. Gibbs /*
23276babe50SJustin T. Gibbs * Install a global async callback. This callback will
23376babe50SJustin T. Gibbs * receive async callbacks like "new device found".
23476babe50SJustin T. Gibbs */
23585d92640SScott Long status = xpt_register_async(AC_FOUND_DEVICE, ptasync, NULL, NULL);
23676babe50SJustin T. Gibbs
23776babe50SJustin T. Gibbs if (status != CAM_REQ_CMP) {
23876babe50SJustin T. Gibbs printf("pt: Failed to attach master async callback "
23976babe50SJustin T. Gibbs "due to status 0x%x!\n", status);
24076babe50SJustin T. Gibbs }
24176babe50SJustin T. Gibbs }
24276babe50SJustin T. Gibbs
24376babe50SJustin T. Gibbs static cam_status
ptctor(struct cam_periph * periph,void * arg)24476babe50SJustin T. Gibbs ptctor(struct cam_periph *periph, void *arg)
24576babe50SJustin T. Gibbs {
24676babe50SJustin T. Gibbs struct pt_softc *softc;
24776babe50SJustin T. Gibbs struct ccb_getdev *cgd;
248b8b6b5d3SAlexander Motin struct ccb_pathinq cpi;
249ee198893SKonstantin Belousov struct make_dev_args args;
250ee198893SKonstantin Belousov int error;
25176babe50SJustin T. Gibbs
25276babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg;
25376babe50SJustin T. Gibbs if (cgd == NULL) {
25476babe50SJustin T. Gibbs printf("ptregister: no getdev CCB, can't register device\n");
25576babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR);
25676babe50SJustin T. Gibbs }
25776babe50SJustin T. Gibbs
25876babe50SJustin T. Gibbs softc = (struct pt_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
25976babe50SJustin T. Gibbs
26076babe50SJustin T. Gibbs if (softc == NULL) {
26176babe50SJustin T. Gibbs printf("daregister: Unable to probe new device. "
26276babe50SJustin T. Gibbs "Unable to allocate softc\n");
26376babe50SJustin T. Gibbs return(CAM_REQ_CMP_ERR);
26476babe50SJustin T. Gibbs }
26576babe50SJustin T. Gibbs
26676babe50SJustin T. Gibbs bzero(softc, sizeof(*softc));
26776babe50SJustin T. Gibbs LIST_INIT(&softc->pending_ccbs);
26876babe50SJustin T. Gibbs softc->state = PT_STATE_NORMAL;
2698177437dSPoul-Henning Kamp bioq_init(&softc->bio_queue);
27076babe50SJustin T. Gibbs
2713ece1bd2SKenneth D. Merry softc->io_timeout = SCSI_PT_DEFAULT_TIMEOUT * 1000;
2723ece1bd2SKenneth D. Merry
27376babe50SJustin T. Gibbs periph->softc = softc;
27476babe50SJustin T. Gibbs
275762a7f4fSWarner Losh xpt_path_inq(&cpi, periph->path);
276b8b6b5d3SAlexander Motin
27785d92640SScott Long cam_periph_unlock(periph);
278ee198893SKonstantin Belousov
279ee198893SKonstantin Belousov make_dev_args_init(&args);
280ee198893SKonstantin Belousov args.mda_devsw = &pt_cdevsw;
281ee198893SKonstantin Belousov args.mda_unit = periph->unit_number;
282ee198893SKonstantin Belousov args.mda_uid = UID_ROOT;
283ee198893SKonstantin Belousov args.mda_gid = GID_OPERATOR;
284ee198893SKonstantin Belousov args.mda_mode = 0600;
285ee198893SKonstantin Belousov args.mda_si_drv1 = periph;
286ee198893SKonstantin Belousov error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name,
287ee198893SKonstantin Belousov periph->unit_number);
288ee198893SKonstantin Belousov if (error != 0) {
289ee198893SKonstantin Belousov cam_periph_lock(periph);
290ee198893SKonstantin Belousov return (CAM_REQ_CMP_ERR);
291ee198893SKonstantin Belousov }
292ee198893SKonstantin Belousov
293a9d2245eSPoul-Henning Kamp softc->device_stats = devstat_new_entry("pt",
29476babe50SJustin T. Gibbs periph->unit_number, 0,
29576babe50SJustin T. Gibbs DEVSTAT_NO_BLOCKSIZE,
296b8b6b5d3SAlexander Motin SID_TYPE(&cgd->inq_data) |
297b8b6b5d3SAlexander Motin XPORT_DEVSTAT_TYPE(cpi.transport),
2982a888f93SKenneth D. Merry DEVSTAT_PRIORITY_OTHER);
29976babe50SJustin T. Gibbs
30058b0b144SScott Long cam_periph_lock(periph);
301e2a5fdf9SNate Lawson
30276babe50SJustin T. Gibbs /*
30376babe50SJustin T. Gibbs * Add async callbacks for bus reset and
30476babe50SJustin T. Gibbs * bus device reset calls. I don't bother
30576babe50SJustin T. Gibbs * checking if this fails as, in most cases,
30676babe50SJustin T. Gibbs * the system will function just fine without
30776babe50SJustin T. Gibbs * them and the only alternative would be to
30876babe50SJustin T. Gibbs * not attach the device on failure.
30976babe50SJustin T. Gibbs */
31085d92640SScott Long xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
31185d92640SScott Long ptasync, periph, periph->path);
31276babe50SJustin T. Gibbs
31376babe50SJustin T. Gibbs /* Tell the user we've attached to the device */
31476babe50SJustin T. Gibbs xpt_announce_periph(periph, NULL);
31576babe50SJustin T. Gibbs
31676babe50SJustin T. Gibbs return(CAM_REQ_CMP);
31776babe50SJustin T. Gibbs }
31876babe50SJustin T. Gibbs
31976babe50SJustin T. Gibbs static void
ptoninvalidate(struct cam_periph * periph)320ee9c90c7SKenneth D. Merry ptoninvalidate(struct cam_periph *periph)
321ee9c90c7SKenneth D. Merry {
322ee9c90c7SKenneth D. Merry struct pt_softc *softc;
323ee9c90c7SKenneth D. Merry
324ee9c90c7SKenneth D. Merry softc = (struct pt_softc *)periph->softc;
325ee9c90c7SKenneth D. Merry
326ee9c90c7SKenneth D. Merry /*
327ee9c90c7SKenneth D. Merry * De-register any async callbacks.
328ee9c90c7SKenneth D. Merry */
32985d92640SScott Long xpt_register_async(0, ptasync, periph, periph->path);
330ee9c90c7SKenneth D. Merry
331ee9c90c7SKenneth D. Merry softc->flags |= PT_FLAG_DEVICE_INVALID;
332ee9c90c7SKenneth D. Merry
333ee9c90c7SKenneth D. Merry /*
334ee9c90c7SKenneth D. Merry * Return all queued I/O with ENXIO.
335ee9c90c7SKenneth D. Merry * XXX Handle any transactions queued to the card
336ee9c90c7SKenneth D. Merry * with XPT_ABORT_CCB.
337ee9c90c7SKenneth D. Merry */
338891619a6SPoul-Henning Kamp bioq_flush(&softc->bio_queue, NULL, ENXIO);
339ee9c90c7SKenneth D. Merry }
340ee9c90c7SKenneth D. Merry
341ee9c90c7SKenneth D. Merry static void
ptdtor(struct cam_periph * periph)34276babe50SJustin T. Gibbs ptdtor(struct cam_periph *periph)
34376babe50SJustin T. Gibbs {
344ee9c90c7SKenneth D. Merry struct pt_softc *softc;
345ee9c90c7SKenneth D. Merry
346ee9c90c7SKenneth D. Merry softc = (struct pt_softc *)periph->softc;
347ee9c90c7SKenneth D. Merry
3485f3fed85SEdward Tomasz Napierala devstat_remove_entry(softc->device_stats);
3495f3fed85SEdward Tomasz Napierala cam_periph_unlock(periph);
3505f3fed85SEdward Tomasz Napierala destroy_dev(softc->dev);
3515f3fed85SEdward Tomasz Napierala cam_periph_lock(periph);
352ee9c90c7SKenneth D. Merry free(softc, M_DEVBUF);
35376babe50SJustin T. Gibbs }
35476babe50SJustin T. Gibbs
35576babe50SJustin T. Gibbs static void
ptasync(void * callback_arg,uint32_t code,struct cam_path * path,void * arg)356*7c5d20a6SWarner Losh ptasync(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
35776babe50SJustin T. Gibbs {
35876babe50SJustin T. Gibbs struct cam_periph *periph;
35976babe50SJustin T. Gibbs
36076babe50SJustin T. Gibbs periph = (struct cam_periph *)callback_arg;
36176babe50SJustin T. Gibbs switch (code) {
36276babe50SJustin T. Gibbs case AC_FOUND_DEVICE:
36376babe50SJustin T. Gibbs {
36476babe50SJustin T. Gibbs struct ccb_getdev *cgd;
36576babe50SJustin T. Gibbs cam_status status;
36676babe50SJustin T. Gibbs
36776babe50SJustin T. Gibbs cgd = (struct ccb_getdev *)arg;
368c5ff3b2fSMatt Jacob if (cgd == NULL)
369c5ff3b2fSMatt Jacob break;
37076babe50SJustin T. Gibbs
37152c9ce25SScott Long if (cgd->protocol != PROTO_SCSI)
37252c9ce25SScott Long break;
37392024858SAlexander Motin if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED)
37492024858SAlexander Motin break;
37510b6172aSMatt Jacob if (SID_TYPE(&cgd->inq_data) != T_PROCESSOR)
37676babe50SJustin T. Gibbs break;
37776babe50SJustin T. Gibbs
37876babe50SJustin T. Gibbs /*
37976babe50SJustin T. Gibbs * Allocate a peripheral instance for
38076babe50SJustin T. Gibbs * this device and start the probe
38176babe50SJustin T. Gibbs * process.
38276babe50SJustin T. Gibbs */
383ee9c90c7SKenneth D. Merry status = cam_periph_alloc(ptctor, ptoninvalidate, ptdtor,
384ee9c90c7SKenneth D. Merry ptstart, "pt", CAM_PERIPH_BIO,
385227d67aaSAlexander Motin path, ptasync,
386ee9c90c7SKenneth D. Merry AC_FOUND_DEVICE, cgd);
38776babe50SJustin T. Gibbs
38876babe50SJustin T. Gibbs if (status != CAM_REQ_CMP
38976babe50SJustin T. Gibbs && status != CAM_REQ_INPROG)
39076babe50SJustin T. Gibbs printf("ptasync: Unable to attach to new device "
39176babe50SJustin T. Gibbs "due to status 0x%x\n", status);
39276babe50SJustin T. Gibbs break;
39376babe50SJustin T. Gibbs }
39476babe50SJustin T. Gibbs case AC_SENT_BDR:
39576babe50SJustin T. Gibbs case AC_BUS_RESET:
39676babe50SJustin T. Gibbs {
39776babe50SJustin T. Gibbs struct pt_softc *softc;
39876babe50SJustin T. Gibbs struct ccb_hdr *ccbh;
39976babe50SJustin T. Gibbs
40076babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc;
40176babe50SJustin T. Gibbs /*
40276babe50SJustin T. Gibbs * Don't fail on the expected unit attention
40376babe50SJustin T. Gibbs * that will occur.
40476babe50SJustin T. Gibbs */
40576babe50SJustin T. Gibbs softc->flags |= PT_FLAG_RETRY_UA;
406fc2ffbe6SPoul-Henning Kamp LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
40776babe50SJustin T. Gibbs ccbh->ccb_state |= PT_CCB_RETRY_UA;
40876babe50SJustin T. Gibbs }
40907c6eac9SPoul-Henning Kamp /* FALLTHROUGH */
41076babe50SJustin T. Gibbs default:
411516871c6SJustin T. Gibbs cam_periph_async(periph, code, path, arg);
41276babe50SJustin T. Gibbs break;
41376babe50SJustin T. Gibbs }
41476babe50SJustin T. Gibbs }
41576babe50SJustin T. Gibbs
41676babe50SJustin T. Gibbs static void
ptstart(struct cam_periph * periph,union ccb * start_ccb)41776babe50SJustin T. Gibbs ptstart(struct cam_periph *periph, union ccb *start_ccb)
41876babe50SJustin T. Gibbs {
41976babe50SJustin T. Gibbs struct pt_softc *softc;
4208177437dSPoul-Henning Kamp struct bio *bp;
42176babe50SJustin T. Gibbs
42276babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc;
42376babe50SJustin T. Gibbs
424fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptstart\n"));
425fddde2b8SAlexander Motin
42676babe50SJustin T. Gibbs /*
42776babe50SJustin T. Gibbs * See if there is a buf with work for us to do..
42876babe50SJustin T. Gibbs */
4298177437dSPoul-Henning Kamp bp = bioq_first(&softc->bio_queue);
430227d67aaSAlexander Motin if (bp == NULL) {
43176babe50SJustin T. Gibbs xpt_release_ccb(start_ccb);
43276babe50SJustin T. Gibbs } else {
4338177437dSPoul-Henning Kamp bioq_remove(&softc->bio_queue, bp);
43476babe50SJustin T. Gibbs
4351ecc485cSPoul-Henning Kamp devstat_start_transaction_bio(softc->device_stats, bp);
43676babe50SJustin T. Gibbs
43776babe50SJustin T. Gibbs scsi_send_receive(&start_ccb->csio,
43876babe50SJustin T. Gibbs /*retries*/4,
43976babe50SJustin T. Gibbs ptdone,
44076babe50SJustin T. Gibbs MSG_SIMPLE_Q_TAG,
4418177437dSPoul-Henning Kamp bp->bio_cmd == BIO_READ,
44276babe50SJustin T. Gibbs /*byte2*/0,
4438177437dSPoul-Henning Kamp bp->bio_bcount,
4448177437dSPoul-Henning Kamp bp->bio_data,
44576babe50SJustin T. Gibbs /*sense_len*/SSD_FULL_SIZE,
4463ece1bd2SKenneth D. Merry /*timeout*/softc->io_timeout);
44776babe50SJustin T. Gibbs
4489c6a0920SKenneth D. Merry start_ccb->ccb_h.ccb_state = PT_CCB_BUFFER_IO_UA;
44976babe50SJustin T. Gibbs
45076babe50SJustin T. Gibbs /*
4517a2b450fSEitan Adler * Block out any asynchronous callbacks
45276babe50SJustin T. Gibbs * while we touch the pending ccb list.
45376babe50SJustin T. Gibbs */
45476babe50SJustin T. Gibbs LIST_INSERT_HEAD(&softc->pending_ccbs, &start_ccb->ccb_h,
45576babe50SJustin T. Gibbs periph_links.le);
45676babe50SJustin T. Gibbs
45776babe50SJustin T. Gibbs start_ccb->ccb_h.ccb_bp = bp;
4588177437dSPoul-Henning Kamp bp = bioq_first(&softc->bio_queue);
45976babe50SJustin T. Gibbs
46076babe50SJustin T. Gibbs xpt_action(start_ccb);
46176babe50SJustin T. Gibbs
46276babe50SJustin T. Gibbs if (bp != NULL) {
46376babe50SJustin T. Gibbs /* Have more work to do, so ensure we stay scheduled */
464bbfa4aa1SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_NORMAL);
46576babe50SJustin T. Gibbs }
46676babe50SJustin T. Gibbs }
46776babe50SJustin T. Gibbs }
46876babe50SJustin T. Gibbs
46976babe50SJustin T. Gibbs static void
ptdone(struct cam_periph * periph,union ccb * done_ccb)47076babe50SJustin T. Gibbs ptdone(struct cam_periph *periph, union ccb *done_ccb)
47176babe50SJustin T. Gibbs {
47276babe50SJustin T. Gibbs struct pt_softc *softc;
47376babe50SJustin T. Gibbs struct ccb_scsiio *csio;
47476babe50SJustin T. Gibbs
47576babe50SJustin T. Gibbs softc = (struct pt_softc *)periph->softc;
476fddde2b8SAlexander Motin
477fddde2b8SAlexander Motin CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("ptdone\n"));
478fddde2b8SAlexander Motin
47976babe50SJustin T. Gibbs csio = &done_ccb->csio;
48076babe50SJustin T. Gibbs switch (csio->ccb_h.ccb_state) {
48176babe50SJustin T. Gibbs case PT_CCB_BUFFER_IO:
48276babe50SJustin T. Gibbs case PT_CCB_BUFFER_IO_UA:
48376babe50SJustin T. Gibbs {
4848177437dSPoul-Henning Kamp struct bio *bp;
48576babe50SJustin T. Gibbs
4868177437dSPoul-Henning Kamp bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
48776babe50SJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
48876babe50SJustin T. Gibbs int error;
48976babe50SJustin T. Gibbs int sf;
49076babe50SJustin T. Gibbs
49176babe50SJustin T. Gibbs if ((csio->ccb_h.ccb_state & PT_CCB_RETRY_UA) != 0)
49276babe50SJustin T. Gibbs sf = SF_RETRY_UA;
49376babe50SJustin T. Gibbs else
49476babe50SJustin T. Gibbs sf = 0;
49576babe50SJustin T. Gibbs
4963393f8daSKenneth D. Merry error = pterror(done_ccb, CAM_RETRY_SELTO, sf);
4973393f8daSKenneth D. Merry if (error == ERESTART) {
49876babe50SJustin T. Gibbs /*
49976babe50SJustin T. Gibbs * A retry was scheuled, so
50076babe50SJustin T. Gibbs * just return.
50176babe50SJustin T. Gibbs */
50276babe50SJustin T. Gibbs return;
50376babe50SJustin T. Gibbs }
50476babe50SJustin T. Gibbs if (error != 0) {
50576babe50SJustin T. Gibbs if (error == ENXIO) {
50676babe50SJustin T. Gibbs /*
50776babe50SJustin T. Gibbs * Catastrophic error. Mark our device
50876babe50SJustin T. Gibbs * as invalid.
50976babe50SJustin T. Gibbs */
510f0d9af51SMatt Jacob xpt_print(periph->path,
511f0d9af51SMatt Jacob "Invalidating device\n");
51276babe50SJustin T. Gibbs softc->flags |= PT_FLAG_DEVICE_INVALID;
51376babe50SJustin T. Gibbs }
51476babe50SJustin T. Gibbs
51576babe50SJustin T. Gibbs /*
51676babe50SJustin T. Gibbs * return all queued I/O with EIO, so that
51776babe50SJustin T. Gibbs * the client can retry these I/Os in the
51876babe50SJustin T. Gibbs * proper order should it attempt to recover.
51976babe50SJustin T. Gibbs */
520891619a6SPoul-Henning Kamp bioq_flush(&softc->bio_queue, NULL, EIO);
5218177437dSPoul-Henning Kamp bp->bio_error = error;
5228177437dSPoul-Henning Kamp bp->bio_resid = bp->bio_bcount;
5238177437dSPoul-Henning Kamp bp->bio_flags |= BIO_ERROR;
52476babe50SJustin T. Gibbs } else {
5258177437dSPoul-Henning Kamp bp->bio_resid = csio->resid;
5268177437dSPoul-Henning Kamp bp->bio_error = 0;
5278177437dSPoul-Henning Kamp if (bp->bio_resid != 0) {
52876babe50SJustin T. Gibbs /* Short transfer ??? */
5298177437dSPoul-Henning Kamp bp->bio_flags |= BIO_ERROR;
53076babe50SJustin T. Gibbs }
53176babe50SJustin T. Gibbs }
53276babe50SJustin T. Gibbs if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
53376babe50SJustin T. Gibbs cam_release_devq(done_ccb->ccb_h.path,
53476babe50SJustin T. Gibbs /*relsim_flags*/0,
53576babe50SJustin T. Gibbs /*reduction*/0,
53676babe50SJustin T. Gibbs /*timeout*/0,
53776babe50SJustin T. Gibbs /*getcount_only*/0);
53876babe50SJustin T. Gibbs } else {
5398177437dSPoul-Henning Kamp bp->bio_resid = csio->resid;
5408177437dSPoul-Henning Kamp if (bp->bio_resid != 0)
5418177437dSPoul-Henning Kamp bp->bio_flags |= BIO_ERROR;
54276babe50SJustin T. Gibbs }
54376babe50SJustin T. Gibbs
54476babe50SJustin T. Gibbs /*
5457a2b450fSEitan Adler * Block out any asynchronous callbacks
54676babe50SJustin T. Gibbs * while we touch the pending ccb list.
54776babe50SJustin T. Gibbs */
54876babe50SJustin T. Gibbs LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
54976babe50SJustin T. Gibbs
550a9d2245eSPoul-Henning Kamp biofinish(bp, softc->device_stats, 0);
55176babe50SJustin T. Gibbs break;
55276babe50SJustin T. Gibbs }
55376babe50SJustin T. Gibbs }
55476babe50SJustin T. Gibbs xpt_release_ccb(done_ccb);
55576babe50SJustin T. Gibbs }
55676babe50SJustin T. Gibbs
55776babe50SJustin T. Gibbs static int
pterror(union ccb * ccb,uint32_t cam_flags,uint32_t sense_flags)558*7c5d20a6SWarner Losh pterror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
55976babe50SJustin T. Gibbs {
56076babe50SJustin T. Gibbs
561553484aeSWarner Losh return(cam_periph_error(ccb, cam_flags, sense_flags));
56276babe50SJustin T. Gibbs }
56376babe50SJustin T. Gibbs
5643ece1bd2SKenneth D. Merry static int
ptioctl(struct cdev * dev,u_long cmd,caddr_t addr,int flag,struct thread * td)56589c9c53dSPoul-Henning Kamp ptioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
5663ece1bd2SKenneth D. Merry {
5673ece1bd2SKenneth D. Merry struct cam_periph *periph;
5683ece1bd2SKenneth D. Merry struct pt_softc *softc;
5692b83592fSScott Long int error = 0;
5703ece1bd2SKenneth D. Merry
571e2a5fdf9SNate Lawson periph = (struct cam_periph *)dev->si_drv1;
5723ece1bd2SKenneth D. Merry softc = (struct pt_softc *)periph->softc;
5733ece1bd2SKenneth D. Merry
5742b83592fSScott Long cam_periph_lock(periph);
5753ece1bd2SKenneth D. Merry
5763ece1bd2SKenneth D. Merry switch(cmd) {
5773ece1bd2SKenneth D. Merry case PTIOCGETTIMEOUT:
5783ece1bd2SKenneth D. Merry if (softc->io_timeout >= 1000)
5793ece1bd2SKenneth D. Merry *(int *)addr = softc->io_timeout / 1000;
5803ece1bd2SKenneth D. Merry else
5813ece1bd2SKenneth D. Merry *(int *)addr = 0;
5823ece1bd2SKenneth D. Merry break;
5833ece1bd2SKenneth D. Merry case PTIOCSETTIMEOUT:
5843ece1bd2SKenneth D. Merry if (*(int *)addr < 1) {
5853ece1bd2SKenneth D. Merry error = EINVAL;
5863ece1bd2SKenneth D. Merry break;
5873ece1bd2SKenneth D. Merry }
5883ece1bd2SKenneth D. Merry
5893ece1bd2SKenneth D. Merry softc->io_timeout = *(int *)addr * 1000;
5903ece1bd2SKenneth D. Merry
5913ece1bd2SKenneth D. Merry break;
5923ece1bd2SKenneth D. Merry default:
5933ece1bd2SKenneth D. Merry error = cam_periph_ioctl(periph, cmd, addr, pterror);
5943ece1bd2SKenneth D. Merry break;
5953ece1bd2SKenneth D. Merry }
5963ece1bd2SKenneth D. Merry
5973ece1bd2SKenneth D. Merry cam_periph_unlock(periph);
5983ece1bd2SKenneth D. Merry
5993ece1bd2SKenneth D. Merry return(error);
6003ece1bd2SKenneth D. Merry }
6013ece1bd2SKenneth D. Merry
60276babe50SJustin T. Gibbs void
scsi_send_receive(struct ccb_scsiio * csio,uint32_t retries,void (* cbfcnp)(struct cam_periph *,union ccb *),u_int tag_action,int readop,u_int byte2,uint32_t xfer_len,uint8_t * data_ptr,uint8_t sense_len,uint32_t timeout)603*7c5d20a6SWarner Losh scsi_send_receive(struct ccb_scsiio *csio, uint32_t retries,
60476babe50SJustin T. Gibbs void (*cbfcnp)(struct cam_periph *, union ccb *),
60576babe50SJustin T. Gibbs u_int tag_action, int readop, u_int byte2,
606*7c5d20a6SWarner Losh uint32_t xfer_len, uint8_t *data_ptr, uint8_t sense_len,
607*7c5d20a6SWarner Losh uint32_t timeout)
60876babe50SJustin T. Gibbs {
60976babe50SJustin T. Gibbs struct scsi_send_receive *scsi_cmd;
61076babe50SJustin T. Gibbs
61176babe50SJustin T. Gibbs scsi_cmd = (struct scsi_send_receive *)&csio->cdb_io.cdb_bytes;
61276babe50SJustin T. Gibbs scsi_cmd->opcode = readop ? RECEIVE : SEND;
61376babe50SJustin T. Gibbs scsi_cmd->byte2 = byte2;
61476babe50SJustin T. Gibbs scsi_ulto3b(xfer_len, scsi_cmd->xfer_len);
61576babe50SJustin T. Gibbs scsi_cmd->control = 0;
61676babe50SJustin T. Gibbs
61776babe50SJustin T. Gibbs cam_fill_csio(csio,
61876babe50SJustin T. Gibbs retries,
61976babe50SJustin T. Gibbs cbfcnp,
62076babe50SJustin T. Gibbs /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT,
62176babe50SJustin T. Gibbs tag_action,
62276babe50SJustin T. Gibbs data_ptr,
62376babe50SJustin T. Gibbs xfer_len,
62476babe50SJustin T. Gibbs sense_len,
62576babe50SJustin T. Gibbs sizeof(*scsi_cmd),
62676babe50SJustin T. Gibbs timeout);
62776babe50SJustin T. Gibbs }
628