1898b0535SWarner Losh /*-
26fda903fSJustin T. Gibbs * Implementation of the Target Mode 'Black Hole device' for CAM.
36fda903fSJustin T. Gibbs *
44d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
5bec9534dSPedro F. Giffuni *
66fda903fSJustin T. Gibbs * Copyright (c) 1999 Justin T. Gibbs.
76fda903fSJustin T. Gibbs * All rights reserved.
86fda903fSJustin T. Gibbs *
96fda903fSJustin T. Gibbs * Redistribution and use in source and binary forms, with or without
106fda903fSJustin T. Gibbs * modification, are permitted provided that the following conditions
116fda903fSJustin T. Gibbs * are met:
126fda903fSJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright
136fda903fSJustin T. Gibbs * notice, this list of conditions, and the following disclaimer,
146fda903fSJustin T. Gibbs * without modification, immediately at the beginning of the file.
156fda903fSJustin T. Gibbs * 2. The name of the author may not be used to endorse or promote products
166fda903fSJustin T. Gibbs * derived from this software without specific prior written permission.
176fda903fSJustin T. Gibbs *
186fda903fSJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
196fda903fSJustin T. Gibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
206fda903fSJustin T. Gibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
216fda903fSJustin T. Gibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
226fda903fSJustin T. Gibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
236fda903fSJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
246fda903fSJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
256fda903fSJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
266fda903fSJustin T. Gibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
276fda903fSJustin T. Gibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
286fda903fSJustin T. Gibbs * SUCH DAMAGE.
296fda903fSJustin T. Gibbs */
306fda903fSJustin T. Gibbs
316fda903fSJustin T. Gibbs #include <sys/param.h>
326fda903fSJustin T. Gibbs #include <sys/queue.h>
336fda903fSJustin T. Gibbs #include <sys/systm.h>
346fda903fSJustin T. Gibbs #include <sys/kernel.h>
356fda903fSJustin T. Gibbs #include <sys/types.h>
369626b608SPoul-Henning Kamp #include <sys/bio.h>
376fda903fSJustin T. Gibbs #include <sys/conf.h>
386fda903fSJustin T. Gibbs #include <sys/devicestat.h>
396fda903fSJustin T. Gibbs #include <sys/malloc.h>
406fda903fSJustin T. Gibbs #include <sys/uio.h>
416fda903fSJustin T. Gibbs
426fda903fSJustin T. Gibbs #include <cam/cam.h>
436fda903fSJustin T. Gibbs #include <cam/cam_ccb.h>
446fda903fSJustin T. Gibbs #include <cam/cam_periph.h>
456fda903fSJustin T. Gibbs #include <cam/cam_queue.h>
466fda903fSJustin T. Gibbs #include <cam/cam_xpt_periph.h>
476fda903fSJustin T. Gibbs #include <cam/cam_debug.h>
482b83592fSScott Long #include <cam/cam_sim.h>
496fda903fSJustin T. Gibbs
506fda903fSJustin T. Gibbs #include <cam/scsi/scsi_all.h>
516fda903fSJustin T. Gibbs #include <cam/scsi/scsi_message.h>
526fda903fSJustin T. Gibbs
53d745c852SEd Schouten static MALLOC_DEFINE(M_SCSIBH, "SCSI bh", "SCSI blackhole buffers");
54362abc44STai-hwa Liang
556fda903fSJustin T. Gibbs typedef enum {
566fda903fSJustin T. Gibbs TARGBH_STATE_NORMAL,
576fda903fSJustin T. Gibbs TARGBH_STATE_EXCEPTION,
586fda903fSJustin T. Gibbs TARGBH_STATE_TEARDOWN
596fda903fSJustin T. Gibbs } targbh_state;
606fda903fSJustin T. Gibbs
616fda903fSJustin T. Gibbs typedef enum {
626fda903fSJustin T. Gibbs TARGBH_FLAG_NONE = 0x00,
636fda903fSJustin T. Gibbs TARGBH_FLAG_LUN_ENABLED = 0x01
646fda903fSJustin T. Gibbs } targbh_flags;
656fda903fSJustin T. Gibbs
666fda903fSJustin T. Gibbs typedef enum {
67227d67aaSAlexander Motin TARGBH_CCB_WORKQ
686fda903fSJustin T. Gibbs } targbh_ccb_types;
696fda903fSJustin T. Gibbs
70e7783a9fSJustin T. Gibbs #define MAX_ACCEPT 8
716fda903fSJustin T. Gibbs #define MAX_IMMEDIATE 16
726fda903fSJustin T. Gibbs #define MAX_BUF_SIZE 256 /* Max inquiry/sense/mode page transfer */
736fda903fSJustin T. Gibbs
746fda903fSJustin T. Gibbs /* Offsets into our private CCB area for storing accept information */
756fda903fSJustin T. Gibbs #define ccb_type ppriv_field0
766fda903fSJustin T. Gibbs #define ccb_descr ppriv_ptr1
776fda903fSJustin T. Gibbs
786fda903fSJustin T. Gibbs /* We stick a pointer to the originating accept TIO in each continue I/O CCB */
796fda903fSJustin T. Gibbs #define ccb_atio ppriv_ptr1
806fda903fSJustin T. Gibbs
81e3975643SJake Burkholder TAILQ_HEAD(ccb_queue, ccb_hdr);
826fda903fSJustin T. Gibbs
836fda903fSJustin T. Gibbs struct targbh_softc {
846fda903fSJustin T. Gibbs struct ccb_queue pending_queue;
856fda903fSJustin T. Gibbs struct ccb_queue work_queue;
866fda903fSJustin T. Gibbs struct ccb_queue unknown_atio_queue;
876fda903fSJustin T. Gibbs struct devstat device_stats;
886fda903fSJustin T. Gibbs targbh_state state;
896fda903fSJustin T. Gibbs targbh_flags flags;
906fda903fSJustin T. Gibbs u_int init_level;
916fda903fSJustin T. Gibbs u_int inq_data_len;
926fda903fSJustin T. Gibbs struct ccb_accept_tio *accept_tio_list;
936fda903fSJustin T. Gibbs struct ccb_hdr_slist immed_notify_slist;
946fda903fSJustin T. Gibbs };
956fda903fSJustin T. Gibbs
966fda903fSJustin T. Gibbs struct targbh_cmd_desc {
976fda903fSJustin T. Gibbs struct ccb_accept_tio* atio_link;
986fda903fSJustin T. Gibbs u_int data_resid; /* How much left to transfer */
996fda903fSJustin T. Gibbs u_int data_increment;/* Amount to send before next disconnect */
1006fda903fSJustin T. Gibbs void* data; /* The data. Can be from backing_store or not */
1016fda903fSJustin T. Gibbs void* backing_store;/* Backing store allocated for this descriptor*/
1026fda903fSJustin T. Gibbs u_int max_size; /* Size of backing_store */
103*7c5d20a6SWarner Losh uint32_t timeout;
104*7c5d20a6SWarner Losh uint8_t status; /* Status to return to initiator */
1056fda903fSJustin T. Gibbs };
1066fda903fSJustin T. Gibbs
1076fda903fSJustin T. Gibbs static struct scsi_inquiry_data no_lun_inq_data =
1086fda903fSJustin T. Gibbs {
1096fda903fSJustin T. Gibbs T_NODEVICE | (SID_QUAL_BAD_LU << 5), 0,
1106fda903fSJustin T. Gibbs /* version */2, /* format version */2
1116fda903fSJustin T. Gibbs };
1126fda903fSJustin T. Gibbs
1131cc052e8SKenneth D. Merry static struct scsi_sense_data_fixed no_lun_sense_data =
1146fda903fSJustin T. Gibbs {
1156fda903fSJustin T. Gibbs SSD_CURRENT_ERROR|SSD_ERRCODE_VALID,
1166fda903fSJustin T. Gibbs 0,
1176fda903fSJustin T. Gibbs SSD_KEY_NOT_READY,
118e7783a9fSJustin T. Gibbs { 0, 0, 0, 0 },
1191cc052e8SKenneth D. Merry /*extra_len*/offsetof(struct scsi_sense_data_fixed, fru)
1201cc052e8SKenneth D. Merry - offsetof(struct scsi_sense_data_fixed, extra_len),
121e7783a9fSJustin T. Gibbs { 0, 0, 0, 0 },
1226fda903fSJustin T. Gibbs /* Logical Unit Not Supported */
1236fda903fSJustin T. Gibbs /*ASC*/0x25, /*ASCQ*/0
1246fda903fSJustin T. Gibbs };
1256fda903fSJustin T. Gibbs
1261cc052e8SKenneth D. Merry static const int request_sense_size = offsetof(struct scsi_sense_data_fixed, fru);
1276fda903fSJustin T. Gibbs
1286fda903fSJustin T. Gibbs static periph_init_t targbhinit;
129*7c5d20a6SWarner Losh static void targbhasync(void *callback_arg, uint32_t code,
1306fda903fSJustin T. Gibbs struct cam_path *path, void *arg);
1316fda903fSJustin T. Gibbs static cam_status targbhenlun(struct cam_periph *periph);
1326fda903fSJustin T. Gibbs static cam_status targbhdislun(struct cam_periph *periph);
1336fda903fSJustin T. Gibbs static periph_ctor_t targbhctor;
1346fda903fSJustin T. Gibbs static periph_dtor_t targbhdtor;
1356fda903fSJustin T. Gibbs static periph_start_t targbhstart;
1366fda903fSJustin T. Gibbs static void targbhdone(struct cam_periph *periph,
1376fda903fSJustin T. Gibbs union ccb *done_ccb);
138e7783a9fSJustin T. Gibbs #ifdef NOTYET
139*7c5d20a6SWarner Losh static int targbherror(union ccb *ccb, uint32_t cam_flags,
140*7c5d20a6SWarner Losh uint32_t sense_flags);
141e7783a9fSJustin T. Gibbs #endif
1426fda903fSJustin T. Gibbs static struct targbh_cmd_desc* targbhallocdescr(void);
1436fda903fSJustin T. Gibbs static void targbhfreedescr(struct targbh_cmd_desc *buf);
1446fda903fSJustin T. Gibbs
1456fda903fSJustin T. Gibbs static struct periph_driver targbhdriver =
1466fda903fSJustin T. Gibbs {
1476fda903fSJustin T. Gibbs targbhinit, "targbh",
1486fda903fSJustin T. Gibbs TAILQ_HEAD_INITIALIZER(targbhdriver.units), /* generation */ 0
1496fda903fSJustin T. Gibbs };
1506fda903fSJustin T. Gibbs
1510b7c27b9SPeter Wemm PERIPHDRIVER_DECLARE(targbh, targbhdriver);
1526fda903fSJustin T. Gibbs
1536fda903fSJustin T. Gibbs static void
targbhinit(void)1546fda903fSJustin T. Gibbs targbhinit(void)
1556fda903fSJustin T. Gibbs {
1566fda903fSJustin T. Gibbs cam_status status;
1576fda903fSJustin T. Gibbs
1586fda903fSJustin T. Gibbs /*
1596fda903fSJustin T. Gibbs * Install a global async callback. This callback will
1606fda903fSJustin T. Gibbs * receive async callbacks like "new path registered".
1616fda903fSJustin T. Gibbs */
16285d92640SScott Long status = xpt_register_async(AC_PATH_REGISTERED | AC_PATH_DEREGISTERED,
16385d92640SScott Long targbhasync, NULL, NULL);
1646fda903fSJustin T. Gibbs
1656fda903fSJustin T. Gibbs if (status != CAM_REQ_CMP) {
1666fda903fSJustin T. Gibbs printf("targbh: Failed to attach master async callback "
1676fda903fSJustin T. Gibbs "due to status 0x%x!\n", status);
1686fda903fSJustin T. Gibbs }
1696fda903fSJustin T. Gibbs }
1706fda903fSJustin T. Gibbs
1716fda903fSJustin T. Gibbs static void
targbhasync(void * callback_arg,uint32_t code,struct cam_path * path,void * arg)172*7c5d20a6SWarner Losh targbhasync(void *callback_arg, uint32_t code,
1736fda903fSJustin T. Gibbs struct cam_path *path, void *arg)
1746fda903fSJustin T. Gibbs {
1756fda903fSJustin T. Gibbs struct cam_path *new_path;
17660ddd2e4SHidetoshi Shimokawa struct ccb_pathinq *cpi;
17760ddd2e4SHidetoshi Shimokawa path_id_t bus_path_id;
1786fda903fSJustin T. Gibbs cam_status status;
1796fda903fSJustin T. Gibbs
18060ddd2e4SHidetoshi Shimokawa cpi = (struct ccb_pathinq *)arg;
18160ddd2e4SHidetoshi Shimokawa if (code == AC_PATH_REGISTERED)
18260ddd2e4SHidetoshi Shimokawa bus_path_id = cpi->ccb_h.path_id;
18360ddd2e4SHidetoshi Shimokawa else
18460ddd2e4SHidetoshi Shimokawa bus_path_id = xpt_path_path_id(path);
1856fda903fSJustin T. Gibbs /*
1866fda903fSJustin T. Gibbs * Allocate a peripheral instance for
1876fda903fSJustin T. Gibbs * this target instance.
1886fda903fSJustin T. Gibbs */
1896fda903fSJustin T. Gibbs status = xpt_create_path(&new_path, NULL,
19060ddd2e4SHidetoshi Shimokawa bus_path_id,
1916fda903fSJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
1926fda903fSJustin T. Gibbs if (status != CAM_REQ_CMP) {
1936fda903fSJustin T. Gibbs printf("targbhasync: Unable to create path "
1946fda903fSJustin T. Gibbs "due to status 0x%x\n", status);
195388f522dSHidetoshi Shimokawa return;
1966fda903fSJustin T. Gibbs }
197388f522dSHidetoshi Shimokawa
198388f522dSHidetoshi Shimokawa switch (code) {
199388f522dSHidetoshi Shimokawa case AC_PATH_REGISTERED:
200388f522dSHidetoshi Shimokawa {
201388f522dSHidetoshi Shimokawa /* Only attach to controllers that support target mode */
202388f522dSHidetoshi Shimokawa if ((cpi->target_sprt & PIT_PROCESSOR) == 0)
203388f522dSHidetoshi Shimokawa break;
204388f522dSHidetoshi Shimokawa
2056fda903fSJustin T. Gibbs status = cam_periph_alloc(targbhctor, NULL, targbhdtor,
2066fda903fSJustin T. Gibbs targbhstart,
2076fda903fSJustin T. Gibbs "targbh", CAM_PERIPH_BIO,
2086fda903fSJustin T. Gibbs new_path, targbhasync,
2096fda903fSJustin T. Gibbs AC_PATH_REGISTERED,
2106fda903fSJustin T. Gibbs cpi);
2116fda903fSJustin T. Gibbs break;
2126fda903fSJustin T. Gibbs }
2136fda903fSJustin T. Gibbs case AC_PATH_DEREGISTERED:
2146fda903fSJustin T. Gibbs {
21560ddd2e4SHidetoshi Shimokawa struct cam_periph *periph;
21660ddd2e4SHidetoshi Shimokawa
21760ddd2e4SHidetoshi Shimokawa if ((periph = cam_periph_find(new_path, "targbh")) != NULL)
21860ddd2e4SHidetoshi Shimokawa cam_periph_invalidate(periph);
2196fda903fSJustin T. Gibbs break;
2206fda903fSJustin T. Gibbs }
2216fda903fSJustin T. Gibbs default:
2226fda903fSJustin T. Gibbs break;
2236fda903fSJustin T. Gibbs }
224388f522dSHidetoshi Shimokawa xpt_free_path(new_path);
2256fda903fSJustin T. Gibbs }
2266fda903fSJustin T. Gibbs
2276fda903fSJustin T. Gibbs /* Attempt to enable our lun */
2286fda903fSJustin T. Gibbs static cam_status
targbhenlun(struct cam_periph * periph)2296fda903fSJustin T. Gibbs targbhenlun(struct cam_periph *periph)
2306fda903fSJustin T. Gibbs {
2316fda903fSJustin T. Gibbs union ccb immed_ccb;
2326fda903fSJustin T. Gibbs struct targbh_softc *softc;
2336fda903fSJustin T. Gibbs cam_status status;
2346fda903fSJustin T. Gibbs int i;
2356fda903fSJustin T. Gibbs
2366fda903fSJustin T. Gibbs softc = (struct targbh_softc *)periph->softc;
2376fda903fSJustin T. Gibbs
2386fda903fSJustin T. Gibbs if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) != 0)
2396fda903fSJustin T. Gibbs return (CAM_REQ_CMP);
2406fda903fSJustin T. Gibbs
241616a676aSEdward Tomasz Napierala memset(&immed_ccb, 0, sizeof(immed_ccb));
242bbfa4aa1SAlexander Motin xpt_setup_ccb(&immed_ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
2436fda903fSJustin T. Gibbs immed_ccb.ccb_h.func_code = XPT_EN_LUN;
2446fda903fSJustin T. Gibbs
2456fda903fSJustin T. Gibbs /* Don't need support for any vendor specific commands */
2466fda903fSJustin T. Gibbs immed_ccb.cel.grp6_len = 0;
2476fda903fSJustin T. Gibbs immed_ccb.cel.grp7_len = 0;
2486fda903fSJustin T. Gibbs immed_ccb.cel.enable = 1;
2496fda903fSJustin T. Gibbs xpt_action(&immed_ccb);
2506fda903fSJustin T. Gibbs status = immed_ccb.ccb_h.status;
2516fda903fSJustin T. Gibbs if (status != CAM_REQ_CMP) {
252f0d9af51SMatt Jacob xpt_print(periph->path,
253f0d9af51SMatt Jacob "targbhenlun - Enable Lun Rejected with status 0x%x\n",
2546fda903fSJustin T. Gibbs status);
2556fda903fSJustin T. Gibbs return (status);
2566fda903fSJustin T. Gibbs }
2576fda903fSJustin T. Gibbs
2586fda903fSJustin T. Gibbs softc->flags |= TARGBH_FLAG_LUN_ENABLED;
2596fda903fSJustin T. Gibbs
2606fda903fSJustin T. Gibbs /*
2616fda903fSJustin T. Gibbs * Build up a buffer of accept target I/O
2626fda903fSJustin T. Gibbs * operations for incoming selections.
2636fda903fSJustin T. Gibbs */
2646fda903fSJustin T. Gibbs for (i = 0; i < MAX_ACCEPT; i++) {
2656fda903fSJustin T. Gibbs struct ccb_accept_tio *atio;
2666fda903fSJustin T. Gibbs
267362abc44STai-hwa Liang atio = (struct ccb_accept_tio*)malloc(sizeof(*atio), M_SCSIBH,
268616a676aSEdward Tomasz Napierala M_ZERO | M_NOWAIT);
2696fda903fSJustin T. Gibbs if (atio == NULL) {
2706fda903fSJustin T. Gibbs status = CAM_RESRC_UNAVAIL;
2716fda903fSJustin T. Gibbs break;
2726fda903fSJustin T. Gibbs }
2736fda903fSJustin T. Gibbs
2746fda903fSJustin T. Gibbs atio->ccb_h.ccb_descr = targbhallocdescr();
2756fda903fSJustin T. Gibbs
2766fda903fSJustin T. Gibbs if (atio->ccb_h.ccb_descr == NULL) {
277362abc44STai-hwa Liang free(atio, M_SCSIBH);
2786fda903fSJustin T. Gibbs status = CAM_RESRC_UNAVAIL;
2796fda903fSJustin T. Gibbs break;
2806fda903fSJustin T. Gibbs }
2816fda903fSJustin T. Gibbs
282bbfa4aa1SAlexander Motin xpt_setup_ccb(&atio->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
2836fda903fSJustin T. Gibbs atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
2846fda903fSJustin T. Gibbs atio->ccb_h.cbfcnp = targbhdone;
2856fda903fSJustin T. Gibbs ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link =
2866fda903fSJustin T. Gibbs softc->accept_tio_list;
2876fda903fSJustin T. Gibbs softc->accept_tio_list = atio;
288d1d536f0SAlexander Motin xpt_action((union ccb *)atio);
289d1d536f0SAlexander Motin status = atio->ccb_h.status;
290d1d536f0SAlexander Motin if (status != CAM_REQ_INPROG)
291d1d536f0SAlexander Motin break;
2926fda903fSJustin T. Gibbs }
2936fda903fSJustin T. Gibbs
2946fda903fSJustin T. Gibbs if (i == 0) {
295f0d9af51SMatt Jacob xpt_print(periph->path,
296f0d9af51SMatt Jacob "targbhenlun - Could not allocate accept tio CCBs: status "
297f0d9af51SMatt Jacob "= 0x%x\n", status);
2986fda903fSJustin T. Gibbs targbhdislun(periph);
2996fda903fSJustin T. Gibbs return (CAM_REQ_CMP_ERR);
3006fda903fSJustin T. Gibbs }
3016fda903fSJustin T. Gibbs
3026fda903fSJustin T. Gibbs /*
3036fda903fSJustin T. Gibbs * Build up a buffer of immediate notify CCBs
3046fda903fSJustin T. Gibbs * so the SIM can tell us of asynchronous target mode events.
3056fda903fSJustin T. Gibbs */
3066fda903fSJustin T. Gibbs for (i = 0; i < MAX_ACCEPT; i++) {
3071d64933fSAlexander Motin struct ccb_immediate_notify *inot;
3086fda903fSJustin T. Gibbs
3091d64933fSAlexander Motin inot = (struct ccb_immediate_notify*)malloc(sizeof(*inot),
310616a676aSEdward Tomasz Napierala M_SCSIBH, M_ZERO | M_NOWAIT);
3116fda903fSJustin T. Gibbs
3126fda903fSJustin T. Gibbs if (inot == NULL) {
3136fda903fSJustin T. Gibbs status = CAM_RESRC_UNAVAIL;
3146fda903fSJustin T. Gibbs break;
3156fda903fSJustin T. Gibbs }
3166fda903fSJustin T. Gibbs
317bbfa4aa1SAlexander Motin xpt_setup_ccb(&inot->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
3181d64933fSAlexander Motin inot->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
3196fda903fSJustin T. Gibbs inot->ccb_h.cbfcnp = targbhdone;
3206fda903fSJustin T. Gibbs SLIST_INSERT_HEAD(&softc->immed_notify_slist, &inot->ccb_h,
3216fda903fSJustin T. Gibbs periph_links.sle);
322d1d536f0SAlexander Motin xpt_action((union ccb *)inot);
323d1d536f0SAlexander Motin status = inot->ccb_h.status;
324d1d536f0SAlexander Motin if (status != CAM_REQ_INPROG)
325d1d536f0SAlexander Motin break;
3266fda903fSJustin T. Gibbs }
3276fda903fSJustin T. Gibbs
3286fda903fSJustin T. Gibbs if (i == 0) {
329f0d9af51SMatt Jacob xpt_print(periph->path,
330f0d9af51SMatt Jacob "targbhenlun - Could not allocate immediate notify "
3316fda903fSJustin T. Gibbs "CCBs: status = 0x%x\n", status);
3326fda903fSJustin T. Gibbs targbhdislun(periph);
3336fda903fSJustin T. Gibbs return (CAM_REQ_CMP_ERR);
3346fda903fSJustin T. Gibbs }
3356fda903fSJustin T. Gibbs
3366fda903fSJustin T. Gibbs return (CAM_REQ_CMP);
3376fda903fSJustin T. Gibbs }
3386fda903fSJustin T. Gibbs
3396fda903fSJustin T. Gibbs static cam_status
targbhdislun(struct cam_periph * periph)3406fda903fSJustin T. Gibbs targbhdislun(struct cam_periph *periph)
3416fda903fSJustin T. Gibbs {
3426fda903fSJustin T. Gibbs union ccb ccb;
3436fda903fSJustin T. Gibbs struct targbh_softc *softc;
3446fda903fSJustin T. Gibbs struct ccb_accept_tio* atio;
3456fda903fSJustin T. Gibbs struct ccb_hdr *ccb_h;
3466fda903fSJustin T. Gibbs
3476fda903fSJustin T. Gibbs softc = (struct targbh_softc *)periph->softc;
3486fda903fSJustin T. Gibbs if ((softc->flags & TARGBH_FLAG_LUN_ENABLED) == 0)
3496fda903fSJustin T. Gibbs return CAM_REQ_CMP;
3506fda903fSJustin T. Gibbs
351616a676aSEdward Tomasz Napierala memset(&ccb, 0, sizeof(ccb));
352616a676aSEdward Tomasz Napierala
3536fda903fSJustin T. Gibbs /* XXX Block for Continue I/O completion */
3546fda903fSJustin T. Gibbs
3556fda903fSJustin T. Gibbs /* Kill off all ACCECPT and IMMEDIATE CCBs */
3566fda903fSJustin T. Gibbs while ((atio = softc->accept_tio_list) != NULL) {
3576fda903fSJustin T. Gibbs
3586fda903fSJustin T. Gibbs softc->accept_tio_list =
3596fda903fSJustin T. Gibbs ((struct targbh_cmd_desc*)atio->ccb_h.ccb_descr)->atio_link;
360bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
3616fda903fSJustin T. Gibbs ccb.cab.ccb_h.func_code = XPT_ABORT;
3626fda903fSJustin T. Gibbs ccb.cab.abort_ccb = (union ccb *)atio;
3636fda903fSJustin T. Gibbs xpt_action(&ccb);
3646fda903fSJustin T. Gibbs }
3656fda903fSJustin T. Gibbs
3666fda903fSJustin T. Gibbs while ((ccb_h = SLIST_FIRST(&softc->immed_notify_slist)) != NULL) {
3676fda903fSJustin T. Gibbs SLIST_REMOVE_HEAD(&softc->immed_notify_slist, periph_links.sle);
368bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.cab.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
3696fda903fSJustin T. Gibbs ccb.cab.ccb_h.func_code = XPT_ABORT;
3706fda903fSJustin T. Gibbs ccb.cab.abort_ccb = (union ccb *)ccb_h;
3716fda903fSJustin T. Gibbs xpt_action(&ccb);
3726fda903fSJustin T. Gibbs }
3736fda903fSJustin T. Gibbs
3746fda903fSJustin T. Gibbs /*
3756fda903fSJustin T. Gibbs * Dissable this lun.
3766fda903fSJustin T. Gibbs */
377bbfa4aa1SAlexander Motin xpt_setup_ccb(&ccb.cel.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
3786fda903fSJustin T. Gibbs ccb.cel.ccb_h.func_code = XPT_EN_LUN;
3796fda903fSJustin T. Gibbs ccb.cel.enable = 0;
3806fda903fSJustin T. Gibbs xpt_action(&ccb);
3816fda903fSJustin T. Gibbs
3826fda903fSJustin T. Gibbs if (ccb.cel.ccb_h.status != CAM_REQ_CMP)
3836fda903fSJustin T. Gibbs printf("targbhdislun - Disabling lun on controller failed "
3846fda903fSJustin T. Gibbs "with status 0x%x\n", ccb.cel.ccb_h.status);
3856fda903fSJustin T. Gibbs else
3866fda903fSJustin T. Gibbs softc->flags &= ~TARGBH_FLAG_LUN_ENABLED;
3876fda903fSJustin T. Gibbs return (ccb.cel.ccb_h.status);
3886fda903fSJustin T. Gibbs }
3896fda903fSJustin T. Gibbs
3906fda903fSJustin T. Gibbs static cam_status
targbhctor(struct cam_periph * periph,void * arg)3916fda903fSJustin T. Gibbs targbhctor(struct cam_periph *periph, void *arg)
3926fda903fSJustin T. Gibbs {
3936fda903fSJustin T. Gibbs struct targbh_softc *softc;
3946fda903fSJustin T. Gibbs
3956fda903fSJustin T. Gibbs /* Allocate our per-instance private storage */
3966fda903fSJustin T. Gibbs softc = (struct targbh_softc *)malloc(sizeof(*softc),
397362abc44STai-hwa Liang M_SCSIBH, M_NOWAIT);
3986fda903fSJustin T. Gibbs if (softc == NULL) {
3996fda903fSJustin T. Gibbs printf("targctor: unable to malloc softc\n");
4006fda903fSJustin T. Gibbs return (CAM_REQ_CMP_ERR);
4016fda903fSJustin T. Gibbs }
4026fda903fSJustin T. Gibbs
403966a2adfSMatt Jacob bzero(softc, sizeof(*softc));
4046fda903fSJustin T. Gibbs TAILQ_INIT(&softc->pending_queue);
4056fda903fSJustin T. Gibbs TAILQ_INIT(&softc->work_queue);
4066fda903fSJustin T. Gibbs softc->accept_tio_list = NULL;
4076fda903fSJustin T. Gibbs SLIST_INIT(&softc->immed_notify_slist);
4086fda903fSJustin T. Gibbs softc->state = TARGBH_STATE_NORMAL;
4096fda903fSJustin T. Gibbs periph->softc = softc;
4106fda903fSJustin T. Gibbs softc->init_level++;
4116fda903fSJustin T. Gibbs
412d1d536f0SAlexander Motin if (targbhenlun(periph) != CAM_REQ_CMP)
413d1d536f0SAlexander Motin cam_periph_invalidate(periph);
414d1d536f0SAlexander Motin return (CAM_REQ_CMP);
4156fda903fSJustin T. Gibbs }
4166fda903fSJustin T. Gibbs
4176fda903fSJustin T. Gibbs static void
targbhdtor(struct cam_periph * periph)4186fda903fSJustin T. Gibbs targbhdtor(struct cam_periph *periph)
4196fda903fSJustin T. Gibbs {
4206fda903fSJustin T. Gibbs struct targbh_softc *softc;
4216fda903fSJustin T. Gibbs
4226fda903fSJustin T. Gibbs softc = (struct targbh_softc *)periph->softc;
4236fda903fSJustin T. Gibbs
4246fda903fSJustin T. Gibbs softc->state = TARGBH_STATE_TEARDOWN;
4256fda903fSJustin T. Gibbs
4266fda903fSJustin T. Gibbs targbhdislun(periph);
4276fda903fSJustin T. Gibbs
4286fda903fSJustin T. Gibbs switch (softc->init_level) {
4296fda903fSJustin T. Gibbs case 0:
430c2ede4b3SMartin Blapp panic("targdtor - impossible init level");
43182dcf708SPoul-Henning Kamp case 1:
43282dcf708SPoul-Henning Kamp /* FALLTHROUGH */
43382dcf708SPoul-Henning Kamp default:
434388f522dSHidetoshi Shimokawa /* XXX Wait for callback of targbhdislun() */
435227d67aaSAlexander Motin cam_periph_sleep(periph, softc, PRIBIO, "targbh", hz/2);
436362abc44STai-hwa Liang free(softc, M_SCSIBH);
43782dcf708SPoul-Henning Kamp break;
4386fda903fSJustin T. Gibbs }
4396fda903fSJustin T. Gibbs }
4406fda903fSJustin T. Gibbs
4416fda903fSJustin T. Gibbs static void
targbhstart(struct cam_periph * periph,union ccb * start_ccb)4426fda903fSJustin T. Gibbs targbhstart(struct cam_periph *periph, union ccb *start_ccb)
4436fda903fSJustin T. Gibbs {
4446fda903fSJustin T. Gibbs struct targbh_softc *softc;
4456fda903fSJustin T. Gibbs struct ccb_hdr *ccbh;
4466fda903fSJustin T. Gibbs struct ccb_accept_tio *atio;
4476fda903fSJustin T. Gibbs struct targbh_cmd_desc *desc;
4486fda903fSJustin T. Gibbs struct ccb_scsiio *csio;
4496fda903fSJustin T. Gibbs ccb_flags flags;
4506fda903fSJustin T. Gibbs
4516fda903fSJustin T. Gibbs softc = (struct targbh_softc *)periph->softc;
4526fda903fSJustin T. Gibbs
4536fda903fSJustin T. Gibbs ccbh = TAILQ_FIRST(&softc->work_queue);
454227d67aaSAlexander Motin if (ccbh == NULL) {
4556fda903fSJustin T. Gibbs xpt_release_ccb(start_ccb);
4566fda903fSJustin T. Gibbs } else {
4576fda903fSJustin T. Gibbs TAILQ_REMOVE(&softc->work_queue, ccbh, periph_links.tqe);
4586fda903fSJustin T. Gibbs TAILQ_INSERT_HEAD(&softc->pending_queue, ccbh,
4596fda903fSJustin T. Gibbs periph_links.tqe);
4606fda903fSJustin T. Gibbs atio = (struct ccb_accept_tio*)ccbh;
4616fda903fSJustin T. Gibbs desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
4626fda903fSJustin T. Gibbs
4636fda903fSJustin T. Gibbs /* Is this a tagged request? */
464c2accd34SMatt Jacob flags = atio->ccb_h.flags &
465c2accd34SMatt Jacob (CAM_DIS_DISCONNECT|CAM_TAG_ACTION_VALID|CAM_DIR_MASK);
4666fda903fSJustin T. Gibbs
467471da226SMatt Jacob csio = &start_ccb->csio;
4686fda903fSJustin T. Gibbs /*
4696fda903fSJustin T. Gibbs * If we are done with the transaction, tell the
4706fda903fSJustin T. Gibbs * controller to send status and perform a CMD_CMPLT.
471471da226SMatt Jacob * If we have associated sense data, see if we can
472471da226SMatt Jacob * send that too.
4736fda903fSJustin T. Gibbs */
474471da226SMatt Jacob if (desc->data_resid == desc->data_increment) {
4756fda903fSJustin T. Gibbs flags |= CAM_SEND_STATUS;
476471da226SMatt Jacob if (atio->sense_len) {
477471da226SMatt Jacob csio->sense_len = atio->sense_len;
478471da226SMatt Jacob csio->sense_data = atio->sense_data;
479471da226SMatt Jacob flags |= CAM_SEND_SENSE;
480471da226SMatt Jacob }
481471da226SMatt Jacob }
482471da226SMatt Jacob
4836fda903fSJustin T. Gibbs cam_fill_ctio(csio,
4846fda903fSJustin T. Gibbs /*retries*/2,
4856fda903fSJustin T. Gibbs targbhdone,
4866fda903fSJustin T. Gibbs flags,
4876bd19f42SMatt Jacob (flags & CAM_TAG_ACTION_VALID)?
4886bd19f42SMatt Jacob MSG_SIMPLE_Q_TAG : 0,
4896fda903fSJustin T. Gibbs atio->tag_id,
4906fda903fSJustin T. Gibbs atio->init_id,
4916fda903fSJustin T. Gibbs desc->status,
4926fda903fSJustin T. Gibbs /*data_ptr*/desc->data_increment == 0
4936fda903fSJustin T. Gibbs ? NULL : desc->data,
4946fda903fSJustin T. Gibbs /*dxfer_len*/desc->data_increment,
4956fda903fSJustin T. Gibbs /*timeout*/desc->timeout);
4966fda903fSJustin T. Gibbs
4976fda903fSJustin T. Gibbs /* Override our wildcard attachment */
4986fda903fSJustin T. Gibbs start_ccb->ccb_h.target_id = atio->ccb_h.target_id;
4996fda903fSJustin T. Gibbs start_ccb->ccb_h.target_lun = atio->ccb_h.target_lun;
5006fda903fSJustin T. Gibbs
5016fda903fSJustin T. Gibbs start_ccb->ccb_h.ccb_type = TARGBH_CCB_WORKQ;
5026fda903fSJustin T. Gibbs start_ccb->ccb_h.ccb_atio = atio;
5036fda903fSJustin T. Gibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
5046fda903fSJustin T. Gibbs ("Sending a CTIO\n"));
5056fda903fSJustin T. Gibbs xpt_action(start_ccb);
506c2accd34SMatt Jacob /*
507c2accd34SMatt Jacob * If the queue was frozen waiting for the response
508c2accd34SMatt Jacob * to this ATIO (for instance disconnection was disallowed),
509c2accd34SMatt Jacob * then release it now that our response has been queued.
510c2accd34SMatt Jacob */
511c2accd34SMatt Jacob if ((atio->ccb_h.status & CAM_DEV_QFRZN) != 0) {
512c2accd34SMatt Jacob cam_release_devq(periph->path,
513c2accd34SMatt Jacob /*relsim_flags*/0,
514c2accd34SMatt Jacob /*reduction*/0,
515c2accd34SMatt Jacob /*timeout*/0,
516c2accd34SMatt Jacob /*getcount_only*/0);
517c2accd34SMatt Jacob atio->ccb_h.status &= ~CAM_DEV_QFRZN;
518c2accd34SMatt Jacob }
5196fda903fSJustin T. Gibbs ccbh = TAILQ_FIRST(&softc->work_queue);
5206fda903fSJustin T. Gibbs }
5216fda903fSJustin T. Gibbs if (ccbh != NULL)
522bbfa4aa1SAlexander Motin xpt_schedule(periph, CAM_PRIORITY_NORMAL);
5236fda903fSJustin T. Gibbs }
5246fda903fSJustin T. Gibbs
5256fda903fSJustin T. Gibbs static void
targbhdone(struct cam_periph * periph,union ccb * done_ccb)5266fda903fSJustin T. Gibbs targbhdone(struct cam_periph *periph, union ccb *done_ccb)
5276fda903fSJustin T. Gibbs {
5286fda903fSJustin T. Gibbs struct targbh_softc *softc;
5296fda903fSJustin T. Gibbs
5306fda903fSJustin T. Gibbs softc = (struct targbh_softc *)periph->softc;
5316fda903fSJustin T. Gibbs
5326fda903fSJustin T. Gibbs switch (done_ccb->ccb_h.func_code) {
5336fda903fSJustin T. Gibbs case XPT_ACCEPT_TARGET_IO:
5346fda903fSJustin T. Gibbs {
5356fda903fSJustin T. Gibbs struct ccb_accept_tio *atio;
5366fda903fSJustin T. Gibbs struct targbh_cmd_desc *descr;
537*7c5d20a6SWarner Losh uint8_t *cdb;
538c2accd34SMatt Jacob int priority;
5396fda903fSJustin T. Gibbs
5406fda903fSJustin T. Gibbs atio = &done_ccb->atio;
5416fda903fSJustin T. Gibbs descr = (struct targbh_cmd_desc*)atio->ccb_h.ccb_descr;
5426fda903fSJustin T. Gibbs cdb = atio->cdb_io.cdb_bytes;
5436fda903fSJustin T. Gibbs if (softc->state == TARGBH_STATE_TEARDOWN
5446fda903fSJustin T. Gibbs || atio->ccb_h.status == CAM_REQ_ABORTED) {
5456fda903fSJustin T. Gibbs targbhfreedescr(descr);
546362abc44STai-hwa Liang xpt_free_ccb(done_ccb);
5476fda903fSJustin T. Gibbs return;
5486fda903fSJustin T. Gibbs }
5496fda903fSJustin T. Gibbs
5506fda903fSJustin T. Gibbs /*
5516fda903fSJustin T. Gibbs * Determine the type of incoming command and
5526fda903fSJustin T. Gibbs * setup our buffer for a response.
5536fda903fSJustin T. Gibbs */
5546fda903fSJustin T. Gibbs switch (cdb[0]) {
5556fda903fSJustin T. Gibbs case INQUIRY:
5566fda903fSJustin T. Gibbs {
5576fda903fSJustin T. Gibbs struct scsi_inquiry *inq;
5586fda903fSJustin T. Gibbs
5596fda903fSJustin T. Gibbs inq = (struct scsi_inquiry *)cdb;
5606fda903fSJustin T. Gibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
5616fda903fSJustin T. Gibbs ("Saw an inquiry!\n"));
5626fda903fSJustin T. Gibbs /*
5636fda903fSJustin T. Gibbs * Validate the command. We don't
5646fda903fSJustin T. Gibbs * support any VPD pages, so complain
5656fda903fSJustin T. Gibbs * if EVPD is set.
5666fda903fSJustin T. Gibbs */
5676fda903fSJustin T. Gibbs if ((inq->byte2 & SI_EVPD) != 0
5686fda903fSJustin T. Gibbs || inq->page_code != 0) {
5696fda903fSJustin T. Gibbs atio->ccb_h.flags &= ~CAM_DIR_MASK;
5706fda903fSJustin T. Gibbs atio->ccb_h.flags |= CAM_DIR_NONE;
571471da226SMatt Jacob /*
572471da226SMatt Jacob * This needs to have other than a
573471da226SMatt Jacob * no_lun_sense_data response.
574471da226SMatt Jacob */
5751cc052e8SKenneth D. Merry bcopy(&no_lun_sense_data, &atio->sense_data,
5761cc052e8SKenneth D. Merry min(sizeof(no_lun_sense_data),
5771cc052e8SKenneth D. Merry sizeof(atio->sense_data)));
578471da226SMatt Jacob atio->sense_len = sizeof(no_lun_sense_data);
5796fda903fSJustin T. Gibbs descr->data_resid = 0;
5806fda903fSJustin T. Gibbs descr->data_increment = 0;
5816fda903fSJustin T. Gibbs descr->status = SCSI_STATUS_CHECK_COND;
5826fda903fSJustin T. Gibbs break;
5836fda903fSJustin T. Gibbs }
5846fda903fSJustin T. Gibbs /*
5856fda903fSJustin T. Gibbs * Direction is always relative
5866fda903fSJustin T. Gibbs * to the initator.
5876fda903fSJustin T. Gibbs */
5886fda903fSJustin T. Gibbs atio->ccb_h.flags &= ~CAM_DIR_MASK;
5896fda903fSJustin T. Gibbs atio->ccb_h.flags |= CAM_DIR_IN;
5906fda903fSJustin T. Gibbs descr->data = &no_lun_inq_data;
5916fda903fSJustin T. Gibbs descr->data_resid = MIN(sizeof(no_lun_inq_data),
592130f4520SKenneth D. Merry scsi_2btoul(inq->length));
5936fda903fSJustin T. Gibbs descr->data_increment = descr->data_resid;
5946fda903fSJustin T. Gibbs descr->timeout = 5 * 1000;
5956fda903fSJustin T. Gibbs descr->status = SCSI_STATUS_OK;
5966fda903fSJustin T. Gibbs break;
5976fda903fSJustin T. Gibbs }
5986fda903fSJustin T. Gibbs case REQUEST_SENSE:
5996fda903fSJustin T. Gibbs {
6006fda903fSJustin T. Gibbs struct scsi_request_sense *rsense;
6016fda903fSJustin T. Gibbs
6026fda903fSJustin T. Gibbs rsense = (struct scsi_request_sense *)cdb;
6036fda903fSJustin T. Gibbs /* Refer to static sense data */
6046fda903fSJustin T. Gibbs atio->ccb_h.flags &= ~CAM_DIR_MASK;
6056fda903fSJustin T. Gibbs atio->ccb_h.flags |= CAM_DIR_IN;
6066fda903fSJustin T. Gibbs descr->data = &no_lun_sense_data;
6076fda903fSJustin T. Gibbs descr->data_resid = request_sense_size;
6086fda903fSJustin T. Gibbs descr->data_resid = MIN(descr->data_resid,
609966a2adfSMatt Jacob SCSI_CDB6_LEN(rsense->length));
6106fda903fSJustin T. Gibbs descr->data_increment = descr->data_resid;
6116fda903fSJustin T. Gibbs descr->timeout = 5 * 1000;
6126fda903fSJustin T. Gibbs descr->status = SCSI_STATUS_OK;
6136fda903fSJustin T. Gibbs break;
6146fda903fSJustin T. Gibbs }
6156fda903fSJustin T. Gibbs default:
6166fda903fSJustin T. Gibbs /* Constant CA, tell initiator */
6176fda903fSJustin T. Gibbs /* Direction is always relative to the initator */
6186fda903fSJustin T. Gibbs atio->ccb_h.flags &= ~CAM_DIR_MASK;
6196fda903fSJustin T. Gibbs atio->ccb_h.flags |= CAM_DIR_NONE;
6201cc052e8SKenneth D. Merry bcopy(&no_lun_sense_data, &atio->sense_data,
6211cc052e8SKenneth D. Merry min(sizeof(no_lun_sense_data),
6221cc052e8SKenneth D. Merry sizeof(atio->sense_data)));
623471da226SMatt Jacob atio->sense_len = sizeof (no_lun_sense_data);
6246fda903fSJustin T. Gibbs descr->data_resid = 0;
6256fda903fSJustin T. Gibbs descr->data_increment = 0;
6266fda903fSJustin T. Gibbs descr->timeout = 5 * 1000;
6276fda903fSJustin T. Gibbs descr->status = SCSI_STATUS_CHECK_COND;
6286fda903fSJustin T. Gibbs break;
6296fda903fSJustin T. Gibbs }
6306fda903fSJustin T. Gibbs
6316fda903fSJustin T. Gibbs /* Queue us up to receive a Continue Target I/O ccb. */
632c2accd34SMatt Jacob if ((atio->ccb_h.flags & CAM_DIS_DISCONNECT) != 0) {
633c2accd34SMatt Jacob TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h,
634c2accd34SMatt Jacob periph_links.tqe);
635c2accd34SMatt Jacob priority = 0;
636c2accd34SMatt Jacob } else {
6376fda903fSJustin T. Gibbs TAILQ_INSERT_TAIL(&softc->work_queue, &atio->ccb_h,
6386fda903fSJustin T. Gibbs periph_links.tqe);
639bbfa4aa1SAlexander Motin priority = CAM_PRIORITY_NORMAL;
640c2accd34SMatt Jacob }
641c2accd34SMatt Jacob xpt_schedule(periph, priority);
6426fda903fSJustin T. Gibbs break;
6436fda903fSJustin T. Gibbs }
6446fda903fSJustin T. Gibbs case XPT_CONT_TARGET_IO:
6456fda903fSJustin T. Gibbs {
6466fda903fSJustin T. Gibbs struct ccb_accept_tio *atio;
6476fda903fSJustin T. Gibbs struct targbh_cmd_desc *desc;
6486fda903fSJustin T. Gibbs
6496fda903fSJustin T. Gibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
6506fda903fSJustin T. Gibbs ("Received completed CTIO\n"));
6516fda903fSJustin T. Gibbs atio = (struct ccb_accept_tio*)done_ccb->ccb_h.ccb_atio;
6526fda903fSJustin T. Gibbs desc = (struct targbh_cmd_desc *)atio->ccb_h.ccb_descr;
6536fda903fSJustin T. Gibbs
6546fda903fSJustin T. Gibbs TAILQ_REMOVE(&softc->pending_queue, &atio->ccb_h,
6556fda903fSJustin T. Gibbs periph_links.tqe);
6566fda903fSJustin T. Gibbs
657471da226SMatt Jacob /*
658471da226SMatt Jacob * We could check for CAM_SENT_SENSE bein set here,
659471da226SMatt Jacob * but since we're not maintaining any CA/UA state,
660471da226SMatt Jacob * there's no point.
661471da226SMatt Jacob */
662471da226SMatt Jacob atio->sense_len = 0;
663471da226SMatt Jacob done_ccb->ccb_h.flags &= ~CAM_SEND_SENSE;
664471da226SMatt Jacob done_ccb->ccb_h.status &= ~CAM_SENT_SENSE;
665471da226SMatt Jacob
666c2accd34SMatt Jacob /*
667c2accd34SMatt Jacob * Any errors will not change the data we return,
668c2accd34SMatt Jacob * so make sure the queue is not left frozen.
669c2accd34SMatt Jacob * XXX - At some point there may be errors that
670c2accd34SMatt Jacob * leave us in a connected state with the
671c2accd34SMatt Jacob * initiator...
672c2accd34SMatt Jacob */
673c2accd34SMatt Jacob if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
674c2accd34SMatt Jacob printf("Releasing Queue\n");
675c2accd34SMatt Jacob cam_release_devq(done_ccb->ccb_h.path,
676c2accd34SMatt Jacob /*relsim_flags*/0,
677c2accd34SMatt Jacob /*reduction*/0,
678c2accd34SMatt Jacob /*timeout*/0,
679c2accd34SMatt Jacob /*getcount_only*/0);
680c2accd34SMatt Jacob done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
681c2accd34SMatt Jacob }
6826fda903fSJustin T. Gibbs desc->data_resid -= desc->data_increment;
6836fda903fSJustin T. Gibbs xpt_release_ccb(done_ccb);
6846fda903fSJustin T. Gibbs if (softc->state != TARGBH_STATE_TEARDOWN) {
6856fda903fSJustin T. Gibbs /*
6866fda903fSJustin T. Gibbs * Send the original accept TIO back to the
6876fda903fSJustin T. Gibbs * controller to handle more work.
6886fda903fSJustin T. Gibbs */
6896fda903fSJustin T. Gibbs CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
6906fda903fSJustin T. Gibbs ("Returning ATIO to target\n"));
6916fda903fSJustin T. Gibbs /* Restore wildcards */
6926fda903fSJustin T. Gibbs atio->ccb_h.target_id = CAM_TARGET_WILDCARD;
6936fda903fSJustin T. Gibbs atio->ccb_h.target_lun = CAM_LUN_WILDCARD;
6946fda903fSJustin T. Gibbs xpt_action((union ccb *)atio);
6956fda903fSJustin T. Gibbs break;
6966fda903fSJustin T. Gibbs } else {
6976fda903fSJustin T. Gibbs targbhfreedescr(desc);
698362abc44STai-hwa Liang free(atio, M_SCSIBH);
6996fda903fSJustin T. Gibbs }
7006fda903fSJustin T. Gibbs break;
7016fda903fSJustin T. Gibbs }
7021d64933fSAlexander Motin case XPT_IMMEDIATE_NOTIFY:
7036fda903fSJustin T. Gibbs {
704c2accd34SMatt Jacob int frozen;
705c2accd34SMatt Jacob
706c2accd34SMatt Jacob frozen = (done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
7076fda903fSJustin T. Gibbs if (softc->state == TARGBH_STATE_TEARDOWN
7086fda903fSJustin T. Gibbs || done_ccb->ccb_h.status == CAM_REQ_ABORTED) {
7096fda903fSJustin T. Gibbs printf("Freed an immediate notify\n");
710362abc44STai-hwa Liang xpt_free_ccb(done_ccb);
711c2accd34SMatt Jacob } else {
712c2accd34SMatt Jacob /* Requeue for another immediate event */
713c2accd34SMatt Jacob xpt_action(done_ccb);
7146fda903fSJustin T. Gibbs }
715c2accd34SMatt Jacob if (frozen != 0)
716c2accd34SMatt Jacob cam_release_devq(periph->path,
717c2accd34SMatt Jacob /*relsim_flags*/0,
718c2accd34SMatt Jacob /*opening reduction*/0,
719c2accd34SMatt Jacob /*timeout*/0,
720c2accd34SMatt Jacob /*getcount_only*/0);
7216fda903fSJustin T. Gibbs break;
7226fda903fSJustin T. Gibbs }
723e7783a9fSJustin T. Gibbs default:
724e7783a9fSJustin T. Gibbs panic("targbhdone: Unexpected ccb opcode");
725e7783a9fSJustin T. Gibbs break;
7266fda903fSJustin T. Gibbs }
7276fda903fSJustin T. Gibbs }
7286fda903fSJustin T. Gibbs
729e7783a9fSJustin T. Gibbs #ifdef NOTYET
7306fda903fSJustin T. Gibbs static int
targbherror(union ccb * ccb,uint32_t cam_flags,uint32_t sense_flags)731*7c5d20a6SWarner Losh targbherror(union ccb *ccb, uint32_t cam_flags, uint32_t sense_flags)
7326fda903fSJustin T. Gibbs {
7336fda903fSJustin T. Gibbs return 0;
7346fda903fSJustin T. Gibbs }
735e7783a9fSJustin T. Gibbs #endif
7366fda903fSJustin T. Gibbs
7376fda903fSJustin T. Gibbs static struct targbh_cmd_desc*
targbhallocdescr(void)7389982b3eeSConrad Meyer targbhallocdescr(void)
7396fda903fSJustin T. Gibbs {
7406fda903fSJustin T. Gibbs struct targbh_cmd_desc* descr;
7416fda903fSJustin T. Gibbs
7426fda903fSJustin T. Gibbs /* Allocate the targbh_descr structure */
7436fda903fSJustin T. Gibbs descr = (struct targbh_cmd_desc *)malloc(sizeof(*descr),
744362abc44STai-hwa Liang M_SCSIBH, M_NOWAIT);
7456fda903fSJustin T. Gibbs if (descr == NULL)
7466fda903fSJustin T. Gibbs return (NULL);
7476fda903fSJustin T. Gibbs
7486fda903fSJustin T. Gibbs bzero(descr, sizeof(*descr));
7496fda903fSJustin T. Gibbs
7506fda903fSJustin T. Gibbs /* Allocate buffer backing store */
751362abc44STai-hwa Liang descr->backing_store = malloc(MAX_BUF_SIZE, M_SCSIBH, M_NOWAIT);
7526fda903fSJustin T. Gibbs if (descr->backing_store == NULL) {
753362abc44STai-hwa Liang free(descr, M_SCSIBH);
7546fda903fSJustin T. Gibbs return (NULL);
7556fda903fSJustin T. Gibbs }
7566fda903fSJustin T. Gibbs descr->max_size = MAX_BUF_SIZE;
7576fda903fSJustin T. Gibbs return (descr);
7586fda903fSJustin T. Gibbs }
7596fda903fSJustin T. Gibbs
7606fda903fSJustin T. Gibbs static void
targbhfreedescr(struct targbh_cmd_desc * descr)7616fda903fSJustin T. Gibbs targbhfreedescr(struct targbh_cmd_desc *descr)
7626fda903fSJustin T. Gibbs {
763362abc44STai-hwa Liang free(descr->backing_store, M_SCSIBH);
764362abc44STai-hwa Liang free(descr, M_SCSIBH);
7656fda903fSJustin T. Gibbs }
766