1f9f848faSopenharmony_ci#include <sys/cdefs.h> 2f9f848faSopenharmony_ci/*- 3f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 4f9f848faSopenharmony_ci * 5f9f848faSopenharmony_ci * Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>, 6f9f848faSopenharmony_ci * Nick Hibma <n_hibma@FreeBSD.org> 7f9f848faSopenharmony_ci * All rights reserved. 8f9f848faSopenharmony_ci * 9f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 10f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 11f9f848faSopenharmony_ci * are met: 12f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 13f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 14f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 15f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 16f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 17f9f848faSopenharmony_ci * 18f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21f9f848faSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22f9f848faSopenharmony_ci * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23f9f848faSopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24f9f848faSopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25f9f848faSopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26f9f848faSopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27f9f848faSopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28f9f848faSopenharmony_ci * SUCH DAMAGE. 29f9f848faSopenharmony_ci * $NetBSD: umass.c,v 1.28 2000/04/02 23:46:53 augustss Exp $ 30f9f848faSopenharmony_ci */ 31f9f848faSopenharmony_ci 32f9f848faSopenharmony_ci/* Also already merged from NetBSD: 33f9f848faSopenharmony_ci * $NetBSD: umass.c,v 1.67 2001/11/25 19:05:22 augustss Exp $ 34f9f848faSopenharmony_ci * $NetBSD: umass.c,v 1.90 2002/11/04 19:17:33 pooka Exp $ 35f9f848faSopenharmony_ci * $NetBSD: umass.c,v 1.108 2003/11/07 17:03:25 wiz Exp $ 36f9f848faSopenharmony_ci * $NetBSD: umass.c,v 1.109 2003/12/04 13:57:31 keihan Exp $ 37f9f848faSopenharmony_ci */ 38f9f848faSopenharmony_ci 39f9f848faSopenharmony_ci/* 40f9f848faSopenharmony_ci * Universal Serial Bus Mass Storage Class specs: 41f9f848faSopenharmony_ci * http://www.usb.org/developers/devclass_docs/usb_msc_overview_1.2.pdf 42f9f848faSopenharmony_ci * http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf 43f9f848faSopenharmony_ci * http://www.usb.org/developers/devclass_docs/usb_msc_cbi_1.1.pdf 44f9f848faSopenharmony_ci * http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf 45f9f848faSopenharmony_ci */ 46f9f848faSopenharmony_ci 47f9f848faSopenharmony_ci/* 48f9f848faSopenharmony_ci * Ported to NetBSD by Lennart Augustsson <augustss@NetBSD.org>. 49f9f848faSopenharmony_ci * Parts of the code written by Jason R. Thorpe <thorpej@shagadelic.org>. 50f9f848faSopenharmony_ci */ 51f9f848faSopenharmony_ci 52f9f848faSopenharmony_ci/* 53f9f848faSopenharmony_ci * The driver handles 3 Wire Protocols 54f9f848faSopenharmony_ci * - Command/Bulk/Interrupt (CBI) 55f9f848faSopenharmony_ci * - Command/Bulk/Interrupt with Command Completion Interrupt (CBI with CCI) 56f9f848faSopenharmony_ci * - Mass Storage Bulk-Only (BBB) 57f9f848faSopenharmony_ci * (BBB refers Bulk/Bulk/Bulk for Command/Data/Status phases) 58f9f848faSopenharmony_ci * 59f9f848faSopenharmony_ci * Over these wire protocols it handles the following command protocols 60f9f848faSopenharmony_ci * - SCSI 61f9f848faSopenharmony_ci * - UFI (floppy command set) 62f9f848faSopenharmony_ci * - 8070i (ATAPI) 63f9f848faSopenharmony_ci * 64f9f848faSopenharmony_ci * UFI and 8070i (ATAPI) are transformed versions of the SCSI command set. The 65f9f848faSopenharmony_ci * sc->sc_transform method is used to convert the commands into the appropriate 66f9f848faSopenharmony_ci * format (if at all necessary). For example, UFI requires all commands to be 67f9f848faSopenharmony_ci * 12 bytes in length amongst other things. 68f9f848faSopenharmony_ci * 69f9f848faSopenharmony_ci * The source code below is marked and can be split into a number of pieces 70f9f848faSopenharmony_ci * (in this order): 71f9f848faSopenharmony_ci * 72f9f848faSopenharmony_ci * - probe/attach/detach 73f9f848faSopenharmony_ci * - generic transfer routines 74f9f848faSopenharmony_ci * - BBB 75f9f848faSopenharmony_ci * - CBI 76f9f848faSopenharmony_ci * - CBI_I (in addition to functions from CBI) 77f9f848faSopenharmony_ci * - CAM (Common Access Method) 78f9f848faSopenharmony_ci * - SCSI 79f9f848faSopenharmony_ci * - UFI 80f9f848faSopenharmony_ci * - 8070i (ATAPI) 81f9f848faSopenharmony_ci * 82f9f848faSopenharmony_ci * The protocols are implemented using a state machine, for the transfers as 83f9f848faSopenharmony_ci * well as for the resets. The state machine is contained in umass_t_*_callback. 84f9f848faSopenharmony_ci * The state machine is started through either umass_command_start() or 85f9f848faSopenharmony_ci * umass_reset(). 86f9f848faSopenharmony_ci * 87f9f848faSopenharmony_ci * The reason for doing this is a) CAM performs a lot better this way and b) it 88f9f848faSopenharmony_ci * avoids using tsleep from interrupt context (for example after a failed 89f9f848faSopenharmony_ci * transfer). 90f9f848faSopenharmony_ci */ 91f9f848faSopenharmony_ci 92f9f848faSopenharmony_ci/* 93f9f848faSopenharmony_ci * The SCSI related part of this driver has been derived from the 94f9f848faSopenharmony_ci * dev/ppbus/vpo.c driver, by Nicolas Souchu (nsouch@FreeBSD.org). 95f9f848faSopenharmony_ci * 96f9f848faSopenharmony_ci * The CAM layer uses so called actions which are messages sent to the host 97f9f848faSopenharmony_ci * adapter for completion. The actions come in through umass_cam_action. The 98f9f848faSopenharmony_ci * appropriate block of routines is called depending on the transport protocol 99f9f848faSopenharmony_ci * in use. When the transfer has finished, these routines call 100f9f848faSopenharmony_ci * umass_cam_cb again to complete the CAM command. 101f9f848faSopenharmony_ci */ 102f9f848faSopenharmony_ci 103f9f848faSopenharmony_ci#include <driver.h> 104f9f848faSopenharmony_ci#include <disk.h> 105f9f848faSopenharmony_ci 106f9f848faSopenharmony_ci#include "implementation/global_implementation.h" 107f9f848faSopenharmony_ci#include "scsi_all.h" 108f9f848faSopenharmony_ci#include "scsi.h" 109f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 110f9f848faSopenharmony_ci#include "implementation/usb_btree.h" 111f9f848faSopenharmony_ci#endif 112f9f848faSopenharmony_ci#include "user_copy.h" 113f9f848faSopenharmony_ci 114f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 115f9f848faSopenharmony_ci#define DIF(m, x) \ 116f9f848faSopenharmony_ci do { \ 117f9f848faSopenharmony_ci if (umass_debug & (m)) { x ; } \ 118f9f848faSopenharmony_ci } while (0) 119f9f848faSopenharmony_ci 120f9f848faSopenharmony_ci#define DPRINTF_UMASS(sc, m, fmt, ...) \ 121f9f848faSopenharmony_ci do { \ 122f9f848faSopenharmony_ci if (umass_debug & (m)) { \ 123f9f848faSopenharmony_ci PRINTK("%s:%s: " fmt, \ 124f9f848faSopenharmony_ci (sc) ? (const char *)(sc)->sc_name : \ 125f9f848faSopenharmony_ci (const char *)"umassX", \ 126f9f848faSopenharmony_ci __FUNCTION__ ,## __VA_ARGS__); \ 127f9f848faSopenharmony_ci } \ 128f9f848faSopenharmony_ci } while (0) 129f9f848faSopenharmony_ci 130f9f848faSopenharmony_ci#define UDMASS_GEN 0x00010000 /* general */ 131f9f848faSopenharmony_ci#define UDMASS_SCSI 0x00020000 /* scsi */ 132f9f848faSopenharmony_ci#define UDMASS_UFI 0x00040000 /* ufi command set */ 133f9f848faSopenharmony_ci#define UDMASS_ATAPI 0x00080000 /* 8070i command set */ 134f9f848faSopenharmony_ci#define UDMASS_CMD (UDMASS_SCSI|UDMASS_UFI|UDMASS_ATAPI) 135f9f848faSopenharmony_ci#define UDMASS_USB 0x00100000 /* USB general */ 136f9f848faSopenharmony_ci#define UDMASS_BBB 0x00200000 /* Bulk-Only transfers */ 137f9f848faSopenharmony_ci#define UDMASS_CBI 0x00400000 /* CBI transfers */ 138f9f848faSopenharmony_ci#define UDMASS_WIRE (UDMASS_BBB|UDMASS_CBI) 139f9f848faSopenharmony_ci#define UDMASS_ALL 0xffff0000 /* all of the above */ 140f9f848faSopenharmony_cistatic int umass_debug = 0; /* UDMASS_ALL; */ 141f9f848faSopenharmony_cistatic int umass_throttle; 142f9f848faSopenharmony_ci 143f9f848faSopenharmony_civoid 144f9f848faSopenharmony_ciumass_debug_func(int level) 145f9f848faSopenharmony_ci{ 146f9f848faSopenharmony_ci switch(level) { 147f9f848faSopenharmony_ci case 0: 148f9f848faSopenharmony_ci umass_debug = 0; 149f9f848faSopenharmony_ci PRINTK("Close the umass debug\n"); 150f9f848faSopenharmony_ci break; 151f9f848faSopenharmony_ci case UDMASS_GEN: 152f9f848faSopenharmony_ci case UDMASS_SCSI: 153f9f848faSopenharmony_ci case UDMASS_UFI: 154f9f848faSopenharmony_ci case UDMASS_ATAPI: 155f9f848faSopenharmony_ci case UDMASS_CMD: 156f9f848faSopenharmony_ci case UDMASS_USB: 157f9f848faSopenharmony_ci case UDMASS_BBB: 158f9f848faSopenharmony_ci case UDMASS_CBI: 159f9f848faSopenharmony_ci case UDMASS_WIRE: 160f9f848faSopenharmony_ci case UDMASS_ALL: 161f9f848faSopenharmony_ci umass_debug = level; 162f9f848faSopenharmony_ci PRINTK("The level of umass debug is %x\n", level); 163f9f848faSopenharmony_ci break; 164f9f848faSopenharmony_ci default: 165f9f848faSopenharmony_ci PRINT_ERR("The level of umass debug is invalid, please refer to umass.c\n"); 166f9f848faSopenharmony_ci break; 167f9f848faSopenharmony_ci } 168f9f848faSopenharmony_ci} 169f9f848faSopenharmony_ciDEBUG_MODULE(umass, umass_debug_func); 170f9f848faSopenharmony_ci#else 171f9f848faSopenharmony_ci#define DIF(...) do { } while (0) 172f9f848faSopenharmony_ci#define DPRINTF_UMASS(...) do { } while (0) 173f9f848faSopenharmony_ci#endif 174f9f848faSopenharmony_ci 175f9f848faSopenharmony_ci#define UMASS_BULK_SIZE (1 << 17) 176f9f848faSopenharmony_ci#define UMASS_CBI_DIAGNOSTIC_CMDLEN 12 /* bytes */ 177f9f848faSopenharmony_ci#define UMASS_MAX_CMDLEN MAX(12, CBWCDBLENGTH) /* bytes */ 178f9f848faSopenharmony_ci 179f9f848faSopenharmony_ci/* USB transfer definitions */ 180f9f848faSopenharmony_ci 181f9f848faSopenharmony_ci#define UMASS_T_BBB_RESET1 0 /* Bulk-Only */ 182f9f848faSopenharmony_ci#define UMASS_T_BBB_RESET2 1 183f9f848faSopenharmony_ci#define UMASS_T_BBB_RESET3 2 184f9f848faSopenharmony_ci#define UMASS_T_BBB_COMMAND 3 185f9f848faSopenharmony_ci#define UMASS_T_BBB_DATA_READ 4 186f9f848faSopenharmony_ci#define UMASS_T_BBB_DATA_RD_CS 5 187f9f848faSopenharmony_ci#define UMASS_T_BBB_DATA_WRITE 6 188f9f848faSopenharmony_ci#define UMASS_T_BBB_DATA_WR_CS 7 189f9f848faSopenharmony_ci#define UMASS_T_BBB_STATUS 8 190f9f848faSopenharmony_ci#define UMASS_T_BBB_MAX 9 191f9f848faSopenharmony_ci 192f9f848faSopenharmony_ci#define UMASS_T_CBI_RESET1 0 /* CBI */ 193f9f848faSopenharmony_ci#define UMASS_T_CBI_RESET2 1 194f9f848faSopenharmony_ci#define UMASS_T_CBI_RESET3 2 195f9f848faSopenharmony_ci#define UMASS_T_CBI_COMMAND 3 196f9f848faSopenharmony_ci#define UMASS_T_CBI_DATA_READ 4 197f9f848faSopenharmony_ci#define UMASS_T_CBI_DATA_RD_CS 5 198f9f848faSopenharmony_ci#define UMASS_T_CBI_DATA_WRITE 6 199f9f848faSopenharmony_ci#define UMASS_T_CBI_DATA_WR_CS 7 200f9f848faSopenharmony_ci#define UMASS_T_CBI_STATUS 8 201f9f848faSopenharmony_ci#define UMASS_T_CBI_RESET4 9 202f9f848faSopenharmony_ci#define UMASS_T_CBI_MAX 10 203f9f848faSopenharmony_ci 204f9f848faSopenharmony_ci#define UMASS_T_MAX MAX(UMASS_T_CBI_MAX, UMASS_T_BBB_MAX) 205f9f848faSopenharmony_ci 206f9f848faSopenharmony_ci/* Generic definitions */ 207f9f848faSopenharmony_ci 208f9f848faSopenharmony_ci/* Direction for transfer */ 209f9f848faSopenharmony_ci#define DIR_NONE 0 210f9f848faSopenharmony_ci#define DIR_IN 1 211f9f848faSopenharmony_ci#define DIR_OUT 2 212f9f848faSopenharmony_ci 213f9f848faSopenharmony_ci/* device name */ 214f9f848faSopenharmony_ci#define DEVNAME "umass" 215f9f848faSopenharmony_ci#define DEVNAME_SIM "umass-sim" 216f9f848faSopenharmony_ci 217f9f848faSopenharmony_ci/* Approximate maximum transfer speeds (assumes 33% overhead). */ 218f9f848faSopenharmony_ci#define UMASS_FULL_TRANSFER_SPEED 1000 219f9f848faSopenharmony_ci#define UMASS_HIGH_TRANSFER_SPEED 40000 220f9f848faSopenharmony_ci#define UMASS_SUPER_TRANSFER_SPEED 400000 221f9f848faSopenharmony_ci#define UMASS_FLOPPY_TRANSFER_SPEED 20 222f9f848faSopenharmony_ci 223f9f848faSopenharmony_ci#define UMASS_TIMEOUT 20000 /* ms */ 224f9f848faSopenharmony_ci 225f9f848faSopenharmony_ci/* CAM specific definitions */ 226f9f848faSopenharmony_ci#define UMASS_SCSIID_MAX 1 /* maximum number of drives expected */ 227f9f848faSopenharmony_ci#define UMASS_SCSIID_HOST UMASS_SCSIID_MAX 228f9f848faSopenharmony_ci 229f9f848faSopenharmony_ci/* Bulk-Only features */ 230f9f848faSopenharmony_ci#define UR_BBB_RESET 0xff /* Bulk-Only reset */ 231f9f848faSopenharmony_ci#define UR_BBB_GET_MAX_LUN 0xfe /* Get maximum lun */ 232f9f848faSopenharmony_ci 233f9f848faSopenharmony_ci#define UMASS_ATTACH_PRENAME "/dev/sd" 234f9f848faSopenharmony_ci#define MASS_NAME 10 235f9f848faSopenharmony_ci#define MAX_DEVICE 5 236f9f848faSopenharmony_ci 237f9f848faSopenharmony_ci/* 238f9f848faSopenharmony_ci * SCSI I/O Request CCB used for the XPT_SCSI_IO and XPT_CONT_TARGET_IO 239f9f848faSopenharmony_ci * function codes. 240f9f848faSopenharmony_ci */ 241f9f848faSopenharmony_cistruct ccb_scsiio { 242f9f848faSopenharmony_ci uint8_t *data_ptr; /* Ptr to the data buf/SG list */ 243f9f848faSopenharmony_ci uint32_t dxfer_len; /* Data transfer length */ 244f9f848faSopenharmony_ci uint32_t resid; /* Transfer residual length: 2's comp */ 245f9f848faSopenharmony_ci int32_t status; 246f9f848faSopenharmony_ci 247f9f848faSopenharmony_ci struct scsi_sense_data sense_data; 248f9f848faSopenharmony_ci uint8_t sense_len; /* Number of bytes to autosense */ 249f9f848faSopenharmony_ci}; 250f9f848faSopenharmony_ci 251f9f848faSopenharmony_ciunion ccb { 252f9f848faSopenharmony_ci struct ccb_scsiio csio; 253f9f848faSopenharmony_ci}; 254f9f848faSopenharmony_ci 255f9f848faSopenharmony_ci 256f9f848faSopenharmony_ci/* Command Block Wrapper */ 257f9f848faSopenharmony_citypedef struct { 258f9f848faSopenharmony_ci uDWord dCBWSignature; 259f9f848faSopenharmony_ci#define CBWSIGNATURE 0x43425355 260f9f848faSopenharmony_ci uDWord dCBWTag; 261f9f848faSopenharmony_ci uDWord dCBWDataTransferLength; 262f9f848faSopenharmony_ci uByte bCBWFlags; 263f9f848faSopenharmony_ci#define CBWFLAGS_OUT 0x00 264f9f848faSopenharmony_ci#define CBWFLAGS_IN 0x80 265f9f848faSopenharmony_ci uByte bCBWLUN; 266f9f848faSopenharmony_ci uByte bCDBLength; 267f9f848faSopenharmony_ci#define CBWCDBLENGTH 16 268f9f848faSopenharmony_ci uByte CBWCDB[CBWCDBLENGTH]; 269f9f848faSopenharmony_ci} __packed umass_bbb_cbw_t; 270f9f848faSopenharmony_ci 271f9f848faSopenharmony_ci#define UMASS_BBB_CBW_SIZE 31 272f9f848faSopenharmony_ci 273f9f848faSopenharmony_ci/* Command Status Wrapper */ 274f9f848faSopenharmony_citypedef struct { 275f9f848faSopenharmony_ci uDWord dCSWSignature; 276f9f848faSopenharmony_ci#define CSWSIGNATURE 0x53425355 277f9f848faSopenharmony_ci#define CSWSIGNATURE_IMAGINATION_DBX1 0x43425355 278f9f848faSopenharmony_ci#define CSWSIGNATURE_OLYMPUS_C1 0x55425355 279f9f848faSopenharmony_ci uDWord dCSWTag; 280f9f848faSopenharmony_ci uDWord dCSWDataResidue; 281f9f848faSopenharmony_ci uByte bCSWStatus; 282f9f848faSopenharmony_ci#define CSWSTATUS_GOOD 0x0 283f9f848faSopenharmony_ci#define CSWSTATUS_FAILED 0x1 284f9f848faSopenharmony_ci#define CSWSTATUS_PHASE 0x2 285f9f848faSopenharmony_ci} __packed umass_bbb_csw_t; 286f9f848faSopenharmony_ci 287f9f848faSopenharmony_ci#define UMASS_BBB_CSW_SIZE 13 288f9f848faSopenharmony_ci 289f9f848faSopenharmony_ci/* CBI features */ 290f9f848faSopenharmony_ci 291f9f848faSopenharmony_ci#define UR_CBI_ADSC 0x00 292f9f848faSopenharmony_ci 293f9f848faSopenharmony_citypedef union { 294f9f848faSopenharmony_ci struct { 295f9f848faSopenharmony_ci uint8_t type; 296f9f848faSopenharmony_ci#define IDB_TYPE_CCI 0x00 297f9f848faSopenharmony_ci uint8_t value; 298f9f848faSopenharmony_ci#define IDB_VALUE_PASS 0x00 299f9f848faSopenharmony_ci#define IDB_VALUE_FAIL 0x01 300f9f848faSopenharmony_ci#define IDB_VALUE_PHASE 0x02 301f9f848faSopenharmony_ci#define IDB_VALUE_PERSISTENT 0x03 302f9f848faSopenharmony_ci#define IDB_VALUE_STATUS_MASK 0x03 303f9f848faSopenharmony_ci } __packed common; 304f9f848faSopenharmony_ci 305f9f848faSopenharmony_ci struct { 306f9f848faSopenharmony_ci uint8_t asc; 307f9f848faSopenharmony_ci uint8_t ascq; 308f9f848faSopenharmony_ci } __packed ufi; 309f9f848faSopenharmony_ci} __packed umass_cbi_sbl_t; 310f9f848faSopenharmony_ci 311f9f848faSopenharmony_cistruct umass_info { 312f9f848faSopenharmony_ci uint32_t sectorsize; 313f9f848faSopenharmony_ci uint64_t sectornum; 314f9f848faSopenharmony_ci}; 315f9f848faSopenharmony_ci 316f9f848faSopenharmony_cistruct umass_softc; /* see below */ 317f9f848faSopenharmony_ci 318f9f848faSopenharmony_citypedef void (umass_callback_t)(struct umass_softc *sc, union ccb *ccb, 319f9f848faSopenharmony_ci uint32_t residue, uint8_t status); 320f9f848faSopenharmony_ci 321f9f848faSopenharmony_ci#define STATUS_CMD_OK 0 /* everything ok */ 322f9f848faSopenharmony_ci#define STATUS_CMD_UNKNOWN 1 /* will have to fetch sense */ 323f9f848faSopenharmony_ci#define STATUS_CMD_FAILED 2 /* transfer was ok, command failed */ 324f9f848faSopenharmony_ci#define STATUS_WIRE_FAILED 3 /* couldn't even get command across */ 325f9f848faSopenharmony_ci 326f9f848faSopenharmony_citypedef uint8_t (umass_transform_t)(struct umass_softc *sc, uint8_t *cmd_ptr, 327f9f848faSopenharmony_ci uint8_t cmd_len); 328f9f848faSopenharmony_ci 329f9f848faSopenharmony_ci/* Wire and command protocol */ 330f9f848faSopenharmony_ci#define UMASS_PROTO_BBB 0x0001 /* USB wire protocol */ 331f9f848faSopenharmony_ci#define UMASS_PROTO_CBI 0x0002 332f9f848faSopenharmony_ci#define UMASS_PROTO_CBI_I 0x0004 333f9f848faSopenharmony_ci#define UMASS_PROTO_WIRE 0x00ff /* USB wire protocol mask */ 334f9f848faSopenharmony_ci#define UMASS_PROTO_SCSI 0x0100 /* command protocol */ 335f9f848faSopenharmony_ci#define UMASS_PROTO_ATAPI 0x0200 336f9f848faSopenharmony_ci#define UMASS_PROTO_UFI 0x0400 337f9f848faSopenharmony_ci#define UMASS_PROTO_RBC 0x0800 338f9f848faSopenharmony_ci#define UMASS_PROTO_COMMAND 0xff00 /* command protocol mask */ 339f9f848faSopenharmony_ci 340f9f848faSopenharmony_ci/* Device specific quirks */ 341f9f848faSopenharmony_ci#define NO_QUIRKS 0x0000 342f9f848faSopenharmony_ci /* 343f9f848faSopenharmony_ci * The drive does not support Test Unit Ready. Convert to Start Unit 344f9f848faSopenharmony_ci */ 345f9f848faSopenharmony_ci#define NO_TEST_UNIT_READY 0x0001 346f9f848faSopenharmony_ci /* 347f9f848faSopenharmony_ci * The drive does not reset the Unit Attention state after REQUEST 348f9f848faSopenharmony_ci * SENSE has been sent. The INQUIRY command does not reset the UA 349f9f848faSopenharmony_ci * either, and so CAM runs in circles trying to retrieve the initial 350f9f848faSopenharmony_ci * INQUIRY data. 351f9f848faSopenharmony_ci */ 352f9f848faSopenharmony_ci#define RS_NO_CLEAR_UA 0x0002 353f9f848faSopenharmony_ci /* The drive does not support START STOP. */ 354f9f848faSopenharmony_ci#define NO_START_STOP 0x0004 355f9f848faSopenharmony_ci /* Don't ask for full inquiry data (255b). */ 356f9f848faSopenharmony_ci#define FORCE_SHORT_INQUIRY 0x0008 357f9f848faSopenharmony_ci /* Needs to be initialised the Shuttle way */ 358f9f848faSopenharmony_ci#define SHUTTLE_INIT 0x0010 359f9f848faSopenharmony_ci /* Drive needs to be switched to alternate iface 1 */ 360f9f848faSopenharmony_ci#define ALT_IFACE_1 0x0020 361f9f848faSopenharmony_ci /* Drive does not do 1Mb/s, but just floppy speeds (20kb/s) */ 362f9f848faSopenharmony_ci#define FLOPPY_SPEED 0x0040 363f9f848faSopenharmony_ci /* The device can't count and gets the residue of transfers wrong */ 364f9f848faSopenharmony_ci#define IGNORE_RESIDUE 0x0080 365f9f848faSopenharmony_ci /* No GetMaxLun call */ 366f9f848faSopenharmony_ci#define NO_GETMAXLUN 0x0100 367f9f848faSopenharmony_ci /* The device uses a weird CSWSIGNATURE. */ 368f9f848faSopenharmony_ci#define WRONG_CSWSIG 0x0200 369f9f848faSopenharmony_ci /* Device cannot handle INQUIRY so fake a generic response */ 370f9f848faSopenharmony_ci#define NO_INQUIRY 0x0400 371f9f848faSopenharmony_ci /* Device cannot handle INQUIRY EVPD, return CHECK CONDITION */ 372f9f848faSopenharmony_ci#define NO_INQUIRY_EVPD 0x0800 373f9f848faSopenharmony_ci /* Pad all RBC requests to 12 bytes. */ 374f9f848faSopenharmony_ci#define RBC_PAD_TO_12 0x1000 375f9f848faSopenharmony_ci /* 376f9f848faSopenharmony_ci * Device reports number of sectors from READ_CAPACITY, not max 377f9f848faSopenharmony_ci * sector number. 378f9f848faSopenharmony_ci */ 379f9f848faSopenharmony_ci#define READ_CAPACITY_OFFBY1 0x2000 380f9f848faSopenharmony_ci /* 381f9f848faSopenharmony_ci * Device cannot handle a SCSI synchronize cache command. Normally 382f9f848faSopenharmony_ci * this quirk would be handled in the cam layer, but for IDE bridges 383f9f848faSopenharmony_ci * we need to associate the quirk with the bridge and not the 384f9f848faSopenharmony_ci * underlying disk device. This is handled by faking a success 385f9f848faSopenharmony_ci * result. 386f9f848faSopenharmony_ci */ 387f9f848faSopenharmony_ci#define NO_SYNCHRONIZE_CACHE 0x4000 388f9f848faSopenharmony_ci /* Device does not support 'PREVENT/ALLOW MEDIUM REMOVAL'. */ 389f9f848faSopenharmony_ci#define NO_PREVENT_ALLOW 0x8000 390f9f848faSopenharmony_ci 391f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 392f9f848faSopenharmony_ciextern usbd_bt_tree hub_tree; 393f9f848faSopenharmony_ci#endif 394f9f848faSopenharmony_ci 395f9f848faSopenharmony_cistruct umass_softc { 396f9f848faSopenharmony_ci union ccb *data_ccb; 397f9f848faSopenharmony_ci struct scsi_sense cam_scsi_sense; 398f9f848faSopenharmony_ci struct scsi_test_unit_ready cam_scsi_test_unit_ready; 399f9f848faSopenharmony_ci struct mtx sc_mtx; 400f9f848faSopenharmony_ci EVENT_CB_S sc_event; 401f9f848faSopenharmony_ci struct { 402f9f848faSopenharmony_ci uint8_t *data_ptr; 403f9f848faSopenharmony_ci union ccb *ccb; 404f9f848faSopenharmony_ci umass_callback_t *callback; 405f9f848faSopenharmony_ci 406f9f848faSopenharmony_ci uint32_t data_len; /* bytes */ 407f9f848faSopenharmony_ci uint32_t data_rem; /* bytes */ 408f9f848faSopenharmony_ci uint32_t data_timeout; /* ms */ 409f9f848faSopenharmony_ci uint32_t actlen; /* bytes */ 410f9f848faSopenharmony_ci 411f9f848faSopenharmony_ci uint8_t cmd_data[UMASS_MAX_CMDLEN]; 412f9f848faSopenharmony_ci uint8_t cmd_len; /* bytes */ 413f9f848faSopenharmony_ci uint8_t dir; 414f9f848faSopenharmony_ci uint8_t lun; 415f9f848faSopenharmony_ci } sc_transfer; 416f9f848faSopenharmony_ci 417f9f848faSopenharmony_ci struct umass_info info; 418f9f848faSopenharmony_ci 419f9f848faSopenharmony_ci /* Bulk specific variables for transfers in progress */ 420f9f848faSopenharmony_ci umass_bbb_cbw_t cbw; /* command block wrapper */ 421f9f848faSopenharmony_ci umass_bbb_csw_t csw; /* command status wrapper */ 422f9f848faSopenharmony_ci 423f9f848faSopenharmony_ci /* CBI specific variables for transfers in progress */ 424f9f848faSopenharmony_ci umass_cbi_sbl_t sbl; /* status block */ 425f9f848faSopenharmony_ci 426f9f848faSopenharmony_ci device_t sc_dev; 427f9f848faSopenharmony_ci struct usb_device *sc_udev; 428f9f848faSopenharmony_ci struct usb_xfer *sc_xfer[UMASS_T_MAX]; 429f9f848faSopenharmony_ci 430f9f848faSopenharmony_ci /* 431f9f848faSopenharmony_ci * The command transform function is used to convert the SCSI 432f9f848faSopenharmony_ci * commands into their derivatives, like UFI, ATAPI, and friends. 433f9f848faSopenharmony_ci */ 434f9f848faSopenharmony_ci umass_transform_t *sc_transform; 435f9f848faSopenharmony_ci 436f9f848faSopenharmony_ci uint32_t sc_unit; 437f9f848faSopenharmony_ci uint32_t sc_quirks; /* they got it almost right */ 438f9f848faSopenharmony_ci uint32_t sc_proto; /* wire and cmd protocol */ 439f9f848faSopenharmony_ci 440f9f848faSopenharmony_ci uint8_t sc_name[16]; 441f9f848faSopenharmony_ci uint8_t sc_iface_no; /* interface number */ 442f9f848faSopenharmony_ci uint8_t sc_maxlun; /* maximum LUN number, inclusive */ 443f9f848faSopenharmony_ci uint8_t sc_last_xfer_index; 444f9f848faSopenharmony_ci uint8_t sc_status_try; 445f9f848faSopenharmony_ci BOOL sc_detach_status; 446f9f848faSopenharmony_ci BOOL sc_super_disk; /* TRUE: Disk is bigger than 2T; FALSE: Disk is less than 2T */ 447f9f848faSopenharmony_ci struct mtx sc_umass_mtx; /* The mtx is used to prevent data read and write competition */ 448f9f848faSopenharmony_ci}; 449f9f848faSopenharmony_ci 450f9f848faSopenharmony_cistruct umass_probe_proto { 451f9f848faSopenharmony_ci uint32_t quirks; 452f9f848faSopenharmony_ci uint32_t proto; 453f9f848faSopenharmony_ci 454f9f848faSopenharmony_ci int error; 455f9f848faSopenharmony_ci}; 456f9f848faSopenharmony_ci 457f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 458f9f848faSopenharmony_cistruct umass_dev_info { 459f9f848faSopenharmony_ci struct umass_softc *sc; 460f9f848faSopenharmony_ci unsigned int dev_unit; 461f9f848faSopenharmony_ci int used; /* 0: not use; 1: in use */ 462f9f848faSopenharmony_ci int attached; /* 0: not attach; 1: in attach */ 463f9f848faSopenharmony_ci struct mtx dev_mtx; /* The mtx is used to prevent U disk insertion or extraction competition */ 464f9f848faSopenharmony_ci}; 465f9f848faSopenharmony_ci 466f9f848faSopenharmony_cistatic struct umass_dev_info g_umass_dev_array[MAX_DEVICE] = {0}; 467f9f848faSopenharmony_cistatic void umass_task_check(int flag); 468f9f848faSopenharmony_cistatic void umass_dev_delete(struct umass_softc *sc, unsigned int dev_unit); 469f9f848faSopenharmony_ciint umass_dev_is_attached(unsigned int dev_unit); 470f9f848faSopenharmony_cistatic void umass_dev_attach_flag_set(int dev_unit); 471f9f848faSopenharmony_cipthread_t umass_taskid; 472f9f848faSopenharmony_ci#define umass_dev_mtx_init(id, type) (void)mtx_init(&g_umass_dev_array[id].dev_mtx, NULL, NULL, type) 473f9f848faSopenharmony_ci#define umass_dev_mtx_destroy(id) (void)mtx_destroy(&g_umass_dev_array[id].dev_mtx) 474f9f848faSopenharmony_ci#define umass_dev_lock(id) (void)mtx_lock(&g_umass_dev_array[id].dev_mtx) 475f9f848faSopenharmony_ci#define umass_dev_unlock(id) (void)mtx_unlock(&g_umass_dev_array[id].dev_mtx) 476f9f848faSopenharmony_ci#else 477f9f848faSopenharmony_ci#define umass_dev_lock(id) (void)mtx_lock(NULL) 478f9f848faSopenharmony_ci#define umass_dev_unlock(id) (void)mtx_unlock(NULL) 479f9f848faSopenharmony_ci#endif 480f9f848faSopenharmony_ci 481f9f848faSopenharmony_cistruct umass_softc *p_umsf = NULL; 482f9f848faSopenharmony_ci/* prototypes */ 483f9f848faSopenharmony_ci 484f9f848faSopenharmony_cistatic device_probe_t umass_probe; 485f9f848faSopenharmony_cistatic device_attach_t umass_attach; 486f9f848faSopenharmony_cistatic device_detach_t umass_detach; 487f9f848faSopenharmony_ci 488f9f848faSopenharmony_cistatic usb_callback_t umass_tr_error; 489f9f848faSopenharmony_cistatic usb_callback_t umass_t_bbb_reset1_callback; 490f9f848faSopenharmony_cistatic usb_callback_t umass_t_bbb_reset2_callback; 491f9f848faSopenharmony_cistatic usb_callback_t umass_t_bbb_reset3_callback; 492f9f848faSopenharmony_cistatic usb_callback_t umass_t_bbb_command_callback; 493f9f848faSopenharmony_cistatic usb_callback_t umass_t_bbb_data_read_callback; 494f9f848faSopenharmony_cistatic usb_callback_t umass_t_bbb_data_rd_cs_callback; 495f9f848faSopenharmony_cistatic usb_callback_t umass_t_bbb_data_write_callback; 496f9f848faSopenharmony_cistatic usb_callback_t umass_t_bbb_data_wr_cs_callback; 497f9f848faSopenharmony_cistatic usb_callback_t umass_t_bbb_status_callback; 498f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_reset1_callback; 499f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_reset2_callback; 500f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_reset3_callback; 501f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_reset4_callback; 502f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_command_callback; 503f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_data_read_callback; 504f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_data_rd_cs_callback; 505f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_data_write_callback; 506f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_data_wr_cs_callback; 507f9f848faSopenharmony_cistatic usb_callback_t umass_t_cbi_status_callback; 508f9f848faSopenharmony_ci 509f9f848faSopenharmony_cistatic void umass_cancel_ccb(struct umass_softc *); 510f9f848faSopenharmony_cistatic void umass_init_shuttle(struct umass_softc *); 511f9f848faSopenharmony_cistatic void umass_t_bbb_data_clear_stall_callback(struct usb_xfer *, 512f9f848faSopenharmony_ci uint8_t, uint8_t, usb_error_t); 513f9f848faSopenharmony_cistatic int umass_command_start(struct umass_softc *, uint8_t, void *, 514f9f848faSopenharmony_ci uint32_t, uint32_t, umass_callback_t *, union ccb *); 515f9f848faSopenharmony_cistatic uint8_t umass_bbb_get_max_lun(struct umass_softc *); 516f9f848faSopenharmony_cistatic void umass_cbi_start_status(struct umass_softc *); 517f9f848faSopenharmony_cistatic void umass_t_cbi_data_clear_stall_callback(struct usb_xfer *, 518f9f848faSopenharmony_ci uint8_t, uint8_t, usb_error_t); 519f9f848faSopenharmony_cistatic void umass_cam_cb(struct umass_softc *, union ccb *, uint32_t, uint8_t); 520f9f848faSopenharmony_cistatic uint8_t umass_scsi_transform(struct umass_softc *, uint8_t *, uint8_t); 521f9f848faSopenharmony_cistatic uint8_t umass_rbc_transform(struct umass_softc *, uint8_t *, uint8_t); 522f9f848faSopenharmony_cistatic uint8_t umass_ufi_transform(struct umass_softc *, uint8_t *, uint8_t); 523f9f848faSopenharmony_cistatic uint8_t umass_atapi_transform(struct umass_softc *, uint8_t *, 524f9f848faSopenharmony_ci uint8_t); 525f9f848faSopenharmony_cistatic uint8_t umass_no_transform(struct umass_softc *, uint8_t *, uint8_t); 526f9f848faSopenharmony_ci 527f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 528f9f848faSopenharmony_cistatic void umass_bbb_dump_cbw(struct umass_softc *, umass_bbb_cbw_t *); 529f9f848faSopenharmony_cistatic void umass_bbb_dump_csw(struct umass_softc *, umass_bbb_csw_t *); 530f9f848faSopenharmony_cistatic void umass_cbi_dump_cmd(struct umass_softc *, void *, uint8_t); 531f9f848faSopenharmony_ci#endif 532f9f848faSopenharmony_ci 533f9f848faSopenharmony_cistatic void devunit_to_devname(unsigned int dev_unit, char *devname); 534f9f848faSopenharmony_cistatic int32_t umass_attach_dev(struct umass_softc *sc, unsigned int dev_unit); 535f9f848faSopenharmony_cistatic void umass_detach_dev_sub(struct umass_softc *sc, int dev_unit, int flag); 536f9f848faSopenharmony_ci 537f9f848faSopenharmony_cistatic struct usb_config umass_bbb_config[UMASS_T_BBB_MAX] = { 538f9f848faSopenharmony_ci [UMASS_T_BBB_RESET1] = { 539f9f848faSopenharmony_ci .type = UE_CONTROL, 540f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 541f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 542f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 543f9f848faSopenharmony_ci .callback = &umass_t_bbb_reset1_callback, 544f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 545f9f848faSopenharmony_ci .interval = 500, /* 500 milliseconds */ 546f9f848faSopenharmony_ci }, 547f9f848faSopenharmony_ci 548f9f848faSopenharmony_ci [UMASS_T_BBB_RESET2] = { 549f9f848faSopenharmony_ci .type = UE_CONTROL, 550f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 551f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 552f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 553f9f848faSopenharmony_ci .callback = &umass_t_bbb_reset2_callback, 554f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 555f9f848faSopenharmony_ci .interval = 50, /* 50 milliseconds */ 556f9f848faSopenharmony_ci }, 557f9f848faSopenharmony_ci 558f9f848faSopenharmony_ci [UMASS_T_BBB_RESET3] = { 559f9f848faSopenharmony_ci .type = UE_CONTROL, 560f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 561f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 562f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 563f9f848faSopenharmony_ci .callback = &umass_t_bbb_reset3_callback, 564f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 565f9f848faSopenharmony_ci .interval = 50, /* 50 milliseconds */ 566f9f848faSopenharmony_ci }, 567f9f848faSopenharmony_ci 568f9f848faSopenharmony_ci [UMASS_T_BBB_COMMAND] = { 569f9f848faSopenharmony_ci .type = UE_BULK, 570f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 571f9f848faSopenharmony_ci .direction = UE_DIR_OUT, 572f9f848faSopenharmony_ci .bufsize = sizeof(umass_bbb_cbw_t), 573f9f848faSopenharmony_ci .callback = &umass_t_bbb_command_callback, 574f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 575f9f848faSopenharmony_ci }, 576f9f848faSopenharmony_ci 577f9f848faSopenharmony_ci [UMASS_T_BBB_DATA_READ] = { 578f9f848faSopenharmony_ci .type = UE_BULK, 579f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 580f9f848faSopenharmony_ci .direction = UE_DIR_IN, 581f9f848faSopenharmony_ci .bufsize = UMASS_BULK_SIZE, 582f9f848faSopenharmony_ci .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,}, 583f9f848faSopenharmony_ci .callback = &umass_t_bbb_data_read_callback, 584f9f848faSopenharmony_ci .timeout = 0, /* overwritten later */ 585f9f848faSopenharmony_ci }, 586f9f848faSopenharmony_ci 587f9f848faSopenharmony_ci [UMASS_T_BBB_DATA_RD_CS] = { 588f9f848faSopenharmony_ci .type = UE_CONTROL, 589f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 590f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 591f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 592f9f848faSopenharmony_ci .callback = &umass_t_bbb_data_rd_cs_callback, 593f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 594f9f848faSopenharmony_ci }, 595f9f848faSopenharmony_ci 596f9f848faSopenharmony_ci [UMASS_T_BBB_DATA_WRITE] = { 597f9f848faSopenharmony_ci .type = UE_BULK, 598f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 599f9f848faSopenharmony_ci .direction = UE_DIR_OUT, 600f9f848faSopenharmony_ci .bufsize = UMASS_BULK_SIZE, 601f9f848faSopenharmony_ci .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,}, 602f9f848faSopenharmony_ci .callback = &umass_t_bbb_data_write_callback, 603f9f848faSopenharmony_ci .timeout = 0, /* overwritten later */ 604f9f848faSopenharmony_ci }, 605f9f848faSopenharmony_ci 606f9f848faSopenharmony_ci [UMASS_T_BBB_DATA_WR_CS] = { 607f9f848faSopenharmony_ci .type = UE_CONTROL, 608f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 609f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 610f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 611f9f848faSopenharmony_ci .callback = &umass_t_bbb_data_wr_cs_callback, 612f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 613f9f848faSopenharmony_ci }, 614f9f848faSopenharmony_ci 615f9f848faSopenharmony_ci [UMASS_T_BBB_STATUS] = { 616f9f848faSopenharmony_ci .type = UE_BULK, 617f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 618f9f848faSopenharmony_ci .direction = UE_DIR_IN, 619f9f848faSopenharmony_ci .bufsize = sizeof(umass_bbb_csw_t), 620f9f848faSopenharmony_ci .flags = {.short_xfer_ok = 1,}, 621f9f848faSopenharmony_ci .callback = &umass_t_bbb_status_callback, 622f9f848faSopenharmony_ci .timeout = 5000, /* ms */ 623f9f848faSopenharmony_ci }, 624f9f848faSopenharmony_ci}; 625f9f848faSopenharmony_ci 626f9f848faSopenharmony_cistatic struct usb_config umass_cbi_config[UMASS_T_CBI_MAX] = { 627f9f848faSopenharmony_ci [UMASS_T_CBI_RESET1] = { 628f9f848faSopenharmony_ci .type = UE_CONTROL, 629f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 630f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 631f9f848faSopenharmony_ci .bufsize = (sizeof(struct usb_device_request) + 632f9f848faSopenharmony_ci UMASS_CBI_DIAGNOSTIC_CMDLEN), 633f9f848faSopenharmony_ci .callback = &umass_t_cbi_reset1_callback, 634f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 635f9f848faSopenharmony_ci .interval = 500, /* 500 milliseconds */ 636f9f848faSopenharmony_ci }, 637f9f848faSopenharmony_ci 638f9f848faSopenharmony_ci [UMASS_T_CBI_RESET2] = { 639f9f848faSopenharmony_ci .type = UE_CONTROL, 640f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 641f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 642f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 643f9f848faSopenharmony_ci .callback = &umass_t_cbi_reset2_callback, 644f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 645f9f848faSopenharmony_ci .interval = 50, /* 50 milliseconds */ 646f9f848faSopenharmony_ci }, 647f9f848faSopenharmony_ci 648f9f848faSopenharmony_ci [UMASS_T_CBI_RESET3] = { 649f9f848faSopenharmony_ci .type = UE_CONTROL, 650f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 651f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 652f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 653f9f848faSopenharmony_ci .callback = &umass_t_cbi_reset3_callback, 654f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 655f9f848faSopenharmony_ci .interval = 50, /* 50 milliseconds */ 656f9f848faSopenharmony_ci }, 657f9f848faSopenharmony_ci 658f9f848faSopenharmony_ci [UMASS_T_CBI_COMMAND] = { 659f9f848faSopenharmony_ci .type = UE_CONTROL, 660f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 661f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 662f9f848faSopenharmony_ci .bufsize = (sizeof(struct usb_device_request) + 663f9f848faSopenharmony_ci UMASS_MAX_CMDLEN), 664f9f848faSopenharmony_ci .callback = &umass_t_cbi_command_callback, 665f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 666f9f848faSopenharmony_ci }, 667f9f848faSopenharmony_ci 668f9f848faSopenharmony_ci [UMASS_T_CBI_DATA_READ] = { 669f9f848faSopenharmony_ci .type = UE_BULK, 670f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 671f9f848faSopenharmony_ci .direction = UE_DIR_IN, 672f9f848faSopenharmony_ci .bufsize = UMASS_BULK_SIZE, 673f9f848faSopenharmony_ci .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,}, 674f9f848faSopenharmony_ci .callback = &umass_t_cbi_data_read_callback, 675f9f848faSopenharmony_ci .timeout = 0, /* overwritten later */ 676f9f848faSopenharmony_ci }, 677f9f848faSopenharmony_ci 678f9f848faSopenharmony_ci [UMASS_T_CBI_DATA_RD_CS] = { 679f9f848faSopenharmony_ci .type = UE_CONTROL, 680f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 681f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 682f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 683f9f848faSopenharmony_ci .callback = &umass_t_cbi_data_rd_cs_callback, 684f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 685f9f848faSopenharmony_ci }, 686f9f848faSopenharmony_ci 687f9f848faSopenharmony_ci [UMASS_T_CBI_DATA_WRITE] = { 688f9f848faSopenharmony_ci .type = UE_BULK, 689f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 690f9f848faSopenharmony_ci .direction = UE_DIR_OUT, 691f9f848faSopenharmony_ci .bufsize = UMASS_BULK_SIZE, 692f9f848faSopenharmony_ci .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer=1,}, 693f9f848faSopenharmony_ci .callback = &umass_t_cbi_data_write_callback, 694f9f848faSopenharmony_ci .timeout = 0, /* overwritten later */ 695f9f848faSopenharmony_ci }, 696f9f848faSopenharmony_ci 697f9f848faSopenharmony_ci [UMASS_T_CBI_DATA_WR_CS] = { 698f9f848faSopenharmony_ci .type = UE_CONTROL, 699f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 700f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 701f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 702f9f848faSopenharmony_ci .callback = &umass_t_cbi_data_wr_cs_callback, 703f9f848faSopenharmony_ci .timeout = 5000, /* 5 seconds */ 704f9f848faSopenharmony_ci }, 705f9f848faSopenharmony_ci 706f9f848faSopenharmony_ci [UMASS_T_CBI_STATUS] = { 707f9f848faSopenharmony_ci .type = UE_INTERRUPT, 708f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 709f9f848faSopenharmony_ci .direction = UE_DIR_IN, 710f9f848faSopenharmony_ci .flags = {.short_xfer_ok = 1,.no_pipe_ok = 1,}, 711f9f848faSopenharmony_ci .bufsize = sizeof(umass_cbi_sbl_t), 712f9f848faSopenharmony_ci .callback = &umass_t_cbi_status_callback, 713f9f848faSopenharmony_ci .timeout = 5000, /* ms */ 714f9f848faSopenharmony_ci }, 715f9f848faSopenharmony_ci 716f9f848faSopenharmony_ci [UMASS_T_CBI_RESET4] = { 717f9f848faSopenharmony_ci .type = UE_CONTROL, 718f9f848faSopenharmony_ci .endpoint = 0x00, /* Control pipe */ 719f9f848faSopenharmony_ci .direction = UE_DIR_ANY, 720f9f848faSopenharmony_ci .bufsize = sizeof(struct usb_device_request), 721f9f848faSopenharmony_ci .callback = &umass_t_cbi_reset4_callback, 722f9f848faSopenharmony_ci .timeout = 5000, /* ms */ 723f9f848faSopenharmony_ci }, 724f9f848faSopenharmony_ci}; 725f9f848faSopenharmony_ci 726f9f848faSopenharmony_ci#define UFI_COMMAND_LENGTH 12 /* UFI commands are always 12 bytes */ 727f9f848faSopenharmony_ci#define ATAPI_COMMAND_LENGTH 12 /* ATAPI commands are always 12 bytes */ 728f9f848faSopenharmony_ci 729f9f848faSopenharmony_cistatic devclass_t umass_devclass; 730f9f848faSopenharmony_ci 731f9f848faSopenharmony_cistatic device_method_t umass_methods[] = { 732f9f848faSopenharmony_ci /* Device interface */ 733f9f848faSopenharmony_ci DEVMETHOD(device_probe, umass_probe), 734f9f848faSopenharmony_ci DEVMETHOD(device_attach, umass_attach), 735f9f848faSopenharmony_ci DEVMETHOD(device_detach, umass_detach), 736f9f848faSopenharmony_ci 737f9f848faSopenharmony_ci DEVMETHOD_END 738f9f848faSopenharmony_ci}; 739f9f848faSopenharmony_ci 740f9f848faSopenharmony_cistatic driver_t umass_driver = { 741f9f848faSopenharmony_ci .name = "umass", 742f9f848faSopenharmony_ci .methods = umass_methods, 743f9f848faSopenharmony_ci .size = sizeof(struct umass_softc), 744f9f848faSopenharmony_ci}; 745f9f848faSopenharmony_ci 746f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 747f9f848faSopenharmony_ciUINT64 dev_quantity = 0; 748f9f848faSopenharmony_ci#endif 749f9f848faSopenharmony_ci 750f9f848faSopenharmony_ciDRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, NULL, 0); 751f9f848faSopenharmony_ci 752f9f848faSopenharmony_cistatic uint16_t 753f9f848faSopenharmony_ciumass_get_proto(struct usb_interface *iface) 754f9f848faSopenharmony_ci{ 755f9f848faSopenharmony_ci struct usb_interface_descriptor *id; 756f9f848faSopenharmony_ci uint16_t retval; 757f9f848faSopenharmony_ci 758f9f848faSopenharmony_ci retval = 0; 759f9f848faSopenharmony_ci 760f9f848faSopenharmony_ci /* Check for a standards compliant device */ 761f9f848faSopenharmony_ci id = usbd_get_interface_descriptor(iface); 762f9f848faSopenharmony_ci if ((id == NULL) || 763f9f848faSopenharmony_ci (id->bInterfaceClass != UICLASS_MASS)) { 764f9f848faSopenharmony_ci goto done; 765f9f848faSopenharmony_ci } 766f9f848faSopenharmony_ci switch (id->bInterfaceSubClass) { 767f9f848faSopenharmony_ci case UISUBCLASS_SCSI: 768f9f848faSopenharmony_ci retval |= UMASS_PROTO_SCSI; 769f9f848faSopenharmony_ci break; 770f9f848faSopenharmony_ci case UISUBCLASS_UFI: 771f9f848faSopenharmony_ci retval |= UMASS_PROTO_UFI; 772f9f848faSopenharmony_ci break; 773f9f848faSopenharmony_ci case UISUBCLASS_RBC: 774f9f848faSopenharmony_ci retval |= UMASS_PROTO_RBC; 775f9f848faSopenharmony_ci break; 776f9f848faSopenharmony_ci case UISUBCLASS_SFF8020I: 777f9f848faSopenharmony_ci case UISUBCLASS_SFF8070I: 778f9f848faSopenharmony_ci retval |= UMASS_PROTO_ATAPI; 779f9f848faSopenharmony_ci break; 780f9f848faSopenharmony_ci default: 781f9f848faSopenharmony_ci goto done; 782f9f848faSopenharmony_ci } 783f9f848faSopenharmony_ci 784f9f848faSopenharmony_ci switch (id->bInterfaceProtocol) { 785f9f848faSopenharmony_ci case UIPROTO_MASS_CBI: 786f9f848faSopenharmony_ci retval |= UMASS_PROTO_CBI; 787f9f848faSopenharmony_ci break; 788f9f848faSopenharmony_ci case UIPROTO_MASS_CBI_I: 789f9f848faSopenharmony_ci retval |= UMASS_PROTO_CBI_I; 790f9f848faSopenharmony_ci break; 791f9f848faSopenharmony_ci case UIPROTO_MASS_BBB_OLD: 792f9f848faSopenharmony_ci case UIPROTO_MASS_BBB: 793f9f848faSopenharmony_ci retval |= UMASS_PROTO_BBB; 794f9f848faSopenharmony_ci break; 795f9f848faSopenharmony_ci default: 796f9f848faSopenharmony_ci goto done; 797f9f848faSopenharmony_ci } 798f9f848faSopenharmony_cidone: 799f9f848faSopenharmony_ci return (retval); 800f9f848faSopenharmony_ci} 801f9f848faSopenharmony_ci 802f9f848faSopenharmony_ci/* 803f9f848faSopenharmony_ci * Match the device we are seeing with the devices supported. 804f9f848faSopenharmony_ci */ 805f9f848faSopenharmony_cistatic struct umass_probe_proto 806f9f848faSopenharmony_ciumass_probe_proto(device_t dev, struct usb_attach_arg *uaa) 807f9f848faSopenharmony_ci{ 808f9f848faSopenharmony_ci struct umass_probe_proto ret; 809f9f848faSopenharmony_ci uint32_t quirks = NO_QUIRKS; 810f9f848faSopenharmony_ci uint32_t proto = umass_get_proto(uaa->iface); 811f9f848faSopenharmony_ci 812f9f848faSopenharmony_ci (void)memset_s(&ret, sizeof(ret), 0, sizeof(ret)); 813f9f848faSopenharmony_ci ret.error = BUS_PROBE_GENERIC; 814f9f848faSopenharmony_ci 815f9f848faSopenharmony_ci /* Search for protocol enforcement */ 816f9f848faSopenharmony_ci 817f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_BBB)) { 818f9f848faSopenharmony_ci proto &= ~UMASS_PROTO_WIRE; 819f9f848faSopenharmony_ci proto |= UMASS_PROTO_BBB; 820f9f848faSopenharmony_ci } else if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_CBI)) { 821f9f848faSopenharmony_ci proto &= ~UMASS_PROTO_WIRE; 822f9f848faSopenharmony_ci proto |= UMASS_PROTO_CBI; 823f9f848faSopenharmony_ci } else if (usb_test_quirk(uaa, UQ_MSC_FORCE_WIRE_CBI_I)) { 824f9f848faSopenharmony_ci proto &= ~UMASS_PROTO_WIRE; 825f9f848faSopenharmony_ci proto |= UMASS_PROTO_CBI_I; 826f9f848faSopenharmony_ci } 827f9f848faSopenharmony_ci 828f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_SCSI)) { 829f9f848faSopenharmony_ci proto &= ~UMASS_PROTO_COMMAND; 830f9f848faSopenharmony_ci proto |= UMASS_PROTO_SCSI; 831f9f848faSopenharmony_ci } else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_ATAPI)) { 832f9f848faSopenharmony_ci proto &= ~UMASS_PROTO_COMMAND; 833f9f848faSopenharmony_ci proto |= UMASS_PROTO_ATAPI; 834f9f848faSopenharmony_ci } else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_UFI)) { 835f9f848faSopenharmony_ci proto &= ~UMASS_PROTO_COMMAND; 836f9f848faSopenharmony_ci proto |= UMASS_PROTO_UFI; 837f9f848faSopenharmony_ci } else if (usb_test_quirk(uaa, UQ_MSC_FORCE_PROTO_RBC)) { 838f9f848faSopenharmony_ci proto &= ~UMASS_PROTO_COMMAND; 839f9f848faSopenharmony_ci proto |= UMASS_PROTO_RBC; 840f9f848faSopenharmony_ci } 841f9f848faSopenharmony_ci 842f9f848faSopenharmony_ci /* Check if the protocol is invalid */ 843f9f848faSopenharmony_ci 844f9f848faSopenharmony_ci if ((proto & UMASS_PROTO_COMMAND) == 0) { 845f9f848faSopenharmony_ci ret.error = ENXIO; 846f9f848faSopenharmony_ci goto done; 847f9f848faSopenharmony_ci } 848f9f848faSopenharmony_ci 849f9f848faSopenharmony_ci if ((proto & UMASS_PROTO_WIRE) == 0) { 850f9f848faSopenharmony_ci ret.error = ENXIO; 851f9f848faSopenharmony_ci goto done; 852f9f848faSopenharmony_ci } 853f9f848faSopenharmony_ci 854f9f848faSopenharmony_ci /* Search for quirks */ 855f9f848faSopenharmony_ci 856f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_NO_TEST_UNIT_READY)) 857f9f848faSopenharmony_ci quirks |= NO_TEST_UNIT_READY; 858f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_NO_RS_CLEAR_UA)) 859f9f848faSopenharmony_ci quirks |= RS_NO_CLEAR_UA; 860f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_NO_START_STOP)) 861f9f848faSopenharmony_ci quirks |= NO_START_STOP; 862f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_NO_GETMAXLUN)) 863f9f848faSopenharmony_ci quirks |= NO_GETMAXLUN; 864f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY)) 865f9f848faSopenharmony_ci quirks |= NO_INQUIRY; 866f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_NO_INQUIRY_EVPD)) 867f9f848faSopenharmony_ci quirks |= NO_INQUIRY_EVPD; 868f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_NO_PREVENT_ALLOW)) 869f9f848faSopenharmony_ci quirks |= NO_PREVENT_ALLOW; 870f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_NO_SYNC_CACHE)) 871f9f848faSopenharmony_ci quirks |= NO_SYNCHRONIZE_CACHE; 872f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_SHUTTLE_INIT)) 873f9f848faSopenharmony_ci quirks |= SHUTTLE_INIT; 874f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_ALT_IFACE_1)) 875f9f848faSopenharmony_ci quirks |= ALT_IFACE_1; 876f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_FLOPPY_SPEED)) 877f9f848faSopenharmony_ci quirks |= FLOPPY_SPEED; 878f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_IGNORE_RESIDUE)) 879f9f848faSopenharmony_ci quirks |= IGNORE_RESIDUE; 880f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_WRONG_CSWSIG)) 881f9f848faSopenharmony_ci quirks |= WRONG_CSWSIG; 882f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_RBC_PAD_TO_12)) 883f9f848faSopenharmony_ci quirks |= RBC_PAD_TO_12; 884f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_READ_CAP_OFFBY1)) 885f9f848faSopenharmony_ci quirks |= READ_CAPACITY_OFFBY1; 886f9f848faSopenharmony_ci if (usb_test_quirk(uaa, UQ_MSC_FORCE_SHORT_INQ)) 887f9f848faSopenharmony_ci quirks |= FORCE_SHORT_INQUIRY; 888f9f848faSopenharmony_ci 889f9f848faSopenharmony_cidone: 890f9f848faSopenharmony_ci ret.quirks = quirks; 891f9f848faSopenharmony_ci ret.proto = proto; 892f9f848faSopenharmony_ci return (ret); 893f9f848faSopenharmony_ci} 894f9f848faSopenharmony_ci 895f9f848faSopenharmony_cistatic int 896f9f848faSopenharmony_ciumass_probe(device_t dev) 897f9f848faSopenharmony_ci{ 898f9f848faSopenharmony_ci struct usb_attach_arg *uaa = 899f9f848faSopenharmony_ci (struct usb_attach_arg *)device_get_ivars(dev); 900f9f848faSopenharmony_ci struct umass_probe_proto temp; 901f9f848faSopenharmony_ci 902f9f848faSopenharmony_ci if (uaa->usb_mode != USB_MODE_HOST) { 903f9f848faSopenharmony_ci return (ENXIO); 904f9f848faSopenharmony_ci } 905f9f848faSopenharmony_ci temp = umass_probe_proto(dev, uaa); 906f9f848faSopenharmony_ci 907f9f848faSopenharmony_ci return (temp.error); 908f9f848faSopenharmony_ci} 909f9f848faSopenharmony_ci 910f9f848faSopenharmony_cistatic int 911f9f848faSopenharmony_ciumass_attach(device_t dev) 912f9f848faSopenharmony_ci{ 913f9f848faSopenharmony_ci struct umass_softc *sc = 914f9f848faSopenharmony_ci (struct umass_softc *)device_get_softc(dev); 915f9f848faSopenharmony_ci struct usb_attach_arg *uaa = 916f9f848faSopenharmony_ci (struct usb_attach_arg *)device_get_ivars(dev); 917f9f848faSopenharmony_ci struct umass_probe_proto temp = umass_probe_proto(dev, uaa); 918f9f848faSopenharmony_ci struct usb_interface_descriptor *id; 919f9f848faSopenharmony_ci usb_error_t err; 920f9f848faSopenharmony_ci 921f9f848faSopenharmony_ci /* 922f9f848faSopenharmony_ci * NOTE: the softc struct is cleared in device_set_driver. 923f9f848faSopenharmony_ci * We can safely call umass_detach without specifically 924f9f848faSopenharmony_ci * initializing the struct. 925f9f848faSopenharmony_ci */ 926f9f848faSopenharmony_ci 927f9f848faSopenharmony_ci sc->sc_dev = dev; 928f9f848faSopenharmony_ci sc->sc_udev = uaa->device; 929f9f848faSopenharmony_ci sc->sc_proto = temp.proto; 930f9f848faSopenharmony_ci sc->sc_quirks = temp.quirks; 931f9f848faSopenharmony_ci sc->sc_unit = device_get_unit(dev); 932f9f848faSopenharmony_ci sc->data_ccb = NULL; 933f9f848faSopenharmony_ci sc->sc_detach_status = FALSE; 934f9f848faSopenharmony_ci sc->sc_super_disk = FALSE; 935f9f848faSopenharmony_ci 936f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 937f9f848faSopenharmony_ci dev_quantity |= 1ull << (unsigned int)device_get_unit(dev); 938f9f848faSopenharmony_ci#endif 939f9f848faSopenharmony_ci 940f9f848faSopenharmony_ci (void)snprintf_s((char *)sc->sc_name, sizeof(sc->sc_name), sizeof(sc->sc_name) - 1, 941f9f848faSopenharmony_ci "%s", device_get_nameunit(dev)); 942f9f848faSopenharmony_ci 943f9f848faSopenharmony_ci device_set_usb_desc(dev); 944f9f848faSopenharmony_ci 945f9f848faSopenharmony_ci mtx_init(&sc->sc_mtx, device_get_nameunit(dev), 946f9f848faSopenharmony_ci NULL, MTX_DEF | MTX_RECURSE); 947f9f848faSopenharmony_ci mtx_init(&sc->sc_umass_mtx, device_get_nameunit(dev), 948f9f848faSopenharmony_ci NULL, MTX_DEF | MTX_RECURSE); 949f9f848faSopenharmony_ci 950f9f848faSopenharmony_ci (void)LOS_EventInit(&sc->sc_event); 951f9f848faSopenharmony_ci 952f9f848faSopenharmony_ci /* get interface index */ 953f9f848faSopenharmony_ci 954f9f848faSopenharmony_ci id = usbd_get_interface_descriptor(uaa->iface); 955f9f848faSopenharmony_ci if (id == NULL) { 956f9f848faSopenharmony_ci device_printf(dev, "failed to get " 957f9f848faSopenharmony_ci "interface number\n"); 958f9f848faSopenharmony_ci goto detach; 959f9f848faSopenharmony_ci } 960f9f848faSopenharmony_ci sc->sc_iface_no = id->bInterfaceNumber; 961f9f848faSopenharmony_ci 962f9f848faSopenharmony_ci device_printf(dev, " "); 963f9f848faSopenharmony_ci 964f9f848faSopenharmony_ci switch (sc->sc_proto & UMASS_PROTO_COMMAND) { 965f9f848faSopenharmony_ci case UMASS_PROTO_SCSI: 966f9f848faSopenharmony_ci PRINTK("SCSI"); 967f9f848faSopenharmony_ci break; 968f9f848faSopenharmony_ci case UMASS_PROTO_ATAPI: 969f9f848faSopenharmony_ci PRINTK("8070i (ATAPI)"); 970f9f848faSopenharmony_ci break; 971f9f848faSopenharmony_ci case UMASS_PROTO_UFI: 972f9f848faSopenharmony_ci PRINTK("UFI"); 973f9f848faSopenharmony_ci break; 974f9f848faSopenharmony_ci case UMASS_PROTO_RBC: 975f9f848faSopenharmony_ci PRINTK("RBC"); 976f9f848faSopenharmony_ci break; 977f9f848faSopenharmony_ci default: 978f9f848faSopenharmony_ci PRINTK("(unknown 0x%02x)", 979f9f848faSopenharmony_ci sc->sc_proto & UMASS_PROTO_COMMAND); 980f9f848faSopenharmony_ci break; 981f9f848faSopenharmony_ci } 982f9f848faSopenharmony_ci 983f9f848faSopenharmony_ci PRINTK(" over "); 984f9f848faSopenharmony_ci 985f9f848faSopenharmony_ci switch (sc->sc_proto & UMASS_PROTO_WIRE) { 986f9f848faSopenharmony_ci case UMASS_PROTO_BBB: 987f9f848faSopenharmony_ci PRINTK("Bulk-Only"); 988f9f848faSopenharmony_ci break; 989f9f848faSopenharmony_ci case UMASS_PROTO_CBI: /* uses Comand/Bulk pipes */ 990f9f848faSopenharmony_ci PRINTK("CBI"); 991f9f848faSopenharmony_ci break; 992f9f848faSopenharmony_ci case UMASS_PROTO_CBI_I: /* uses Comand/Bulk/Interrupt pipes */ 993f9f848faSopenharmony_ci PRINTK("CBI with CCI"); 994f9f848faSopenharmony_ci break; 995f9f848faSopenharmony_ci default: 996f9f848faSopenharmony_ci PRINTK("(unknown 0x%02x)", 997f9f848faSopenharmony_ci sc->sc_proto & UMASS_PROTO_WIRE); 998f9f848faSopenharmony_ci } 999f9f848faSopenharmony_ci 1000f9f848faSopenharmony_ci PRINTK("; quirks = 0x%04x\n", sc->sc_quirks); 1001f9f848faSopenharmony_ci 1002f9f848faSopenharmony_ci if (sc->sc_quirks & ALT_IFACE_1) { 1003f9f848faSopenharmony_ci err = usbd_set_alt_interface_index 1004f9f848faSopenharmony_ci (uaa->device, uaa->info.bIfaceIndex, 1); 1005f9f848faSopenharmony_ci 1006f9f848faSopenharmony_ci if (err) { 1007f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_USB, "could not switch to " 1008f9f848faSopenharmony_ci "Alt Interface 1\n"); 1009f9f848faSopenharmony_ci goto detach; 1010f9f848faSopenharmony_ci } 1011f9f848faSopenharmony_ci } 1012f9f848faSopenharmony_ci /* allocate all required USB transfers */ 1013f9f848faSopenharmony_ci 1014f9f848faSopenharmony_ci if (sc->sc_proto & UMASS_PROTO_BBB) { 1015f9f848faSopenharmony_ci err = usbd_transfer_setup(uaa->device, 1016f9f848faSopenharmony_ci &uaa->info.bIfaceIndex, sc->sc_xfer, umass_bbb_config, 1017f9f848faSopenharmony_ci UMASS_T_BBB_MAX, sc, &sc->sc_mtx); 1018f9f848faSopenharmony_ci 1019f9f848faSopenharmony_ci /* skip reset first time */ 1020f9f848faSopenharmony_ci sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND; 1021f9f848faSopenharmony_ci 1022f9f848faSopenharmony_ci } else if (sc->sc_proto & (UMASS_PROTO_CBI | UMASS_PROTO_CBI_I)) { 1023f9f848faSopenharmony_ci err = usbd_transfer_setup(uaa->device, 1024f9f848faSopenharmony_ci &uaa->info.bIfaceIndex, sc->sc_xfer, umass_cbi_config, 1025f9f848faSopenharmony_ci UMASS_T_CBI_MAX, sc, &sc->sc_mtx); 1026f9f848faSopenharmony_ci 1027f9f848faSopenharmony_ci /* skip reset first time */ 1028f9f848faSopenharmony_ci sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND; 1029f9f848faSopenharmony_ci 1030f9f848faSopenharmony_ci } else { 1031f9f848faSopenharmony_ci err = USB_ERR_INVAL; 1032f9f848faSopenharmony_ci } 1033f9f848faSopenharmony_ci 1034f9f848faSopenharmony_ci if (err) { 1035f9f848faSopenharmony_ci device_printf(dev, "could not setup required " 1036f9f848faSopenharmony_ci "transfers, %s\n", usbd_errstr(err)); 1037f9f848faSopenharmony_ci goto detach; 1038f9f848faSopenharmony_ci } 1039f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 1040f9f848faSopenharmony_ci if (umass_throttle > 0) { 1041f9f848faSopenharmony_ci uint8_t x; 1042f9f848faSopenharmony_ci int iv; 1043f9f848faSopenharmony_ci 1044f9f848faSopenharmony_ci iv = umass_throttle; 1045f9f848faSopenharmony_ci 1046f9f848faSopenharmony_ci if (iv < 1) 1047f9f848faSopenharmony_ci iv = 1; 1048f9f848faSopenharmony_ci else if (iv > 8000) 1049f9f848faSopenharmony_ci iv = 8000; 1050f9f848faSopenharmony_ci 1051f9f848faSopenharmony_ci for (x = 0; x != UMASS_T_MAX; x++) { 1052f9f848faSopenharmony_ci if (sc->sc_xfer[x] != NULL) 1053f9f848faSopenharmony_ci usbd_xfer_set_interval(sc->sc_xfer[x], iv); 1054f9f848faSopenharmony_ci } 1055f9f848faSopenharmony_ci } 1056f9f848faSopenharmony_ci#endif 1057f9f848faSopenharmony_ci sc->sc_transform = 1058f9f848faSopenharmony_ci (sc->sc_proto & UMASS_PROTO_SCSI) ? &umass_scsi_transform : 1059f9f848faSopenharmony_ci (sc->sc_proto & UMASS_PROTO_UFI) ? &umass_ufi_transform : 1060f9f848faSopenharmony_ci (sc->sc_proto & UMASS_PROTO_ATAPI) ? &umass_atapi_transform : 1061f9f848faSopenharmony_ci (sc->sc_proto & UMASS_PROTO_RBC) ? &umass_rbc_transform : 1062f9f848faSopenharmony_ci &umass_no_transform; 1063f9f848faSopenharmony_ci 1064f9f848faSopenharmony_ci /* from here onwards the device can be used. */ 1065f9f848faSopenharmony_ci 1066f9f848faSopenharmony_ci if (sc->sc_quirks & SHUTTLE_INIT) { 1067f9f848faSopenharmony_ci umass_init_shuttle(sc); 1068f9f848faSopenharmony_ci } 1069f9f848faSopenharmony_ci /* get the maximum LUN supported by the device */ 1070f9f848faSopenharmony_ci 1071f9f848faSopenharmony_ci if (((sc->sc_proto & UMASS_PROTO_WIRE) == UMASS_PROTO_BBB) && 1072f9f848faSopenharmony_ci !(sc->sc_quirks & NO_GETMAXLUN)) 1073f9f848faSopenharmony_ci sc->sc_maxlun = umass_bbb_get_max_lun(sc); 1074f9f848faSopenharmony_ci else 1075f9f848faSopenharmony_ci sc->sc_maxlun = 0; 1076f9f848faSopenharmony_ci 1077f9f848faSopenharmony_ci /* Prepare the SCSI command block */ 1078f9f848faSopenharmony_ci sc->cam_scsi_sense.opcode = REQUEST_SENSE; 1079f9f848faSopenharmony_ci sc->cam_scsi_test_unit_ready.opcode = TEST_UNIT_READY; 1080f9f848faSopenharmony_ci 1081f9f848faSopenharmony_ci#define SOFT_CACHE_SIZE 0x40 1082f9f848faSopenharmony_ci sc->data_ccb = (union ccb *)malloc(sizeof(union ccb)); 1083f9f848faSopenharmony_ci if (sc->data_ccb == NULL) 1084f9f848faSopenharmony_ci goto detach; 1085f9f848faSopenharmony_ci sc->data_ccb->csio.data_ptr = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(SOFT_CACHE_SIZE)); 1086f9f848faSopenharmony_ci if (sc->data_ccb->csio.data_ptr == NULL) 1087f9f848faSopenharmony_ci goto detach; 1088f9f848faSopenharmony_ci sc->data_ccb->csio.dxfer_len = SOFT_CACHE_SIZE; 1089f9f848faSopenharmony_ci 1090f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_GEN, "Attach finished\n"); 1091f9f848faSopenharmony_ci 1092f9f848faSopenharmony_ci /* register the device*/ 1093f9f848faSopenharmony_ci if (umass_attach_dev(sc, device_get_unit(dev))) { 1094f9f848faSopenharmony_ci goto detach; 1095f9f848faSopenharmony_ci } 1096f9f848faSopenharmony_ci 1097f9f848faSopenharmony_ci p_umsf = sc; 1098f9f848faSopenharmony_ci return (0); /* success */ 1099f9f848faSopenharmony_ci 1100f9f848faSopenharmony_cidetach: 1101f9f848faSopenharmony_ci (void)umass_detach(dev); 1102f9f848faSopenharmony_ci return (ENXIO); /* failure */ 1103f9f848faSopenharmony_ci} 1104f9f848faSopenharmony_ci 1105f9f848faSopenharmony_cistatic int 1106f9f848faSopenharmony_ciumass_detach(device_t dev) 1107f9f848faSopenharmony_ci{ 1108f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)device_get_softc(dev); 1109f9f848faSopenharmony_ci unsigned int dev_unit = device_get_unit(dev); 1110f9f848faSopenharmony_ci 1111f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_USB, "\n"); 1112f9f848faSopenharmony_ci 1113f9f848faSopenharmony_ci sc->sc_detach_status = TRUE; 1114f9f848faSopenharmony_ci 1115f9f848faSopenharmony_ci /* teardown our statemachine */ 1116f9f848faSopenharmony_ci usbd_transfer_unsetup(sc->sc_xfer, UMASS_T_MAX); 1117f9f848faSopenharmony_ci 1118f9f848faSopenharmony_ci mtx_lock(&sc->sc_mtx); 1119f9f848faSopenharmony_ci 1120f9f848faSopenharmony_ci /* cancel any leftover CCB's */ 1121f9f848faSopenharmony_ci umass_cancel_ccb(sc); 1122f9f848faSopenharmony_ci 1123f9f848faSopenharmony_ci mtx_lock(&sc->sc_umass_mtx); 1124f9f848faSopenharmony_ci if (sc->data_ccb != NULL) { 1125f9f848faSopenharmony_ci if (sc->data_ccb->csio.data_ptr != NULL) { 1126f9f848faSopenharmony_ci free((void*)sc->data_ccb->csio.data_ptr); 1127f9f848faSopenharmony_ci sc->data_ccb->csio.data_ptr = NULL; 1128f9f848faSopenharmony_ci } 1129f9f848faSopenharmony_ci free(sc->data_ccb); 1130f9f848faSopenharmony_ci sc->data_ccb = NULL; 1131f9f848faSopenharmony_ci } 1132f9f848faSopenharmony_ci mtx_unlock(&sc->sc_umass_mtx); 1133f9f848faSopenharmony_ci 1134f9f848faSopenharmony_ci umass_detach_dev_sub(sc, dev_unit, 0); 1135f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 1136f9f848faSopenharmony_ci umass_task_check(1); 1137f9f848faSopenharmony_ci#endif 1138f9f848faSopenharmony_ci 1139f9f848faSopenharmony_ci mtx_unlock(&sc->sc_mtx); 1140f9f848faSopenharmony_ci sc->sc_detach_status = FALSE; 1141f9f848faSopenharmony_ci mtx_destroy(&sc->sc_mtx); 1142f9f848faSopenharmony_ci mtx_destroy(&sc->sc_umass_mtx); 1143f9f848faSopenharmony_ci 1144f9f848faSopenharmony_ci p_umsf = NULL; 1145f9f848faSopenharmony_ci return (0); /* success */ 1146f9f848faSopenharmony_ci} 1147f9f848faSopenharmony_ci 1148f9f848faSopenharmony_cistatic void 1149f9f848faSopenharmony_ciumass_init_shuttle(struct umass_softc *sc) 1150f9f848faSopenharmony_ci{ 1151f9f848faSopenharmony_ci struct usb_device_request req; 1152f9f848faSopenharmony_ci usb_error_t err; 1153f9f848faSopenharmony_ci uint8_t status[2] = {0, 0}; 1154f9f848faSopenharmony_ci 1155f9f848faSopenharmony_ci /* 1156f9f848faSopenharmony_ci * The Linux driver does this, but no one can tell us what the 1157f9f848faSopenharmony_ci * command does. 1158f9f848faSopenharmony_ci */ 1159f9f848faSopenharmony_ci req.bmRequestType = UT_READ_VENDOR_DEVICE; 1160f9f848faSopenharmony_ci req.bRequest = 1; /* XXX unknown command */ 1161f9f848faSopenharmony_ci USETW(req.wValue, 0); 1162f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_iface_no; 1163f9f848faSopenharmony_ci req.wIndex[1] = 0; 1164f9f848faSopenharmony_ci USETW(req.wLength, sizeof(status)); 1165f9f848faSopenharmony_ci err = usbd_do_request(sc->sc_udev, NULL, &req, &status); 1166f9f848faSopenharmony_ci if (err) 1167f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_GEN, "request failed in %s %d, err=%d\n", 1168f9f848faSopenharmony_ci __FUNCTION__, __LINE__, err); 1169f9f848faSopenharmony_ci 1170f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_GEN, "Shuttle init returned 0x%02x%02x\n", 1171f9f848faSopenharmony_ci status[0], status[1]); 1172f9f848faSopenharmony_ci} 1173f9f848faSopenharmony_ci 1174f9f848faSopenharmony_ci/* 1175f9f848faSopenharmony_ci * Generic functions to handle transfers 1176f9f848faSopenharmony_ci */ 1177f9f848faSopenharmony_ci 1178f9f848faSopenharmony_cistatic void 1179f9f848faSopenharmony_ciumass_transfer_start(struct umass_softc *sc, uint8_t xfer_index) 1180f9f848faSopenharmony_ci{ 1181f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_GEN, "transfer index = " 1182f9f848faSopenharmony_ci "%d\n", xfer_index); 1183f9f848faSopenharmony_ci 1184f9f848faSopenharmony_ci if (sc->sc_xfer[xfer_index]) { 1185f9f848faSopenharmony_ci sc->sc_last_xfer_index = xfer_index; 1186f9f848faSopenharmony_ci usbd_transfer_start(sc->sc_xfer[xfer_index]); 1187f9f848faSopenharmony_ci } else { 1188f9f848faSopenharmony_ci umass_cancel_ccb(sc); 1189f9f848faSopenharmony_ci } 1190f9f848faSopenharmony_ci} 1191f9f848faSopenharmony_ci 1192f9f848faSopenharmony_cistatic void 1193f9f848faSopenharmony_ciumass_cancel_ccb(struct umass_softc *sc) 1194f9f848faSopenharmony_ci{ 1195f9f848faSopenharmony_ci union ccb *umass_ccb; 1196f9f848faSopenharmony_ci 1197f9f848faSopenharmony_ci mtx_assert(&sc->sc_mtx, MA_OWNED); 1198f9f848faSopenharmony_ci 1199f9f848faSopenharmony_ci umass_ccb = sc->sc_transfer.ccb; 1200f9f848faSopenharmony_ci sc->sc_transfer.ccb = NULL; 1201f9f848faSopenharmony_ci sc->sc_last_xfer_index = 0; 1202f9f848faSopenharmony_ci 1203f9f848faSopenharmony_ci if (umass_ccb != NULL) { 1204f9f848faSopenharmony_ci (sc->sc_transfer.callback) 1205f9f848faSopenharmony_ci (sc, umass_ccb, (sc->sc_transfer.data_len - 1206f9f848faSopenharmony_ci sc->sc_transfer.actlen), STATUS_WIRE_FAILED); 1207f9f848faSopenharmony_ci } 1208f9f848faSopenharmony_ci} 1209f9f848faSopenharmony_ci 1210f9f848faSopenharmony_cistatic void 1211f9f848faSopenharmony_ciumass_tr_error(struct usb_xfer *xfer, usb_error_t error) 1212f9f848faSopenharmony_ci{ 1213f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1214f9f848faSopenharmony_ci 1215f9f848faSopenharmony_ci if (error != USB_ERR_CANCELLED) { 1216f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_GEN, "transfer error, %s -> " 1217f9f848faSopenharmony_ci "reset\n", usbd_errstr(error)); 1218f9f848faSopenharmony_ci } 1219f9f848faSopenharmony_ci umass_cancel_ccb(sc); 1220f9f848faSopenharmony_ci} 1221f9f848faSopenharmony_ci 1222f9f848faSopenharmony_ci/* 1223f9f848faSopenharmony_ci *return 0: find the corresponding LUN; 1224f9f848faSopenharmony_ci * 1: find the SBC Direct-access; 1225f9f848faSopenharmony_ci * -1: did not find the LUN. 1226f9f848faSopenharmony_ci */ 1227f9f848faSopenharmony_cistatic int 1228f9f848faSopenharmony_ciumass_scsi_inquiry_data(struct umass_softc *sc, void *data, int len) 1229f9f848faSopenharmony_ci{ 1230f9f848faSopenharmony_ci struct scsiresp_inquiry_s *cur_i; 1231f9f848faSopenharmony_ci uint8_t pdt; 1232f9f848faSopenharmony_ci uint8_t rmb; 1233f9f848faSopenharmony_ci int is_dir; 1234f9f848faSopenharmony_ci char *name; 1235f9f848faSopenharmony_ci 1236f9f848faSopenharmony_ci if (len != SCSIRESP_INQUIRY_SIZEOF) 1237f9f848faSopenharmony_ci return (-1); 1238f9f848faSopenharmony_ci 1239f9f848faSopenharmony_ci is_dir = 0; 1240f9f848faSopenharmony_ci cur_i = (struct scsiresp_inquiry_s *)data; 1241f9f848faSopenharmony_ci 1242f9f848faSopenharmony_ci pdt = SCSI_GET_INQUIRY_PDT(cur_i->qualtype); 1243f9f848faSopenharmony_ci rmb = SCSI_GET_INQUIRY_RMB(cur_i->flags1); 1244f9f848faSopenharmony_ci switch (pdt) { 1245f9f848faSopenharmony_ci case T_DIRECT: 1246f9f848faSopenharmony_ci name = "SBC Direct-access"; 1247f9f848faSopenharmony_ci is_dir = 1; 1248f9f848faSopenharmony_ci break; 1249f9f848faSopenharmony_ci case T_CDROM: 1250f9f848faSopenharmony_ci name = "CD-ROM"; 1251f9f848faSopenharmony_ci break; 1252f9f848faSopenharmony_ci case T_OPTICAL: 1253f9f848faSopenharmony_ci name = "Optical memory"; 1254f9f848faSopenharmony_ci break; 1255f9f848faSopenharmony_ci case T_RBC: 1256f9f848faSopenharmony_ci name = "RBC Direct-access"; 1257f9f848faSopenharmony_ci break; 1258f9f848faSopenharmony_ci default: 1259f9f848faSopenharmony_ci name = "PDT out of scope"; 1260f9f848faSopenharmony_ci break; 1261f9f848faSopenharmony_ci } 1262f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "SCSI: LUN-%d %s %s\n", sc->sc_transfer.lun, name, 1263f9f848faSopenharmony_ci (rmb ? "Removable" : "Not Removable")); 1264f9f848faSopenharmony_ci 1265f9f848faSopenharmony_ci (void)name; 1266f9f848faSopenharmony_ci (void)rmb; /* this is for clearing warning */ 1267f9f848faSopenharmony_ci return (is_dir); 1268f9f848faSopenharmony_ci} 1269f9f848faSopenharmony_ci 1270f9f848faSopenharmony_ci/* 1271f9f848faSopenharmony_ci * BBB protocol specific functions 1272f9f848faSopenharmony_ci */ 1273f9f848faSopenharmony_ci 1274f9f848faSopenharmony_cistatic void 1275f9f848faSopenharmony_ciumass_t_bbb_reset1_callback(struct usb_xfer *xfer, usb_error_t error) 1276f9f848faSopenharmony_ci{ 1277f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1278f9f848faSopenharmony_ci struct usb_device_request req; 1279f9f848faSopenharmony_ci struct usb_page_cache *pc; 1280f9f848faSopenharmony_ci 1281f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1282f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1283f9f848faSopenharmony_ci umass_transfer_start(sc, UMASS_T_BBB_RESET2); 1284f9f848faSopenharmony_ci return; 1285f9f848faSopenharmony_ci 1286f9f848faSopenharmony_ci case USB_ST_SETUP: 1287f9f848faSopenharmony_ci /* 1288f9f848faSopenharmony_ci * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class) 1289f9f848faSopenharmony_ci * 1290f9f848faSopenharmony_ci * For Reset Recovery the host shall issue in the following order: 1291f9f848faSopenharmony_ci * a) a Bulk-Only Mass Storage Reset 1292f9f848faSopenharmony_ci * b) a Clear Feature HALT to the Bulk-In endpoint 1293f9f848faSopenharmony_ci * c) a Clear Feature HALT to the Bulk-Out endpoint 1294f9f848faSopenharmony_ci * 1295f9f848faSopenharmony_ci * This is done in 3 steps, using 3 transfers: 1296f9f848faSopenharmony_ci * UMASS_T_BBB_RESET1 1297f9f848faSopenharmony_ci * UMASS_T_BBB_RESET2 1298f9f848faSopenharmony_ci * UMASS_T_BBB_RESET3 1299f9f848faSopenharmony_ci */ 1300f9f848faSopenharmony_ci 1301f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "BBB reset!\n"); 1302f9f848faSopenharmony_ci 1303f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1304f9f848faSopenharmony_ci req.bRequest = UR_BBB_RESET; /* bulk only reset */ 1305f9f848faSopenharmony_ci USETW(req.wValue, 0); 1306f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_iface_no; 1307f9f848faSopenharmony_ci req.wIndex[1] = 0; 1308f9f848faSopenharmony_ci USETW(req.wLength, 0); 1309f9f848faSopenharmony_ci 1310f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 0); 1311f9f848faSopenharmony_ci usbd_copy_in(pc, 0, &req, sizeof(req)); 1312f9f848faSopenharmony_ci 1313f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 1314f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 1); 1315f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1316f9f848faSopenharmony_ci return; 1317f9f848faSopenharmony_ci 1318f9f848faSopenharmony_ci default: /* Error */ 1319f9f848faSopenharmony_ci umass_tr_error(xfer, error); 1320f9f848faSopenharmony_ci return; 1321f9f848faSopenharmony_ci } 1322f9f848faSopenharmony_ci} 1323f9f848faSopenharmony_ci 1324f9f848faSopenharmony_cistatic void 1325f9f848faSopenharmony_ciumass_t_bbb_reset2_callback(struct usb_xfer *xfer, usb_error_t error) 1326f9f848faSopenharmony_ci{ 1327f9f848faSopenharmony_ci umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_RESET3, 1328f9f848faSopenharmony_ci UMASS_T_BBB_DATA_READ, error); 1329f9f848faSopenharmony_ci} 1330f9f848faSopenharmony_ci 1331f9f848faSopenharmony_cistatic void 1332f9f848faSopenharmony_ciumass_t_bbb_reset3_callback(struct usb_xfer *xfer, usb_error_t error) 1333f9f848faSopenharmony_ci{ 1334f9f848faSopenharmony_ci umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_COMMAND, 1335f9f848faSopenharmony_ci UMASS_T_BBB_DATA_WRITE, error); 1336f9f848faSopenharmony_ci} 1337f9f848faSopenharmony_ci 1338f9f848faSopenharmony_cistatic void 1339f9f848faSopenharmony_ciumass_t_bbb_data_clear_stall_callback(struct usb_xfer *xfer, 1340f9f848faSopenharmony_ci uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error) 1341f9f848faSopenharmony_ci{ 1342f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1343f9f848faSopenharmony_ci 1344f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1345f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1346f9f848faSopenharmony_citr_transferred: 1347f9f848faSopenharmony_ci umass_transfer_start(sc, next_xfer); 1348f9f848faSopenharmony_ci return; 1349f9f848faSopenharmony_ci 1350f9f848faSopenharmony_ci case USB_ST_SETUP: 1351f9f848faSopenharmony_ci if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) { 1352f9f848faSopenharmony_ci goto tr_transferred; 1353f9f848faSopenharmony_ci } 1354f9f848faSopenharmony_ci return; 1355f9f848faSopenharmony_ci 1356f9f848faSopenharmony_ci default: /* Error */ 1357f9f848faSopenharmony_ci umass_tr_error(xfer, error); 1358f9f848faSopenharmony_ci return; 1359f9f848faSopenharmony_ci } 1360f9f848faSopenharmony_ci} 1361f9f848faSopenharmony_ci 1362f9f848faSopenharmony_cistatic void 1363f9f848faSopenharmony_ciumass_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error) 1364f9f848faSopenharmony_ci{ 1365f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1366f9f848faSopenharmony_ci struct usb_page_cache *pc; 1367f9f848faSopenharmony_ci uint32_t tag; 1368f9f848faSopenharmony_ci int ret; 1369f9f848faSopenharmony_ci 1370f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1371f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1372f9f848faSopenharmony_ci umass_transfer_start 1373f9f848faSopenharmony_ci (sc, ((sc->sc_transfer.dir == DIR_IN) ? UMASS_T_BBB_DATA_READ : 1374f9f848faSopenharmony_ci (sc->sc_transfer.dir == DIR_OUT) ? UMASS_T_BBB_DATA_WRITE : 1375f9f848faSopenharmony_ci UMASS_T_BBB_STATUS)); 1376f9f848faSopenharmony_ci return; 1377f9f848faSopenharmony_ci 1378f9f848faSopenharmony_ci case USB_ST_SETUP: 1379f9f848faSopenharmony_ci 1380f9f848faSopenharmony_ci sc->sc_status_try = 0; 1381f9f848faSopenharmony_ci 1382f9f848faSopenharmony_ci /* 1383f9f848faSopenharmony_ci * the initial value is not important, 1384f9f848faSopenharmony_ci * as long as the values are unique: 1385f9f848faSopenharmony_ci */ 1386f9f848faSopenharmony_ci tag = UGETDW(sc->cbw.dCBWTag) + 1; 1387f9f848faSopenharmony_ci 1388f9f848faSopenharmony_ci USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE); 1389f9f848faSopenharmony_ci USETDW(sc->cbw.dCBWTag, tag); 1390f9f848faSopenharmony_ci 1391f9f848faSopenharmony_ci /* 1392f9f848faSopenharmony_ci * dCBWDataTransferLength: 1393f9f848faSopenharmony_ci * This field indicates the number of bytes of data that the host 1394f9f848faSopenharmony_ci * intends to transfer on the IN or OUT Bulk endpoint(as indicated by 1395f9f848faSopenharmony_ci * the Direction bit) during the execution of this command. If this 1396f9f848faSopenharmony_ci * field is set to 0, the device will expect that no data will be 1397f9f848faSopenharmony_ci * transferred IN or OUT during this command, regardless of the value 1398f9f848faSopenharmony_ci * of the Direction bit defined in dCBWFlags. 1399f9f848faSopenharmony_ci */ 1400f9f848faSopenharmony_ci USETDW(sc->cbw.dCBWDataTransferLength, sc->sc_transfer.data_len); 1401f9f848faSopenharmony_ci 1402f9f848faSopenharmony_ci /* 1403f9f848faSopenharmony_ci * dCBWFlags: 1404f9f848faSopenharmony_ci * The bits of the Flags field are defined as follows: 1405f9f848faSopenharmony_ci * Bits 0-6 reserved 1406f9f848faSopenharmony_ci * Bit 7 Direction - this bit shall be ignored if the 1407f9f848faSopenharmony_ci * dCBWDataTransferLength field is zero. 1408f9f848faSopenharmony_ci * 0 = data Out from host to device 1409f9f848faSopenharmony_ci * 1 = data In from device to host 1410f9f848faSopenharmony_ci */ 1411f9f848faSopenharmony_ci sc->cbw.bCBWFlags = ((sc->sc_transfer.dir == DIR_IN) ? 1412f9f848faSopenharmony_ci CBWFLAGS_IN : CBWFLAGS_OUT); 1413f9f848faSopenharmony_ci sc->cbw.bCBWLUN = sc->sc_transfer.lun; 1414f9f848faSopenharmony_ci 1415f9f848faSopenharmony_ci if (sc->sc_transfer.cmd_len > sizeof(sc->cbw.CBWCDB)) { 1416f9f848faSopenharmony_ci sc->sc_transfer.cmd_len = sizeof(sc->cbw.CBWCDB); 1417f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "Truncating long command!\n"); 1418f9f848faSopenharmony_ci } 1419f9f848faSopenharmony_ci sc->cbw.bCDBLength = sc->sc_transfer.cmd_len; 1420f9f848faSopenharmony_ci 1421f9f848faSopenharmony_ci /* copy SCSI command data */ 1422f9f848faSopenharmony_ci ret = memcpy_s(sc->cbw.CBWCDB, CBWCDBLENGTH, 1423f9f848faSopenharmony_ci sc->sc_transfer.cmd_data, sc->sc_transfer.cmd_len); 1424f9f848faSopenharmony_ci if (ret != EOK) { 1425f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "memcpy_s fail, %d\n", ret); 1426f9f848faSopenharmony_ci return; 1427f9f848faSopenharmony_ci } 1428f9f848faSopenharmony_ci 1429f9f848faSopenharmony_ci /* clear remaining command area */ 1430f9f848faSopenharmony_ci (void)memset_s(sc->cbw.CBWCDB + sc->sc_transfer.cmd_len, 1431f9f848faSopenharmony_ci sizeof(sc->cbw.CBWCDB) - sc->sc_transfer.cmd_len, 0, 1432f9f848faSopenharmony_ci sizeof(sc->cbw.CBWCDB) - sc->sc_transfer.cmd_len); 1433f9f848faSopenharmony_ci 1434f9f848faSopenharmony_ci DIF(UDMASS_BBB, umass_bbb_dump_cbw(sc, &sc->cbw)); 1435f9f848faSopenharmony_ci 1436f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 0); 1437f9f848faSopenharmony_ci usbd_copy_in(pc, 0, &sc->cbw, sizeof(sc->cbw)); 1438f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sizeof(sc->cbw)); 1439f9f848faSopenharmony_ci 1440f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1441f9f848faSopenharmony_ci 1442f9f848faSopenharmony_ci return; 1443f9f848faSopenharmony_ci 1444f9f848faSopenharmony_ci default: /* Error */ 1445f9f848faSopenharmony_ci umass_tr_error(xfer, error); 1446f9f848faSopenharmony_ci return; 1447f9f848faSopenharmony_ci } 1448f9f848faSopenharmony_ci} 1449f9f848faSopenharmony_ci 1450f9f848faSopenharmony_cistatic void 1451f9f848faSopenharmony_ciumass_t_bbb_data_callback(struct usb_xfer *xfer, usb_error_t error, 1452f9f848faSopenharmony_ci uint8_t xfer_index) 1453f9f848faSopenharmony_ci{ 1454f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1455f9f848faSopenharmony_ci uint32_t max_bulk = usbd_xfer_max_len(xfer); 1456f9f848faSopenharmony_ci int actlen, sumlen; 1457f9f848faSopenharmony_ci 1458f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 1459f9f848faSopenharmony_ci 1460f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1461f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1462f9f848faSopenharmony_ci sc->sc_transfer.data_rem -= actlen; 1463f9f848faSopenharmony_ci sc->sc_transfer.data_ptr += actlen; 1464f9f848faSopenharmony_ci sc->sc_transfer.actlen += actlen; 1465f9f848faSopenharmony_ci 1466f9f848faSopenharmony_ci if (actlen < sumlen) { 1467f9f848faSopenharmony_ci /* short transfer */ 1468f9f848faSopenharmony_ci sc->sc_transfer.data_rem = 0; 1469f9f848faSopenharmony_ci } 1470f9f848faSopenharmony_ci case USB_ST_SETUP: 1471f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "max_bulk=%u, data_rem=%u\n", 1472f9f848faSopenharmony_ci max_bulk, sc->sc_transfer.data_rem); 1473f9f848faSopenharmony_ci 1474f9f848faSopenharmony_ci if (sc->sc_transfer.data_rem == 0) { 1475f9f848faSopenharmony_ci umass_transfer_start(sc, UMASS_T_BBB_STATUS); 1476f9f848faSopenharmony_ci return; 1477f9f848faSopenharmony_ci } 1478f9f848faSopenharmony_ci if (max_bulk > sc->sc_transfer.data_rem) { 1479f9f848faSopenharmony_ci max_bulk = sc->sc_transfer.data_rem; 1480f9f848faSopenharmony_ci } 1481f9f848faSopenharmony_ci usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); 1482f9f848faSopenharmony_ci 1483f9f848faSopenharmony_ci usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, 1484f9f848faSopenharmony_ci max_bulk); 1485f9f848faSopenharmony_ci 1486f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1487f9f848faSopenharmony_ci return; 1488f9f848faSopenharmony_ci 1489f9f848faSopenharmony_ci default: /* Error */ 1490f9f848faSopenharmony_ci if (error == USB_ERR_CANCELLED) { 1491f9f848faSopenharmony_ci umass_tr_error(xfer, error); 1492f9f848faSopenharmony_ci } else { 1493f9f848faSopenharmony_ci umass_transfer_start(sc, xfer_index); 1494f9f848faSopenharmony_ci } 1495f9f848faSopenharmony_ci return; 1496f9f848faSopenharmony_ci } 1497f9f848faSopenharmony_ci} 1498f9f848faSopenharmony_ci 1499f9f848faSopenharmony_cistatic void 1500f9f848faSopenharmony_ciumass_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error) 1501f9f848faSopenharmony_ci{ 1502f9f848faSopenharmony_ci umass_t_bbb_data_callback(xfer, error, UMASS_T_BBB_DATA_RD_CS); 1503f9f848faSopenharmony_ci} 1504f9f848faSopenharmony_ci 1505f9f848faSopenharmony_cistatic void 1506f9f848faSopenharmony_ciumass_t_bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error) 1507f9f848faSopenharmony_ci{ 1508f9f848faSopenharmony_ci umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS, 1509f9f848faSopenharmony_ci UMASS_T_BBB_DATA_READ, error); 1510f9f848faSopenharmony_ci} 1511f9f848faSopenharmony_ci 1512f9f848faSopenharmony_cistatic void 1513f9f848faSopenharmony_ciumass_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error) 1514f9f848faSopenharmony_ci{ 1515f9f848faSopenharmony_ci umass_t_bbb_data_callback(xfer, error, UMASS_T_BBB_DATA_WR_CS); 1516f9f848faSopenharmony_ci} 1517f9f848faSopenharmony_ci 1518f9f848faSopenharmony_cistatic void 1519f9f848faSopenharmony_ciumass_t_bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error) 1520f9f848faSopenharmony_ci{ 1521f9f848faSopenharmony_ci umass_t_bbb_data_clear_stall_callback(xfer, UMASS_T_BBB_STATUS, 1522f9f848faSopenharmony_ci UMASS_T_BBB_DATA_WRITE, error); 1523f9f848faSopenharmony_ci} 1524f9f848faSopenharmony_ci 1525f9f848faSopenharmony_cistatic void 1526f9f848faSopenharmony_ciumass_t_bbb_status_callback(struct usb_xfer *xfer, usb_error_t error) 1527f9f848faSopenharmony_ci{ 1528f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1529f9f848faSopenharmony_ci union ccb *umass_ccb = sc->sc_transfer.ccb; 1530f9f848faSopenharmony_ci struct usb_page_cache *pc; 1531f9f848faSopenharmony_ci uint32_t residue; 1532f9f848faSopenharmony_ci int actlen; 1533f9f848faSopenharmony_ci 1534f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 1535f9f848faSopenharmony_ci 1536f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1537f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1538f9f848faSopenharmony_ci 1539f9f848faSopenharmony_ci /* 1540f9f848faSopenharmony_ci * Do a full reset if there is something wrong with the CSW: 1541f9f848faSopenharmony_ci */ 1542f9f848faSopenharmony_ci sc->sc_status_try = 1; 1543f9f848faSopenharmony_ci 1544f9f848faSopenharmony_ci /* Zero missing parts of the CSW: */ 1545f9f848faSopenharmony_ci 1546f9f848faSopenharmony_ci if (actlen < (int)sizeof(sc->csw)) { 1547f9f848faSopenharmony_ci (void)memset_s(&sc->csw, sizeof(sc->csw), 0, sizeof(sc->csw)); 1548f9f848faSopenharmony_ci } 1549f9f848faSopenharmony_ci 1550f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 0); 1551f9f848faSopenharmony_ci 1552f9f848faSopenharmony_ci usbd_copy_out(pc, 0, &sc->csw, actlen); 1553f9f848faSopenharmony_ci 1554f9f848faSopenharmony_ci DIF(UDMASS_BBB, umass_bbb_dump_csw(sc, &sc->csw)); 1555f9f848faSopenharmony_ci 1556f9f848faSopenharmony_ci residue = UGETDW(sc->csw.dCSWDataResidue); 1557f9f848faSopenharmony_ci 1558f9f848faSopenharmony_ci if ((!residue) || (sc->sc_quirks & IGNORE_RESIDUE)) { 1559f9f848faSopenharmony_ci residue = (sc->sc_transfer.data_len - 1560f9f848faSopenharmony_ci sc->sc_transfer.actlen); 1561f9f848faSopenharmony_ci } 1562f9f848faSopenharmony_ci if (residue > sc->sc_transfer.data_len) { 1563f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "truncating residue from %d " 1564f9f848faSopenharmony_ci "to %d bytes\n", residue, sc->sc_transfer.data_len); 1565f9f848faSopenharmony_ci residue = sc->sc_transfer.data_len; 1566f9f848faSopenharmony_ci } 1567f9f848faSopenharmony_ci /* translate weird command-status signatures: */ 1568f9f848faSopenharmony_ci if (sc->sc_quirks & WRONG_CSWSIG) { 1569f9f848faSopenharmony_ci uint32_t temp = UGETDW(sc->csw.dCSWSignature); 1570f9f848faSopenharmony_ci 1571f9f848faSopenharmony_ci if ((temp == CSWSIGNATURE_OLYMPUS_C1) || 1572f9f848faSopenharmony_ci (temp == CSWSIGNATURE_IMAGINATION_DBX1)) { 1573f9f848faSopenharmony_ci USETDW(sc->csw.dCSWSignature, CSWSIGNATURE); 1574f9f848faSopenharmony_ci } 1575f9f848faSopenharmony_ci } 1576f9f848faSopenharmony_ci /* check CSW and handle eventual error */ 1577f9f848faSopenharmony_ci if (UGETDW(sc->csw.dCSWSignature) != CSWSIGNATURE) { 1578f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "bad CSW signature 0x%08x != 0x%08x\n", 1579f9f848faSopenharmony_ci UGETDW(sc->csw.dCSWSignature), CSWSIGNATURE); 1580f9f848faSopenharmony_ci /* 1581f9f848faSopenharmony_ci * Invalid CSW: Wrong signature or wrong tag might 1582f9f848faSopenharmony_ci * indicate that we lost synchronization. Reset the 1583f9f848faSopenharmony_ci * device. 1584f9f848faSopenharmony_ci */ 1585f9f848faSopenharmony_ci goto tr_error; 1586f9f848faSopenharmony_ci } else if (UGETDW(sc->csw.dCSWTag) != UGETDW(sc->cbw.dCBWTag)) { 1587f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "Invalid CSW: tag 0x%08x should be " 1588f9f848faSopenharmony_ci "0x%08x\n", UGETDW(sc->csw.dCSWTag), 1589f9f848faSopenharmony_ci UGETDW(sc->cbw.dCBWTag)); 1590f9f848faSopenharmony_ci goto tr_error; 1591f9f848faSopenharmony_ci } else if (sc->csw.bCSWStatus > CSWSTATUS_PHASE) { 1592f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "Invalid CSW: status %d > %d\n", 1593f9f848faSopenharmony_ci sc->csw.bCSWStatus, CSWSTATUS_PHASE); 1594f9f848faSopenharmony_ci goto tr_error; 1595f9f848faSopenharmony_ci } else if (sc->csw.bCSWStatus == CSWSTATUS_PHASE) { 1596f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "Phase error, residue = " 1597f9f848faSopenharmony_ci "%d\n", residue); 1598f9f848faSopenharmony_ci goto tr_error; 1599f9f848faSopenharmony_ci } else if (sc->sc_transfer.actlen > sc->sc_transfer.data_len) { 1600f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "Buffer overrun %d > %d\n", 1601f9f848faSopenharmony_ci sc->sc_transfer.actlen, sc->sc_transfer.data_len); 1602f9f848faSopenharmony_ci goto tr_error; 1603f9f848faSopenharmony_ci } else if (sc->csw.bCSWStatus == CSWSTATUS_FAILED) { 1604f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "Command failed, residue = " 1605f9f848faSopenharmony_ci "%d\n", residue); 1606f9f848faSopenharmony_ci 1607f9f848faSopenharmony_ci sc->sc_transfer.ccb = NULL; 1608f9f848faSopenharmony_ci 1609f9f848faSopenharmony_ci sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND; 1610f9f848faSopenharmony_ci 1611f9f848faSopenharmony_ci (sc->sc_transfer.callback) 1612f9f848faSopenharmony_ci (sc, umass_ccb, residue, STATUS_CMD_FAILED); 1613f9f848faSopenharmony_ci } else { 1614f9f848faSopenharmony_ci sc->sc_transfer.ccb = NULL; 1615f9f848faSopenharmony_ci 1616f9f848faSopenharmony_ci sc->sc_last_xfer_index = UMASS_T_BBB_COMMAND; 1617f9f848faSopenharmony_ci 1618f9f848faSopenharmony_ci (sc->sc_transfer.callback) 1619f9f848faSopenharmony_ci (sc, umass_ccb, residue, STATUS_CMD_OK); 1620f9f848faSopenharmony_ci } 1621f9f848faSopenharmony_ci return; 1622f9f848faSopenharmony_ci 1623f9f848faSopenharmony_ci case USB_ST_SETUP: 1624f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 1625f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1626f9f848faSopenharmony_ci return; 1627f9f848faSopenharmony_ci 1628f9f848faSopenharmony_ci default: 1629f9f848faSopenharmony_citr_error: 1630f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "Failed to read CSW: %s, try %d\n", 1631f9f848faSopenharmony_ci usbd_errstr(error), sc->sc_status_try); 1632f9f848faSopenharmony_ci 1633f9f848faSopenharmony_ci if ((error == USB_ERR_CANCELLED) || 1634f9f848faSopenharmony_ci (sc->sc_status_try)) { 1635f9f848faSopenharmony_ci umass_tr_error(xfer, error); 1636f9f848faSopenharmony_ci } else { 1637f9f848faSopenharmony_ci sc->sc_status_try = 1; 1638f9f848faSopenharmony_ci umass_transfer_start(sc, UMASS_T_BBB_DATA_RD_CS); 1639f9f848faSopenharmony_ci } 1640f9f848faSopenharmony_ci return; 1641f9f848faSopenharmony_ci } 1642f9f848faSopenharmony_ci} 1643f9f848faSopenharmony_ci 1644f9f848faSopenharmony_cistatic int 1645f9f848faSopenharmony_ciumass_command_start(struct umass_softc *sc, uint8_t dir, 1646f9f848faSopenharmony_ci void *data_ptr, uint32_t data_len, 1647f9f848faSopenharmony_ci uint32_t data_timeout, umass_callback_t *callback, 1648f9f848faSopenharmony_ci union ccb *umass_ccb) 1649f9f848faSopenharmony_ci{ 1650f9f848faSopenharmony_ci if (sc->sc_detach_status) 1651f9f848faSopenharmony_ci { 1652f9f848faSopenharmony_ci PRINT_WARN("[%s][%d] usb is detaching\n",__FUNCTION__,__LINE__); 1653f9f848faSopenharmony_ci return (-1); 1654f9f848faSopenharmony_ci } 1655f9f848faSopenharmony_ci 1656f9f848faSopenharmony_ci /* 1657f9f848faSopenharmony_ci * NOTE: assumes that "sc->sc_transfer.cmd_data" and 1658f9f848faSopenharmony_ci * "sc->sc_transfer.cmd_len" has been properly 1659f9f848faSopenharmony_ci * initialized. 1660f9f848faSopenharmony_ci */ 1661f9f848faSopenharmony_ci 1662f9f848faSopenharmony_ci sc->sc_transfer.dir = data_len ? dir : DIR_NONE; 1663f9f848faSopenharmony_ci sc->sc_transfer.data_ptr = (uint8_t *)data_ptr; 1664f9f848faSopenharmony_ci sc->sc_transfer.data_len = data_len; 1665f9f848faSopenharmony_ci sc->sc_transfer.data_rem = data_len; 1666f9f848faSopenharmony_ci sc->sc_transfer.data_timeout = (data_timeout + UMASS_TIMEOUT); 1667f9f848faSopenharmony_ci 1668f9f848faSopenharmony_ci sc->sc_transfer.actlen = 0; 1669f9f848faSopenharmony_ci sc->sc_transfer.callback = callback; 1670f9f848faSopenharmony_ci sc->sc_transfer.ccb = umass_ccb; 1671f9f848faSopenharmony_ci 1672f9f848faSopenharmony_ci if (sc->sc_xfer[sc->sc_last_xfer_index]) { 1673f9f848faSopenharmony_ci usbd_transfer_start(sc->sc_xfer[sc->sc_last_xfer_index]); 1674f9f848faSopenharmony_ci } else { 1675f9f848faSopenharmony_ci umass_cancel_ccb(sc); 1676f9f848faSopenharmony_ci } 1677f9f848faSopenharmony_ci 1678f9f848faSopenharmony_ci (void)LOS_EventRead(&sc->sc_event, 0xFF, 1679f9f848faSopenharmony_ci LOS_WAITMODE_OR | LOS_WAITMODE_CLR, 10 * LOSCFG_BASE_CORE_TICK_PER_SECOND); /* 10 seconds. */ 1680f9f848faSopenharmony_ci 1681f9f848faSopenharmony_ci return (0); 1682f9f848faSopenharmony_ci} 1683f9f848faSopenharmony_ci 1684f9f848faSopenharmony_cistatic uint8_t 1685f9f848faSopenharmony_ciumass_bbb_get_max_lun(struct umass_softc *sc) 1686f9f848faSopenharmony_ci{ 1687f9f848faSopenharmony_ci struct usb_device_request req; 1688f9f848faSopenharmony_ci usb_error_t err; 1689f9f848faSopenharmony_ci uint8_t buf = 0; 1690f9f848faSopenharmony_ci 1691f9f848faSopenharmony_ci /* The Get Max Lun command is a class-specific request. */ 1692f9f848faSopenharmony_ci req.bmRequestType = UT_READ_CLASS_INTERFACE; 1693f9f848faSopenharmony_ci req.bRequest = UR_BBB_GET_MAX_LUN; 1694f9f848faSopenharmony_ci USETW(req.wValue, 0); 1695f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_iface_no; 1696f9f848faSopenharmony_ci req.wIndex[1] = 0; 1697f9f848faSopenharmony_ci USETW(req.wLength, 1); 1698f9f848faSopenharmony_ci 1699f9f848faSopenharmony_ci err = usbd_do_request(sc->sc_udev, NULL, &req, &buf); 1700f9f848faSopenharmony_ci if (err) { 1701f9f848faSopenharmony_ci buf = 0; 1702f9f848faSopenharmony_ci 1703f9f848faSopenharmony_ci /* Device doesn't support Get Max Lun request. */ 1704f9f848faSopenharmony_ci PRINTK("%s: Get Max Lun not supported (%s)\n", 1705f9f848faSopenharmony_ci sc->sc_name, usbd_errstr(err)); 1706f9f848faSopenharmony_ci } 1707f9f848faSopenharmony_ci return (buf); 1708f9f848faSopenharmony_ci} 1709f9f848faSopenharmony_ci 1710f9f848faSopenharmony_ci/* 1711f9f848faSopenharmony_ci * Command/Bulk/Interrupt (CBI) specific functions 1712f9f848faSopenharmony_ci */ 1713f9f848faSopenharmony_ci 1714f9f848faSopenharmony_cistatic void 1715f9f848faSopenharmony_ciumass_cbi_start_status(struct umass_softc *sc) 1716f9f848faSopenharmony_ci{ 1717f9f848faSopenharmony_ci if (sc->sc_xfer[UMASS_T_CBI_STATUS]) { 1718f9f848faSopenharmony_ci umass_transfer_start(sc, UMASS_T_CBI_STATUS); 1719f9f848faSopenharmony_ci } else { 1720f9f848faSopenharmony_ci union ccb *umass_ccb = sc->sc_transfer.ccb; 1721f9f848faSopenharmony_ci 1722f9f848faSopenharmony_ci sc->sc_transfer.ccb = NULL; 1723f9f848faSopenharmony_ci 1724f9f848faSopenharmony_ci sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND; 1725f9f848faSopenharmony_ci 1726f9f848faSopenharmony_ci (sc->sc_transfer.callback) 1727f9f848faSopenharmony_ci (sc, umass_ccb, (sc->sc_transfer.data_len - 1728f9f848faSopenharmony_ci sc->sc_transfer.actlen), STATUS_CMD_UNKNOWN); 1729f9f848faSopenharmony_ci } 1730f9f848faSopenharmony_ci} 1731f9f848faSopenharmony_ci 1732f9f848faSopenharmony_cistatic void 1733f9f848faSopenharmony_ciumass_t_cbi_reset1_callback(struct usb_xfer *xfer, usb_error_t error) 1734f9f848faSopenharmony_ci{ 1735f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1736f9f848faSopenharmony_ci struct usb_device_request req; 1737f9f848faSopenharmony_ci struct usb_page_cache *pc; 1738f9f848faSopenharmony_ci uint8_t buf[UMASS_CBI_DIAGNOSTIC_CMDLEN]; 1739f9f848faSopenharmony_ci 1740f9f848faSopenharmony_ci uint8_t i; 1741f9f848faSopenharmony_ci 1742f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1743f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1744f9f848faSopenharmony_ci umass_transfer_start(sc, UMASS_T_CBI_RESET2); 1745f9f848faSopenharmony_ci break; 1746f9f848faSopenharmony_ci 1747f9f848faSopenharmony_ci case USB_ST_SETUP: 1748f9f848faSopenharmony_ci /* 1749f9f848faSopenharmony_ci * Command Block Reset Protocol 1750f9f848faSopenharmony_ci * 1751f9f848faSopenharmony_ci * First send a reset request to the device. Then clear 1752f9f848faSopenharmony_ci * any possibly stalled bulk endpoints. 1753f9f848faSopenharmony_ci * 1754f9f848faSopenharmony_ci * This is done in 3 steps, using 3 transfers: 1755f9f848faSopenharmony_ci * UMASS_T_CBI_RESET1 1756f9f848faSopenharmony_ci * UMASS_T_CBI_RESET2 1757f9f848faSopenharmony_ci * UMASS_T_CBI_RESET3 1758f9f848faSopenharmony_ci * UMASS_T_CBI_RESET4 (only if there is an interrupt endpoint) 1759f9f848faSopenharmony_ci */ 1760f9f848faSopenharmony_ci 1761f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_CBI, "CBI reset!\n"); 1762f9f848faSopenharmony_ci 1763f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1764f9f848faSopenharmony_ci req.bRequest = UR_CBI_ADSC; 1765f9f848faSopenharmony_ci USETW(req.wValue, 0); 1766f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_iface_no; 1767f9f848faSopenharmony_ci req.wIndex[1] = 0; 1768f9f848faSopenharmony_ci USETW(req.wLength, UMASS_CBI_DIAGNOSTIC_CMDLEN); 1769f9f848faSopenharmony_ci 1770f9f848faSopenharmony_ci /* 1771f9f848faSopenharmony_ci * The 0x1d code is the SEND DIAGNOSTIC command. To 1772f9f848faSopenharmony_ci * distinguish between the two, the last 10 bytes of the CBL 1773f9f848faSopenharmony_ci * is filled with 0xff (section 2.2 of the CBI 1774f9f848faSopenharmony_ci * specification) 1775f9f848faSopenharmony_ci */ 1776f9f848faSopenharmony_ci buf[0] = 0x1d; /* Command Block Reset */ 1777f9f848faSopenharmony_ci buf[1] = 0x04; 1778f9f848faSopenharmony_ci 1779f9f848faSopenharmony_ci for (i = 2; i < UMASS_CBI_DIAGNOSTIC_CMDLEN; i++) { 1780f9f848faSopenharmony_ci buf[i] = 0xff; 1781f9f848faSopenharmony_ci } 1782f9f848faSopenharmony_ci 1783f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 0); 1784f9f848faSopenharmony_ci usbd_copy_in(pc, 0, &req, sizeof(req)); 1785f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 1); 1786f9f848faSopenharmony_ci usbd_copy_in(pc, 0, buf, sizeof(buf)); 1787f9f848faSopenharmony_ci 1788f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 1789f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 1, sizeof(buf)); 1790f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 2); 1791f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1792f9f848faSopenharmony_ci break; 1793f9f848faSopenharmony_ci 1794f9f848faSopenharmony_ci default: /* Error */ 1795f9f848faSopenharmony_ci if (error == USB_ERR_CANCELLED) 1796f9f848faSopenharmony_ci umass_tr_error(xfer, error); 1797f9f848faSopenharmony_ci else 1798f9f848faSopenharmony_ci umass_transfer_start(sc, UMASS_T_CBI_RESET2); 1799f9f848faSopenharmony_ci break; 1800f9f848faSopenharmony_ci } 1801f9f848faSopenharmony_ci} 1802f9f848faSopenharmony_ci 1803f9f848faSopenharmony_cistatic void 1804f9f848faSopenharmony_ciumass_t_cbi_reset2_callback(struct usb_xfer *xfer, usb_error_t error) 1805f9f848faSopenharmony_ci{ 1806f9f848faSopenharmony_ci umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_RESET3, 1807f9f848faSopenharmony_ci UMASS_T_CBI_DATA_READ, error); 1808f9f848faSopenharmony_ci} 1809f9f848faSopenharmony_ci 1810f9f848faSopenharmony_cistatic void 1811f9f848faSopenharmony_ciumass_t_cbi_reset3_callback(struct usb_xfer *xfer, usb_error_t error) 1812f9f848faSopenharmony_ci{ 1813f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1814f9f848faSopenharmony_ci 1815f9f848faSopenharmony_ci umass_t_cbi_data_clear_stall_callback 1816f9f848faSopenharmony_ci (xfer, (sc->sc_xfer[UMASS_T_CBI_RESET4] && 1817f9f848faSopenharmony_ci sc->sc_xfer[UMASS_T_CBI_STATUS]) ? 1818f9f848faSopenharmony_ci UMASS_T_CBI_RESET4 : UMASS_T_CBI_COMMAND, 1819f9f848faSopenharmony_ci UMASS_T_CBI_DATA_WRITE, error); 1820f9f848faSopenharmony_ci} 1821f9f848faSopenharmony_ci 1822f9f848faSopenharmony_cistatic void 1823f9f848faSopenharmony_ciumass_t_cbi_reset4_callback(struct usb_xfer *xfer, usb_error_t error) 1824f9f848faSopenharmony_ci{ 1825f9f848faSopenharmony_ci umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_COMMAND, 1826f9f848faSopenharmony_ci UMASS_T_CBI_STATUS, error); 1827f9f848faSopenharmony_ci} 1828f9f848faSopenharmony_ci 1829f9f848faSopenharmony_cistatic void 1830f9f848faSopenharmony_ciumass_t_cbi_data_clear_stall_callback(struct usb_xfer *xfer, 1831f9f848faSopenharmony_ci uint8_t next_xfer, uint8_t stall_xfer, usb_error_t error) 1832f9f848faSopenharmony_ci{ 1833f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1834f9f848faSopenharmony_ci 1835f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1836f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1837f9f848faSopenharmony_citr_transferred: 1838f9f848faSopenharmony_ci if (next_xfer == UMASS_T_CBI_STATUS) { 1839f9f848faSopenharmony_ci umass_cbi_start_status(sc); 1840f9f848faSopenharmony_ci } else { 1841f9f848faSopenharmony_ci umass_transfer_start(sc, next_xfer); 1842f9f848faSopenharmony_ci } 1843f9f848faSopenharmony_ci break; 1844f9f848faSopenharmony_ci 1845f9f848faSopenharmony_ci case USB_ST_SETUP: 1846f9f848faSopenharmony_ci if (usbd_clear_stall_callback(xfer, sc->sc_xfer[stall_xfer])) { 1847f9f848faSopenharmony_ci goto tr_transferred; /* should not happen */ 1848f9f848faSopenharmony_ci } 1849f9f848faSopenharmony_ci break; 1850f9f848faSopenharmony_ci 1851f9f848faSopenharmony_ci default: /* Error */ 1852f9f848faSopenharmony_ci umass_tr_error(xfer, error); 1853f9f848faSopenharmony_ci break; 1854f9f848faSopenharmony_ci } 1855f9f848faSopenharmony_ci} 1856f9f848faSopenharmony_ci 1857f9f848faSopenharmony_cistatic void 1858f9f848faSopenharmony_ciumass_t_cbi_command_callback(struct usb_xfer *xfer, usb_error_t error) 1859f9f848faSopenharmony_ci{ 1860f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1861f9f848faSopenharmony_ci union ccb *umass_ccb = sc->sc_transfer.ccb; 1862f9f848faSopenharmony_ci struct usb_device_request req; 1863f9f848faSopenharmony_ci struct usb_page_cache *pc; 1864f9f848faSopenharmony_ci 1865f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1866f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1867f9f848faSopenharmony_ci 1868f9f848faSopenharmony_ci if (sc->sc_transfer.dir == DIR_NONE) { 1869f9f848faSopenharmony_ci umass_cbi_start_status(sc); 1870f9f848faSopenharmony_ci } else { 1871f9f848faSopenharmony_ci umass_transfer_start 1872f9f848faSopenharmony_ci (sc, (sc->sc_transfer.dir == DIR_IN) ? 1873f9f848faSopenharmony_ci UMASS_T_CBI_DATA_READ : UMASS_T_CBI_DATA_WRITE); 1874f9f848faSopenharmony_ci } 1875f9f848faSopenharmony_ci break; 1876f9f848faSopenharmony_ci 1877f9f848faSopenharmony_ci case USB_ST_SETUP: 1878f9f848faSopenharmony_ci 1879f9f848faSopenharmony_ci if (umass_ccb) { 1880f9f848faSopenharmony_ci /* 1881f9f848faSopenharmony_ci * do a CBI transfer with cmd_len bytes from 1882f9f848faSopenharmony_ci * cmd_data, possibly a data phase of data_len 1883f9f848faSopenharmony_ci * bytes from/to the device and finally a status 1884f9f848faSopenharmony_ci * read phase. 1885f9f848faSopenharmony_ci */ 1886f9f848faSopenharmony_ci 1887f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 1888f9f848faSopenharmony_ci req.bRequest = UR_CBI_ADSC; 1889f9f848faSopenharmony_ci USETW(req.wValue, 0); 1890f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_iface_no; 1891f9f848faSopenharmony_ci req.wIndex[1] = 0; 1892f9f848faSopenharmony_ci req.wLength[0] = sc->sc_transfer.cmd_len; 1893f9f848faSopenharmony_ci req.wLength[1] = 0; 1894f9f848faSopenharmony_ci 1895f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 0); 1896f9f848faSopenharmony_ci usbd_copy_in(pc, 0, &req, sizeof(req)); 1897f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 1); 1898f9f848faSopenharmony_ci usbd_copy_in(pc, 0, sc->sc_transfer.cmd_data, 1899f9f848faSopenharmony_ci sc->sc_transfer.cmd_len); 1900f9f848faSopenharmony_ci 1901f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 1902f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 1, sc->sc_transfer.cmd_len); 1903f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 1904f9f848faSopenharmony_ci sc->sc_transfer.cmd_len ? 2 : 1); 1905f9f848faSopenharmony_ci 1906f9f848faSopenharmony_ci DIF(UDMASS_CBI, 1907f9f848faSopenharmony_ci umass_cbi_dump_cmd(sc, 1908f9f848faSopenharmony_ci sc->sc_transfer.cmd_data, 1909f9f848faSopenharmony_ci sc->sc_transfer.cmd_len)); 1910f9f848faSopenharmony_ci 1911f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1912f9f848faSopenharmony_ci } 1913f9f848faSopenharmony_ci break; 1914f9f848faSopenharmony_ci 1915f9f848faSopenharmony_ci default: /* Error */ 1916f9f848faSopenharmony_ci /* 1917f9f848faSopenharmony_ci * STALL on the control pipe can be result of the command error. 1918f9f848faSopenharmony_ci * Attempt to clear this STALL same as for bulk pipe also 1919f9f848faSopenharmony_ci * results in command completion interrupt, but ASC/ASCQ there 1920f9f848faSopenharmony_ci * look like not always valid, so don't bother about it. 1921f9f848faSopenharmony_ci */ 1922f9f848faSopenharmony_ci if ((error == USB_ERR_STALLED) || 1923f9f848faSopenharmony_ci (sc->sc_transfer.callback == &umass_cam_cb)) { 1924f9f848faSopenharmony_ci sc->sc_transfer.ccb = NULL; 1925f9f848faSopenharmony_ci (sc->sc_transfer.callback) 1926f9f848faSopenharmony_ci (sc, umass_ccb, sc->sc_transfer.data_len, 1927f9f848faSopenharmony_ci STATUS_CMD_UNKNOWN); 1928f9f848faSopenharmony_ci } else { 1929f9f848faSopenharmony_ci umass_tr_error(xfer, error); 1930f9f848faSopenharmony_ci /* skip reset */ 1931f9f848faSopenharmony_ci sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND; 1932f9f848faSopenharmony_ci } 1933f9f848faSopenharmony_ci break; 1934f9f848faSopenharmony_ci } 1935f9f848faSopenharmony_ci} 1936f9f848faSopenharmony_ci 1937f9f848faSopenharmony_cistatic void 1938f9f848faSopenharmony_ciumass_t_cbi_data_read_callback(struct usb_xfer *xfer, usb_error_t error) 1939f9f848faSopenharmony_ci{ 1940f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1941f9f848faSopenharmony_ci uint32_t max_bulk = usbd_xfer_max_len(xfer); 1942f9f848faSopenharmony_ci int actlen, sumlen; 1943f9f848faSopenharmony_ci 1944f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 1945f9f848faSopenharmony_ci 1946f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1947f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1948f9f848faSopenharmony_ci sc->sc_transfer.data_rem -= actlen; 1949f9f848faSopenharmony_ci sc->sc_transfer.data_ptr += actlen; 1950f9f848faSopenharmony_ci sc->sc_transfer.actlen += actlen; 1951f9f848faSopenharmony_ci 1952f9f848faSopenharmony_ci if (actlen < sumlen) { 1953f9f848faSopenharmony_ci /* short transfer */ 1954f9f848faSopenharmony_ci sc->sc_transfer.data_rem = 0; 1955f9f848faSopenharmony_ci } 1956f9f848faSopenharmony_ci case USB_ST_SETUP: 1957f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n", 1958f9f848faSopenharmony_ci max_bulk, sc->sc_transfer.data_rem); 1959f9f848faSopenharmony_ci 1960f9f848faSopenharmony_ci if (sc->sc_transfer.data_rem == 0) { 1961f9f848faSopenharmony_ci umass_cbi_start_status(sc); 1962f9f848faSopenharmony_ci break; 1963f9f848faSopenharmony_ci } 1964f9f848faSopenharmony_ci if (max_bulk > sc->sc_transfer.data_rem) { 1965f9f848faSopenharmony_ci max_bulk = sc->sc_transfer.data_rem; 1966f9f848faSopenharmony_ci } 1967f9f848faSopenharmony_ci usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); 1968f9f848faSopenharmony_ci 1969f9f848faSopenharmony_ci usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, 1970f9f848faSopenharmony_ci max_bulk); 1971f9f848faSopenharmony_ci 1972f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1973f9f848faSopenharmony_ci break; 1974f9f848faSopenharmony_ci 1975f9f848faSopenharmony_ci default: /* Error */ 1976f9f848faSopenharmony_ci if ((error == USB_ERR_CANCELLED) || 1977f9f848faSopenharmony_ci (sc->sc_transfer.callback != &umass_cam_cb)) { 1978f9f848faSopenharmony_ci umass_tr_error(xfer, error); 1979f9f848faSopenharmony_ci } else { 1980f9f848faSopenharmony_ci umass_transfer_start(sc, UMASS_T_CBI_DATA_RD_CS); 1981f9f848faSopenharmony_ci } 1982f9f848faSopenharmony_ci break; 1983f9f848faSopenharmony_ci } 1984f9f848faSopenharmony_ci} 1985f9f848faSopenharmony_ci 1986f9f848faSopenharmony_cistatic void 1987f9f848faSopenharmony_ciumass_t_cbi_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error) 1988f9f848faSopenharmony_ci{ 1989f9f848faSopenharmony_ci umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS, 1990f9f848faSopenharmony_ci UMASS_T_CBI_DATA_READ, error); 1991f9f848faSopenharmony_ci} 1992f9f848faSopenharmony_ci 1993f9f848faSopenharmony_cistatic void 1994f9f848faSopenharmony_ciumass_t_cbi_data_write_callback(struct usb_xfer *xfer, usb_error_t error) 1995f9f848faSopenharmony_ci{ 1996f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 1997f9f848faSopenharmony_ci uint32_t max_bulk = usbd_xfer_max_len(xfer); 1998f9f848faSopenharmony_ci int actlen, sumlen; 1999f9f848faSopenharmony_ci 2000f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 2001f9f848faSopenharmony_ci 2002f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 2003f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 2004f9f848faSopenharmony_ci sc->sc_transfer.data_rem -= actlen; 2005f9f848faSopenharmony_ci sc->sc_transfer.data_ptr += actlen; 2006f9f848faSopenharmony_ci sc->sc_transfer.actlen += actlen; 2007f9f848faSopenharmony_ci 2008f9f848faSopenharmony_ci if (actlen < sumlen) { 2009f9f848faSopenharmony_ci /* short transfer */ 2010f9f848faSopenharmony_ci sc->sc_transfer.data_rem = 0; 2011f9f848faSopenharmony_ci } 2012f9f848faSopenharmony_ci case USB_ST_SETUP: 2013f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_CBI, "max_bulk=%d, data_rem=%d\n", 2014f9f848faSopenharmony_ci max_bulk, sc->sc_transfer.data_rem); 2015f9f848faSopenharmony_ci 2016f9f848faSopenharmony_ci if (sc->sc_transfer.data_rem == 0) { 2017f9f848faSopenharmony_ci umass_cbi_start_status(sc); 2018f9f848faSopenharmony_ci break; 2019f9f848faSopenharmony_ci } 2020f9f848faSopenharmony_ci if (max_bulk > sc->sc_transfer.data_rem) { 2021f9f848faSopenharmony_ci max_bulk = sc->sc_transfer.data_rem; 2022f9f848faSopenharmony_ci } 2023f9f848faSopenharmony_ci usbd_xfer_set_timeout(xfer, sc->sc_transfer.data_timeout); 2024f9f848faSopenharmony_ci 2025f9f848faSopenharmony_ci usbd_xfer_set_frame_data(xfer, 0, sc->sc_transfer.data_ptr, 2026f9f848faSopenharmony_ci max_bulk); 2027f9f848faSopenharmony_ci 2028f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 2029f9f848faSopenharmony_ci break; 2030f9f848faSopenharmony_ci 2031f9f848faSopenharmony_ci default: /* Error */ 2032f9f848faSopenharmony_ci if ((error == USB_ERR_CANCELLED) || 2033f9f848faSopenharmony_ci (sc->sc_transfer.callback != &umass_cam_cb)) { 2034f9f848faSopenharmony_ci umass_tr_error(xfer, error); 2035f9f848faSopenharmony_ci } else { 2036f9f848faSopenharmony_ci umass_transfer_start(sc, UMASS_T_CBI_DATA_WR_CS); 2037f9f848faSopenharmony_ci } 2038f9f848faSopenharmony_ci break; 2039f9f848faSopenharmony_ci } 2040f9f848faSopenharmony_ci} 2041f9f848faSopenharmony_ci 2042f9f848faSopenharmony_cistatic void 2043f9f848faSopenharmony_ciumass_t_cbi_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error) 2044f9f848faSopenharmony_ci{ 2045f9f848faSopenharmony_ci umass_t_cbi_data_clear_stall_callback(xfer, UMASS_T_CBI_STATUS, 2046f9f848faSopenharmony_ci UMASS_T_CBI_DATA_WRITE, error); 2047f9f848faSopenharmony_ci} 2048f9f848faSopenharmony_ci 2049f9f848faSopenharmony_cistatic void 2050f9f848faSopenharmony_ciumass_t_cbi_status_callback(struct usb_xfer *xfer, usb_error_t error) 2051f9f848faSopenharmony_ci{ 2052f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)usbd_xfer_softc(xfer); 2053f9f848faSopenharmony_ci union ccb *umass_ccb = sc->sc_transfer.ccb; 2054f9f848faSopenharmony_ci struct usb_page_cache *pc; 2055f9f848faSopenharmony_ci uint32_t residue; 2056f9f848faSopenharmony_ci uint8_t status; 2057f9f848faSopenharmony_ci int actlen; 2058f9f848faSopenharmony_ci 2059f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 2060f9f848faSopenharmony_ci 2061f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 2062f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 2063f9f848faSopenharmony_ci 2064f9f848faSopenharmony_ci if (actlen < (int)sizeof(sc->sbl)) { 2065f9f848faSopenharmony_ci goto tr_setup; 2066f9f848faSopenharmony_ci } 2067f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 0); 2068f9f848faSopenharmony_ci usbd_copy_out(pc, 0, &sc->sbl, sizeof(sc->sbl)); 2069f9f848faSopenharmony_ci 2070f9f848faSopenharmony_ci residue = (sc->sc_transfer.data_len - 2071f9f848faSopenharmony_ci sc->sc_transfer.actlen); 2072f9f848faSopenharmony_ci 2073f9f848faSopenharmony_ci /* dissect the information in the buffer */ 2074f9f848faSopenharmony_ci 2075f9f848faSopenharmony_ci if (sc->sc_proto & UMASS_PROTO_UFI) { 2076f9f848faSopenharmony_ci /* 2077f9f848faSopenharmony_ci * Section 3.4.3.1.3 specifies that the UFI command 2078f9f848faSopenharmony_ci * protocol returns an ASC and ASCQ in the interrupt 2079f9f848faSopenharmony_ci * data block. 2080f9f848faSopenharmony_ci */ 2081f9f848faSopenharmony_ci 2082f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_CBI, "UFI CCI, ASC = 0x%02x, " 2083f9f848faSopenharmony_ci "ASCQ = 0x%02x\n", sc->sbl.ufi.asc, 2084f9f848faSopenharmony_ci sc->sbl.ufi.ascq); 2085f9f848faSopenharmony_ci 2086f9f848faSopenharmony_ci status = (((sc->sbl.ufi.asc == 0) && 2087f9f848faSopenharmony_ci (sc->sbl.ufi.ascq == 0)) ? 2088f9f848faSopenharmony_ci STATUS_CMD_OK : STATUS_CMD_FAILED); 2089f9f848faSopenharmony_ci 2090f9f848faSopenharmony_ci sc->sc_transfer.ccb = NULL; 2091f9f848faSopenharmony_ci 2092f9f848faSopenharmony_ci sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND; 2093f9f848faSopenharmony_ci 2094f9f848faSopenharmony_ci (sc->sc_transfer.callback) 2095f9f848faSopenharmony_ci (sc, umass_ccb, residue, status); 2096f9f848faSopenharmony_ci 2097f9f848faSopenharmony_ci break; 2098f9f848faSopenharmony_ci 2099f9f848faSopenharmony_ci } else { 2100f9f848faSopenharmony_ci /* Command Interrupt Data Block */ 2101f9f848faSopenharmony_ci 2102f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_CBI, "type=0x%02x, value=0x%02x\n", 2103f9f848faSopenharmony_ci sc->sbl.common.type, sc->sbl.common.value); 2104f9f848faSopenharmony_ci 2105f9f848faSopenharmony_ci if (sc->sbl.common.type == IDB_TYPE_CCI) { 2106f9f848faSopenharmony_ci status = (sc->sbl.common.value & IDB_VALUE_STATUS_MASK); 2107f9f848faSopenharmony_ci 2108f9f848faSopenharmony_ci status = ((status == IDB_VALUE_PASS) ? STATUS_CMD_OK : 2109f9f848faSopenharmony_ci (status == IDB_VALUE_FAIL) ? STATUS_CMD_FAILED : 2110f9f848faSopenharmony_ci (status == IDB_VALUE_PERSISTENT) ? STATUS_CMD_FAILED : 2111f9f848faSopenharmony_ci STATUS_WIRE_FAILED); 2112f9f848faSopenharmony_ci 2113f9f848faSopenharmony_ci sc->sc_transfer.ccb = NULL; 2114f9f848faSopenharmony_ci 2115f9f848faSopenharmony_ci sc->sc_last_xfer_index = UMASS_T_CBI_COMMAND; 2116f9f848faSopenharmony_ci 2117f9f848faSopenharmony_ci (sc->sc_transfer.callback) 2118f9f848faSopenharmony_ci (sc, umass_ccb, residue, status); 2119f9f848faSopenharmony_ci 2120f9f848faSopenharmony_ci break; 2121f9f848faSopenharmony_ci } 2122f9f848faSopenharmony_ci } 2123f9f848faSopenharmony_ci 2124f9f848faSopenharmony_ci /* fallthrough */ 2125f9f848faSopenharmony_ci 2126f9f848faSopenharmony_ci case USB_ST_SETUP: 2127f9f848faSopenharmony_citr_setup: 2128f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 2129f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 2130f9f848faSopenharmony_ci break; 2131f9f848faSopenharmony_ci 2132f9f848faSopenharmony_ci default: /* Error */ 2133f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_CBI, "Failed to read CSW: %s\n", 2134f9f848faSopenharmony_ci usbd_errstr(error)); 2135f9f848faSopenharmony_ci umass_tr_error(xfer, error); 2136f9f848faSopenharmony_ci break; 2137f9f848faSopenharmony_ci } 2138f9f848faSopenharmony_ci} 2139f9f848faSopenharmony_ci 2140f9f848faSopenharmony_ci/* umass_cam_cb 2141f9f848faSopenharmony_ci * finalise a completed CAM command 2142f9f848faSopenharmony_ci */ 2143f9f848faSopenharmony_ci 2144f9f848faSopenharmony_cistatic void 2145f9f848faSopenharmony_ciumass_cam_cb(struct umass_softc *sc, union ccb *umass_ccb, uint32_t residue, 2146f9f848faSopenharmony_ci uint8_t status) 2147f9f848faSopenharmony_ci{ 2148f9f848faSopenharmony_ci umass_ccb->csio.resid = residue; 2149f9f848faSopenharmony_ci umass_ccb->csio.status = status; 2150f9f848faSopenharmony_ci 2151f9f848faSopenharmony_ci switch (status) { 2152f9f848faSopenharmony_ci case STATUS_CMD_OK: 2153f9f848faSopenharmony_ci (void)LOS_EventWrite(&sc->sc_event, 0x01); 2154f9f848faSopenharmony_ci break; 2155f9f848faSopenharmony_ci 2156f9f848faSopenharmony_ci case STATUS_CMD_UNKNOWN: 2157f9f848faSopenharmony_ci case STATUS_CMD_FAILED: 2158f9f848faSopenharmony_ci /* fetch sense data */ 2159f9f848faSopenharmony_ci (void)LOS_EventWrite(&sc->sc_event, 0x02); 2160f9f848faSopenharmony_ci break; 2161f9f848faSopenharmony_ci 2162f9f848faSopenharmony_ci default: 2163f9f848faSopenharmony_ci (void)LOS_EventWrite(&sc->sc_event, 0x04); 2164f9f848faSopenharmony_ci break; 2165f9f848faSopenharmony_ci } 2166f9f848faSopenharmony_ci} 2167f9f848faSopenharmony_ci 2168f9f848faSopenharmony_ci/* 2169f9f848faSopenharmony_ci * SCSI specific functions 2170f9f848faSopenharmony_ci */ 2171f9f848faSopenharmony_ci 2172f9f848faSopenharmony_cistatic uint8_t 2173f9f848faSopenharmony_ciumass_scsi_transform(struct umass_softc *sc, uint8_t *cmd_ptr, 2174f9f848faSopenharmony_ci uint8_t cmd_len) 2175f9f848faSopenharmony_ci{ 2176f9f848faSopenharmony_ci int ret; 2177f9f848faSopenharmony_ci 2178f9f848faSopenharmony_ci if ((cmd_len == 0) || 2179f9f848faSopenharmony_ci (cmd_len > sizeof(sc->sc_transfer.cmd_data))) { 2180f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_SCSI, "Invalid command " 2181f9f848faSopenharmony_ci "length: %d bytes\n", cmd_len); 2182f9f848faSopenharmony_ci return (0); /* failure */ 2183f9f848faSopenharmony_ci } 2184f9f848faSopenharmony_ci sc->sc_transfer.cmd_len = cmd_len; 2185f9f848faSopenharmony_ci 2186f9f848faSopenharmony_ci switch (cmd_ptr[0]) { 2187f9f848faSopenharmony_ci case TEST_UNIT_READY: 2188f9f848faSopenharmony_ci if (sc->sc_quirks & NO_TEST_UNIT_READY) { 2189f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY " 2190f9f848faSopenharmony_ci "to START_UNIT\n"); 2191f9f848faSopenharmony_ci ret = memset_s(sc->sc_transfer.cmd_data, sizeof(sc->sc_transfer.cmd_data), 0, cmd_len); 2192f9f848faSopenharmony_ci if (ret != EOK) { 2193f9f848faSopenharmony_ci usb_err("memset_s failed!, ret:%d\n", ret); 2194f9f848faSopenharmony_ci return (0); 2195f9f848faSopenharmony_ci } 2196f9f848faSopenharmony_ci sc->sc_transfer.cmd_data[0] = START_STOP_UNIT; 2197f9f848faSopenharmony_ci sc->sc_transfer.cmd_data[4] = SSS_START; 2198f9f848faSopenharmony_ci return (1); 2199f9f848faSopenharmony_ci } 2200f9f848faSopenharmony_ci break; 2201f9f848faSopenharmony_ci 2202f9f848faSopenharmony_ci case INQUIRY: 2203f9f848faSopenharmony_ci /* 2204f9f848faSopenharmony_ci * some drives wedge when asked for full inquiry 2205f9f848faSopenharmony_ci * information. 2206f9f848faSopenharmony_ci */ 2207f9f848faSopenharmony_ci if (sc->sc_quirks & FORCE_SHORT_INQUIRY) { 2208f9f848faSopenharmony_ci ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len); 2209f9f848faSopenharmony_ci if (ret != EOK) { 2210f9f848faSopenharmony_ci usb_err("memcpy_s failed!, ret:%d\n", ret); 2211f9f848faSopenharmony_ci return (0); 2212f9f848faSopenharmony_ci } 2213f9f848faSopenharmony_ci sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH; 2214f9f848faSopenharmony_ci return (1); 2215f9f848faSopenharmony_ci } 2216f9f848faSopenharmony_ci break; 2217f9f848faSopenharmony_ci } 2218f9f848faSopenharmony_ci 2219f9f848faSopenharmony_ci ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len); 2220f9f848faSopenharmony_ci if (ret != EOK) { 2221f9f848faSopenharmony_ci usb_err("memcpy_s failed!, ret:%d\n", ret); 2222f9f848faSopenharmony_ci return (0); 2223f9f848faSopenharmony_ci } 2224f9f848faSopenharmony_ci 2225f9f848faSopenharmony_ci return (1); 2226f9f848faSopenharmony_ci} 2227f9f848faSopenharmony_ci 2228f9f848faSopenharmony_cistatic uint8_t 2229f9f848faSopenharmony_ciumass_rbc_transform(struct umass_softc *sc, uint8_t *cmd_ptr, uint8_t cmd_len) 2230f9f848faSopenharmony_ci{ 2231f9f848faSopenharmony_ci int ret; 2232f9f848faSopenharmony_ci 2233f9f848faSopenharmony_ci if ((cmd_len == 0) || 2234f9f848faSopenharmony_ci (cmd_len > sizeof(sc->sc_transfer.cmd_data))) { 2235f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_SCSI, "Invalid command " 2236f9f848faSopenharmony_ci "length: %d bytes\n", cmd_len); 2237f9f848faSopenharmony_ci return (0); /* failure */ 2238f9f848faSopenharmony_ci } 2239f9f848faSopenharmony_ci switch (cmd_ptr[0]) { 2240f9f848faSopenharmony_ci /* these commands are defined in RBC: */ 2241f9f848faSopenharmony_ci case READ_10: 2242f9f848faSopenharmony_ci case READ_CAPACITY: 2243f9f848faSopenharmony_ci case START_STOP_UNIT: 2244f9f848faSopenharmony_ci case SYNCHRONIZE_CACHE: 2245f9f848faSopenharmony_ci case WRITE_10: 2246f9f848faSopenharmony_ci case 0x2f: /* VERIFY_10 is absent from * scsi_all.h??? */ 2247f9f848faSopenharmony_ci case INQUIRY: 2248f9f848faSopenharmony_ci case MODE_SELECT_10: 2249f9f848faSopenharmony_ci case MODE_SENSE_10: 2250f9f848faSopenharmony_ci case TEST_UNIT_READY: 2251f9f848faSopenharmony_ci case WRITE_BUFFER: 2252f9f848faSopenharmony_ci /* 2253f9f848faSopenharmony_ci * The following commands are not listed in my copy of the 2254f9f848faSopenharmony_ci * RBC specs. CAM however seems to want those, and at least 2255f9f848faSopenharmony_ci * the Sony DSC device appears to support those as well 2256f9f848faSopenharmony_ci */ 2257f9f848faSopenharmony_ci case REQUEST_SENSE: 2258f9f848faSopenharmony_ci case PREVENT_ALLOW: 2259f9f848faSopenharmony_ci 2260f9f848faSopenharmony_ci ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len); 2261f9f848faSopenharmony_ci if (ret != EOK) { 2262f9f848faSopenharmony_ci usb_err("memcpy_s failed!, ret:%d\n", ret); 2263f9f848faSopenharmony_ci return (0); 2264f9f848faSopenharmony_ci } 2265f9f848faSopenharmony_ci 2266f9f848faSopenharmony_ci if ((sc->sc_quirks & RBC_PAD_TO_12) && (cmd_len < 12)) { 2267f9f848faSopenharmony_ci ret = memset_s(sc->sc_transfer.cmd_data + cmd_len, 2268f9f848faSopenharmony_ci (size_t)(UMASS_MAX_CMDLEN - cmd_len), 0, (size_t)(12 - cmd_len)); 2269f9f848faSopenharmony_ci if (ret != EOK){ 2270f9f848faSopenharmony_ci usb_err("memset_s failed!, ret:%d\n", ret); 2271f9f848faSopenharmony_ci return (0); 2272f9f848faSopenharmony_ci } 2273f9f848faSopenharmony_ci cmd_len = 12; 2274f9f848faSopenharmony_ci } 2275f9f848faSopenharmony_ci sc->sc_transfer.cmd_len = cmd_len; 2276f9f848faSopenharmony_ci return (1); /* sucess */ 2277f9f848faSopenharmony_ci 2278f9f848faSopenharmony_ci /* All other commands are not legal in RBC */ 2279f9f848faSopenharmony_ci default: 2280f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_SCSI, "Unsupported RBC " 2281f9f848faSopenharmony_ci "command 0x%02x\n", cmd_ptr[0]); 2282f9f848faSopenharmony_ci return (0); /* failure */ 2283f9f848faSopenharmony_ci } 2284f9f848faSopenharmony_ci} 2285f9f848faSopenharmony_ci 2286f9f848faSopenharmony_cistatic uint8_t 2287f9f848faSopenharmony_ciumass_ufi_transform(struct umass_softc *sc, uint8_t *cmd_ptr, 2288f9f848faSopenharmony_ci uint8_t cmd_len) 2289f9f848faSopenharmony_ci{ 2290f9f848faSopenharmony_ci int ret; 2291f9f848faSopenharmony_ci 2292f9f848faSopenharmony_ci if ((cmd_len == 0) || 2293f9f848faSopenharmony_ci (cmd_len > sizeof(sc->sc_transfer.cmd_data))) { 2294f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_SCSI, "Invalid command " 2295f9f848faSopenharmony_ci "length: %d bytes\n", cmd_len); 2296f9f848faSopenharmony_ci return (0); /* failure */ 2297f9f848faSopenharmony_ci } 2298f9f848faSopenharmony_ci /* An UFI command is always 12 bytes in length */ 2299f9f848faSopenharmony_ci sc->sc_transfer.cmd_len = UFI_COMMAND_LENGTH; 2300f9f848faSopenharmony_ci 2301f9f848faSopenharmony_ci /* Zero the command data */ 2302f9f848faSopenharmony_ci ret = memset_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, 0, UFI_COMMAND_LENGTH); 2303f9f848faSopenharmony_ci if (ret != EOK) { 2304f9f848faSopenharmony_ci usb_err("memset_s failed!, ret:%d\n", ret); 2305f9f848faSopenharmony_ci return (0); 2306f9f848faSopenharmony_ci } 2307f9f848faSopenharmony_ci 2308f9f848faSopenharmony_ci switch (cmd_ptr[0]) { 2309f9f848faSopenharmony_ci /* 2310f9f848faSopenharmony_ci * Commands of which the format has been verified. They 2311f9f848faSopenharmony_ci * should work. Copy the command into the (zeroed out) 2312f9f848faSopenharmony_ci * destination buffer. 2313f9f848faSopenharmony_ci */ 2314f9f848faSopenharmony_ci case TEST_UNIT_READY: 2315f9f848faSopenharmony_ci if (sc->sc_quirks & NO_TEST_UNIT_READY) { 2316f9f848faSopenharmony_ci /* 2317f9f848faSopenharmony_ci * Some devices do not support this command. Start 2318f9f848faSopenharmony_ci * Stop Unit should give the same results 2319f9f848faSopenharmony_ci */ 2320f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_UFI, "Converted TEST_UNIT_READY " 2321f9f848faSopenharmony_ci "to START_UNIT\n"); 2322f9f848faSopenharmony_ci 2323f9f848faSopenharmony_ci sc->sc_transfer.cmd_data[0] = START_STOP_UNIT; 2324f9f848faSopenharmony_ci sc->sc_transfer.cmd_data[4] = SSS_START; 2325f9f848faSopenharmony_ci return (1); 2326f9f848faSopenharmony_ci } 2327f9f848faSopenharmony_ci break; 2328f9f848faSopenharmony_ci 2329f9f848faSopenharmony_ci case REZERO_UNIT: 2330f9f848faSopenharmony_ci case REQUEST_SENSE: 2331f9f848faSopenharmony_ci case FORMAT_UNIT: 2332f9f848faSopenharmony_ci case INQUIRY: 2333f9f848faSopenharmony_ci case START_STOP_UNIT: 2334f9f848faSopenharmony_ci case SEND_DIAGNOSTIC: 2335f9f848faSopenharmony_ci case PREVENT_ALLOW: 2336f9f848faSopenharmony_ci case READ_CAPACITY: 2337f9f848faSopenharmony_ci case READ_10: 2338f9f848faSopenharmony_ci case WRITE_10: 2339f9f848faSopenharmony_ci case POSITION_TO_ELEMENT: /* SEEK_10 */ 2340f9f848faSopenharmony_ci case WRITE_AND_VERIFY: 2341f9f848faSopenharmony_ci case VERIFIED: 2342f9f848faSopenharmony_ci case MODE_SELECT_10: 2343f9f848faSopenharmony_ci case MODE_SENSE_10: 2344f9f848faSopenharmony_ci case READ_12: 2345f9f848faSopenharmony_ci case WRITE_12: 2346f9f848faSopenharmony_ci case READ_FORMAT_CAPACITIES: 2347f9f848faSopenharmony_ci break; 2348f9f848faSopenharmony_ci 2349f9f848faSopenharmony_ci /* 2350f9f848faSopenharmony_ci * SYNCHRONIZE_CACHE isn't supported by UFI, nor should it be 2351f9f848faSopenharmony_ci * required for UFI devices, so it is appropriate to fake 2352f9f848faSopenharmony_ci * success. 2353f9f848faSopenharmony_ci */ 2354f9f848faSopenharmony_ci case SYNCHRONIZE_CACHE: 2355f9f848faSopenharmony_ci return (2); 2356f9f848faSopenharmony_ci 2357f9f848faSopenharmony_ci default: 2358f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_SCSI, "Unsupported UFI " 2359f9f848faSopenharmony_ci "command 0x%02x\n", cmd_ptr[0]); 2360f9f848faSopenharmony_ci return (0); /* failure */ 2361f9f848faSopenharmony_ci } 2362f9f848faSopenharmony_ci 2363f9f848faSopenharmony_ci ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len); 2364f9f848faSopenharmony_ci if (ret != EOK) { 2365f9f848faSopenharmony_ci usb_err("memcpy_s failed!, ret:%d\n", ret); 2366f9f848faSopenharmony_ci return (0); 2367f9f848faSopenharmony_ci } 2368f9f848faSopenharmony_ci 2369f9f848faSopenharmony_ci return (1); /* success */ 2370f9f848faSopenharmony_ci} 2371f9f848faSopenharmony_ci 2372f9f848faSopenharmony_ci/* 2373f9f848faSopenharmony_ci * 8070i (ATAPI) specific functions 2374f9f848faSopenharmony_ci */ 2375f9f848faSopenharmony_cistatic uint8_t 2376f9f848faSopenharmony_ciumass_atapi_transform(struct umass_softc *sc, uint8_t *cmd_ptr, 2377f9f848faSopenharmony_ci uint8_t cmd_len) 2378f9f848faSopenharmony_ci{ 2379f9f848faSopenharmony_ci int ret; 2380f9f848faSopenharmony_ci 2381f9f848faSopenharmony_ci if ((cmd_len == 0) || 2382f9f848faSopenharmony_ci (cmd_len > sizeof(sc->sc_transfer.cmd_data))) { 2383f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_SCSI, "Invalid command " 2384f9f848faSopenharmony_ci "length: %d bytes\n", cmd_len); 2385f9f848faSopenharmony_ci return (0); /* failure */ 2386f9f848faSopenharmony_ci } 2387f9f848faSopenharmony_ci /* An ATAPI command is always 12 bytes in length. */ 2388f9f848faSopenharmony_ci sc->sc_transfer.cmd_len = ATAPI_COMMAND_LENGTH; 2389f9f848faSopenharmony_ci 2390f9f848faSopenharmony_ci /* Zero the command data */ 2391f9f848faSopenharmony_ci ret = memset_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, 0, ATAPI_COMMAND_LENGTH); 2392f9f848faSopenharmony_ci if (ret != EOK) { 2393f9f848faSopenharmony_ci usb_err("memset_s failed!, ret:%d\n", ret); 2394f9f848faSopenharmony_ci return (0); 2395f9f848faSopenharmony_ci } 2396f9f848faSopenharmony_ci 2397f9f848faSopenharmony_ci switch (cmd_ptr[0]) { 2398f9f848faSopenharmony_ci /* 2399f9f848faSopenharmony_ci * Commands of which the format has been verified. They 2400f9f848faSopenharmony_ci * should work. Copy the command into the destination 2401f9f848faSopenharmony_ci * buffer. 2402f9f848faSopenharmony_ci */ 2403f9f848faSopenharmony_ci case INQUIRY: 2404f9f848faSopenharmony_ci /* 2405f9f848faSopenharmony_ci * some drives wedge when asked for full inquiry 2406f9f848faSopenharmony_ci * information. 2407f9f848faSopenharmony_ci */ 2408f9f848faSopenharmony_ci if (sc->sc_quirks & FORCE_SHORT_INQUIRY) { 2409f9f848faSopenharmony_ci ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len); 2410f9f848faSopenharmony_ci if (ret != EOK) { 2411f9f848faSopenharmony_ci usb_err("memcpy_s failed!, ret:%d\n", ret); 2412f9f848faSopenharmony_ci return (0); 2413f9f848faSopenharmony_ci } 2414f9f848faSopenharmony_ci sc->sc_transfer.cmd_data[4] = SHORT_INQUIRY_LENGTH; 2415f9f848faSopenharmony_ci return (1); 2416f9f848faSopenharmony_ci } 2417f9f848faSopenharmony_ci break; 2418f9f848faSopenharmony_ci 2419f9f848faSopenharmony_ci case TEST_UNIT_READY: 2420f9f848faSopenharmony_ci if (sc->sc_quirks & NO_TEST_UNIT_READY) { 2421f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_SCSI, "Converted TEST_UNIT_READY " 2422f9f848faSopenharmony_ci "to START_UNIT\n"); 2423f9f848faSopenharmony_ci sc->sc_transfer.cmd_data[0] = START_STOP_UNIT; 2424f9f848faSopenharmony_ci sc->sc_transfer.cmd_data[4] = SSS_START; 2425f9f848faSopenharmony_ci return (1); 2426f9f848faSopenharmony_ci } 2427f9f848faSopenharmony_ci break; 2428f9f848faSopenharmony_ci 2429f9f848faSopenharmony_ci case REZERO_UNIT: 2430f9f848faSopenharmony_ci case REQUEST_SENSE: 2431f9f848faSopenharmony_ci case START_STOP_UNIT: 2432f9f848faSopenharmony_ci case SEND_DIAGNOSTIC: 2433f9f848faSopenharmony_ci case PREVENT_ALLOW: 2434f9f848faSopenharmony_ci case READ_CAPACITY: 2435f9f848faSopenharmony_ci case READ_10: 2436f9f848faSopenharmony_ci case WRITE_10: 2437f9f848faSopenharmony_ci case POSITION_TO_ELEMENT: /* SEEK_10 */ 2438f9f848faSopenharmony_ci case SYNCHRONIZE_CACHE: 2439f9f848faSopenharmony_ci case MODE_SELECT_10: 2440f9f848faSopenharmony_ci case MODE_SENSE_10: 2441f9f848faSopenharmony_ci case READ_BUFFER: 2442f9f848faSopenharmony_ci case 0x42: /* READ_SUBCHANNEL */ 2443f9f848faSopenharmony_ci case 0x43: /* READ_TOC */ 2444f9f848faSopenharmony_ci case 0x44: /* READ_HEADER */ 2445f9f848faSopenharmony_ci case 0x47: /* PLAY_MSF (Play Minute/Second/Frame) */ 2446f9f848faSopenharmony_ci case 0x48: /* PLAY_TRACK */ 2447f9f848faSopenharmony_ci case 0x49: /* PLAY_TRACK_REL */ 2448f9f848faSopenharmony_ci case 0x4b: /* PAUSE */ 2449f9f848faSopenharmony_ci case 0x51: /* READ_DISK_INFO */ 2450f9f848faSopenharmony_ci case 0x52: /* READ_TRACK_INFO */ 2451f9f848faSopenharmony_ci case 0x54: /* SEND_OPC */ 2452f9f848faSopenharmony_ci case 0x59: /* READ_MASTER_CUE */ 2453f9f848faSopenharmony_ci case 0x5b: /* CLOSE_TR_SESSION */ 2454f9f848faSopenharmony_ci case 0x5c: /* READ_BUFFER_CAP */ 2455f9f848faSopenharmony_ci case 0x5d: /* SEND_CUE_SHEET */ 2456f9f848faSopenharmony_ci case 0xa1: /* BLANK */ 2457f9f848faSopenharmony_ci case 0xa5: /* PLAY_12 */ 2458f9f848faSopenharmony_ci case 0xa6: /* EXCHANGE_MEDIUM */ 2459f9f848faSopenharmony_ci case 0xad: /* READ_DVD_STRUCTURE */ 2460f9f848faSopenharmony_ci case 0xbb: /* SET_CD_SPEED */ 2461f9f848faSopenharmony_ci case 0xe5: /* READ_TRACK_INFO_PHILIPS */ 2462f9f848faSopenharmony_ci break; 2463f9f848faSopenharmony_ci 2464f9f848faSopenharmony_ci case READ_12: 2465f9f848faSopenharmony_ci case WRITE_12: 2466f9f848faSopenharmony_ci default: 2467f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_SCSI, "Unsupported ATAPI " 2468f9f848faSopenharmony_ci "command 0x%02x - trying anyway\n", 2469f9f848faSopenharmony_ci cmd_ptr[0]); 2470f9f848faSopenharmony_ci break; 2471f9f848faSopenharmony_ci } 2472f9f848faSopenharmony_ci 2473f9f848faSopenharmony_ci ret = memcpy_s(sc->sc_transfer.cmd_data, UMASS_MAX_CMDLEN, cmd_ptr, cmd_len); 2474f9f848faSopenharmony_ci if (ret != EOK) { 2475f9f848faSopenharmony_ci usb_err("memcpy_s failed!, ret:%d\n", ret); 2476f9f848faSopenharmony_ci return (0); 2477f9f848faSopenharmony_ci } 2478f9f848faSopenharmony_ci 2479f9f848faSopenharmony_ci return (1); /* success */ 2480f9f848faSopenharmony_ci} 2481f9f848faSopenharmony_ci 2482f9f848faSopenharmony_cistatic uint8_t 2483f9f848faSopenharmony_ciumass_no_transform(struct umass_softc *sc, uint8_t *cmd, 2484f9f848faSopenharmony_ci uint8_t cmdlen) 2485f9f848faSopenharmony_ci{ 2486f9f848faSopenharmony_ci return (0); /* failure */ 2487f9f848faSopenharmony_ci} 2488f9f848faSopenharmony_ci 2489f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 2490f9f848faSopenharmony_cistatic void 2491f9f848faSopenharmony_ciumass_bbb_dump_cbw(struct umass_softc *sc, umass_bbb_cbw_t *cbw) 2492f9f848faSopenharmony_ci{ 2493f9f848faSopenharmony_ci uint8_t *c = cbw->CBWCDB; 2494f9f848faSopenharmony_ci 2495f9f848faSopenharmony_ci uint32_t dlen = UGETDW(cbw->dCBWDataTransferLength); 2496f9f848faSopenharmony_ci uint32_t tag = UGETDW(cbw->dCBWTag); 2497f9f848faSopenharmony_ci 2498f9f848faSopenharmony_ci uint8_t clen = cbw->bCDBLength; 2499f9f848faSopenharmony_ci uint8_t flags = cbw->bCBWFlags; 2500f9f848faSopenharmony_ci uint8_t lun = cbw->bCBWLUN; 2501f9f848faSopenharmony_ci 2502f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "CBW %d: cmd = %db " 2503f9f848faSopenharmony_ci "(0x%02x%02x%02x%02x%02x%02x%s), " 2504f9f848faSopenharmony_ci "data = %db, lun = %d, dir = %s\n", 2505f9f848faSopenharmony_ci tag, clen, 2506f9f848faSopenharmony_ci c[0], c[1], c[2], c[3], c[4], c[5], (clen > 6 ? "..." : ""), 2507f9f848faSopenharmony_ci dlen, lun, (flags == CBWFLAGS_IN ? "in" : 2508f9f848faSopenharmony_ci (flags == CBWFLAGS_OUT ? "out" : "<invalid>"))); 2509f9f848faSopenharmony_ci} 2510f9f848faSopenharmony_ci 2511f9f848faSopenharmony_cistatic void 2512f9f848faSopenharmony_ciumass_bbb_dump_csw(struct umass_softc *sc, umass_bbb_csw_t *csw) 2513f9f848faSopenharmony_ci{ 2514f9f848faSopenharmony_ci uint32_t sig = UGETDW(csw->dCSWSignature); 2515f9f848faSopenharmony_ci uint32_t tag = UGETDW(csw->dCSWTag); 2516f9f848faSopenharmony_ci uint32_t res = UGETDW(csw->dCSWDataResidue); 2517f9f848faSopenharmony_ci uint8_t status = csw->bCSWStatus; 2518f9f848faSopenharmony_ci 2519f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "CSW %d: sig = 0x%08x (%s), tag = 0x%08x, " 2520f9f848faSopenharmony_ci "res = %d, status = 0x%02x (%s)\n", 2521f9f848faSopenharmony_ci tag, sig, (sig == CSWSIGNATURE ? "valid" : "invalid"), 2522f9f848faSopenharmony_ci tag, res, 2523f9f848faSopenharmony_ci status, (status == CSWSTATUS_GOOD ? "good" : 2524f9f848faSopenharmony_ci (status == CSWSTATUS_FAILED ? "failed" : 2525f9f848faSopenharmony_ci (status == CSWSTATUS_PHASE ? "phase" : "<invalid>")))); 2526f9f848faSopenharmony_ci} 2527f9f848faSopenharmony_ci 2528f9f848faSopenharmony_cistatic void 2529f9f848faSopenharmony_ciumass_cbi_dump_cmd(struct umass_softc *sc, void *cmd, uint8_t cmdlen) 2530f9f848faSopenharmony_ci{ 2531f9f848faSopenharmony_ci uint8_t *c = cmd; 2532f9f848faSopenharmony_ci uint8_t dir = sc->sc_transfer.dir; 2533f9f848faSopenharmony_ci 2534f9f848faSopenharmony_ci DPRINTF_UMASS(sc, UDMASS_BBB, "cmd = %db " 2535f9f848faSopenharmony_ci "(0x%02x%02x%02x%02x%02x%02x%s), " 2536f9f848faSopenharmony_ci "data = %db, dir = %s\n", 2537f9f848faSopenharmony_ci cmdlen, 2538f9f848faSopenharmony_ci c[0], c[1], c[2], c[3], c[4], c[5], (cmdlen > 6 ? "..." : ""), 2539f9f848faSopenharmony_ci sc->sc_transfer.data_len, 2540f9f848faSopenharmony_ci (dir == DIR_IN ? "in" : 2541f9f848faSopenharmony_ci (dir == DIR_OUT ? "out" : 2542f9f848faSopenharmony_ci (dir == DIR_NONE ? "no data phase" : "<invalid>")))); 2543f9f848faSopenharmony_ci} 2544f9f848faSopenharmony_ci 2545f9f848faSopenharmony_ci#endif 2546f9f848faSopenharmony_ci 2547f9f848faSopenharmony_ci#define SCSI_INQ_LEN 0x24 2548f9f848faSopenharmony_ci 2549f9f848faSopenharmony_cistatic uint8_t scsi_test_unit_ready[] = { 2550f9f848faSopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 2551f9f848faSopenharmony_ci}; 2552f9f848faSopenharmony_cistatic uint8_t scsi_inquiry[] = { 2553f9f848faSopenharmony_ci 0x12, 0x00, 0x00, 0x00, SCSI_INQ_LEN, 0x00 2554f9f848faSopenharmony_ci}; 2555f9f848faSopenharmony_cistatic uint8_t scsi_request_sense[] = { 2556f9f848faSopenharmony_ci 0x03, 0x00, 0x00, 0x00, 0x12, 0x00, 2557f9f848faSopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 2558f9f848faSopenharmony_ci}; 2559f9f848faSopenharmony_cistatic uint8_t scsi_read_capacity[] = { 2560f9f848faSopenharmony_ci 0x25, 0x00, 0x00, 0x00, 0x00, 2561f9f848faSopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00 2562f9f848faSopenharmony_ci}; 2563f9f848faSopenharmony_ci 2564f9f848faSopenharmony_cistatic uint8_t scsi_read_capacity_16[] = { 2565f9f848faSopenharmony_ci 0x9e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2566f9f848faSopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00 2567f9f848faSopenharmony_ci}; 2568f9f848faSopenharmony_ci 2569f9f848faSopenharmony_ci/* Description: Get a (possibly unaligned) 16-bit big endian value. */ 2570f9f848faSopenharmony_cistatic inline uint16_t 2571f9f848faSopenharmony_ciusbhost_getbe16(const uint8_t *val) 2572f9f848faSopenharmony_ci{ 2573f9f848faSopenharmony_ci return ((uint16_t)val[0] << 8 | (uint16_t)val[1]); 2574f9f848faSopenharmony_ci} 2575f9f848faSopenharmony_ci 2576f9f848faSopenharmony_ci/* Description: Put a (possibly unaligned) 16-bit little endian value. */ 2577f9f848faSopenharmony_civoid 2578f9f848faSopenharmony_ciusbhost_putle16(uint8_t *dest, uint16_t val) 2579f9f848faSopenharmony_ci{ 2580f9f848faSopenharmony_ci dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */ 2581f9f848faSopenharmony_ci dest[1] = val >> 8; 2582f9f848faSopenharmony_ci} 2583f9f848faSopenharmony_ci 2584f9f848faSopenharmony_ci/* Description: Put a (possibly unaligned) 16-bit big endian value. */ 2585f9f848faSopenharmony_civoid 2586f9f848faSopenharmony_ciusbhost_putbe16(uint8_t *dest, uint16_t val) 2587f9f848faSopenharmony_ci{ 2588f9f848faSopenharmony_ci dest[0] = val >> 8; /* Big endian means MS byte first in byte stream */ 2589f9f848faSopenharmony_ci dest[1] = val & 0xff; 2590f9f848faSopenharmony_ci} 2591f9f848faSopenharmony_ci 2592f9f848faSopenharmony_ci/* Description: Get a (possibly unaligned) 32-bit big endian value. */ 2593f9f848faSopenharmony_ciuint32_t 2594f9f848faSopenharmony_ciusbhost_getbe32(const uint8_t *val) 2595f9f848faSopenharmony_ci{ 2596f9f848faSopenharmony_ci /* Big endian means MS halfword first in byte stream */ 2597f9f848faSopenharmony_ci return ((uint32_t)usbhost_getbe16(val) << 16 | 2598f9f848faSopenharmony_ci (uint32_t)usbhost_getbe16(&val[2])); 2599f9f848faSopenharmony_ci} 2600f9f848faSopenharmony_ci 2601f9f848faSopenharmony_ci/* Description: Get a (possibly unaligned) 64-bit big endian value. */ 2602f9f848faSopenharmony_ciuint64_t 2603f9f848faSopenharmony_ciusbhost_getbe64(const uint8_t *val) 2604f9f848faSopenharmony_ci{ 2605f9f848faSopenharmony_ci /* Big endian means MS halfword first in byte stream */ 2606f9f848faSopenharmony_ci return ((uint64_t)usbhost_getbe32(val) << 32 | 2607f9f848faSopenharmony_ci (uint64_t)usbhost_getbe32(&val[4])); 2608f9f848faSopenharmony_ci} 2609f9f848faSopenharmony_ci 2610f9f848faSopenharmony_ci/* Description: Put a (possibly unaligned) 32-bit little endian value. */ 2611f9f848faSopenharmony_civoid 2612f9f848faSopenharmony_ciusbhost_putle32(uint8_t *dest, uint32_t val) 2613f9f848faSopenharmony_ci{ 2614f9f848faSopenharmony_ci /* Little endian means LS halfword first in byte stream */ 2615f9f848faSopenharmony_ci usbhost_putle16(dest, (uint16_t)(val & 0xffff)); 2616f9f848faSopenharmony_ci usbhost_putle16(dest+2, (uint16_t)(val >> 16)); 2617f9f848faSopenharmony_ci} 2618f9f848faSopenharmony_ci 2619f9f848faSopenharmony_ci/* Put a (possibly unaligned) 32-bit big endian value. */ 2620f9f848faSopenharmony_civoid 2621f9f848faSopenharmony_ciusbhost_putbe32(uint8_t *dest, uint32_t val) 2622f9f848faSopenharmony_ci{ 2623f9f848faSopenharmony_ci /* Big endian means MS halfword first in byte stream */ 2624f9f848faSopenharmony_ci usbhost_putbe16(dest, (uint16_t)(val >> 16)); 2625f9f848faSopenharmony_ci usbhost_putbe16(dest+2, (uint16_t)(val & 0xffff)); 2626f9f848faSopenharmony_ci} 2627f9f848faSopenharmony_ci 2628f9f848faSopenharmony_ci/* Put a (possibly unaligned) 64-bit big endian value. */ 2629f9f848faSopenharmony_civoid 2630f9f848faSopenharmony_ciusbhost_putbe64(uint8_t *dest, uint64_t val) 2631f9f848faSopenharmony_ci{ 2632f9f848faSopenharmony_ci /* Big endian means MS halfword first in byte stream */ 2633f9f848faSopenharmony_ci usbhost_putbe32(dest, (uint32_t)(val >> 32)); 2634f9f848faSopenharmony_ci usbhost_putbe32(dest+4, (uint32_t)(val & 0xffffffff)); 2635f9f848faSopenharmony_ci} 2636f9f848faSopenharmony_ci 2637f9f848faSopenharmony_civoid 2638f9f848faSopenharmony_ciusbhost_readcdb16(uint64_t startsector, uint16_t blocksize, 2639f9f848faSopenharmony_ci unsigned int nsectors, struct scsicmd_read16_s *cdb) 2640f9f848faSopenharmony_ci{ 2641f9f848faSopenharmony_ci struct scsicmd_read16_s *rd16 = (struct scsicmd_read16_s *)cdb; 2642f9f848faSopenharmony_ci 2643f9f848faSopenharmony_ci /* Format the CDB */ 2644f9f848faSopenharmony_ci rd16->opcode = SCSI_CMD_READ16; 2645f9f848faSopenharmony_ci usbhost_putbe64(rd16->lba, startsector); 2646f9f848faSopenharmony_ci usbhost_putbe32(rd16->xfrlen, nsectors); 2647f9f848faSopenharmony_ci} 2648f9f848faSopenharmony_ci 2649f9f848faSopenharmony_civoid 2650f9f848faSopenharmony_ciusbhost_readcdb10(size_t startsector, uint16_t blocksize, 2651f9f848faSopenharmony_ci unsigned int nsectors, struct scsicmd_read10_s *cdb) 2652f9f848faSopenharmony_ci{ 2653f9f848faSopenharmony_ci struct scsicmd_read10_s *rd10 = (struct scsicmd_read10_s *)cdb; 2654f9f848faSopenharmony_ci 2655f9f848faSopenharmony_ci /* Format the CDB */ 2656f9f848faSopenharmony_ci rd10->opcode = SCSI_CMD_READ10; 2657f9f848faSopenharmony_ci usbhost_putbe32(rd10->lba, startsector); 2658f9f848faSopenharmony_ci usbhost_putbe16(rd10->xfrlen, nsectors); 2659f9f848faSopenharmony_ci} 2660f9f848faSopenharmony_ci 2661f9f848faSopenharmony_civoid 2662f9f848faSopenharmony_ciusbhost_writecbw16(uint64_t startsector, uint16_t blocksize, 2663f9f848faSopenharmony_ci unsigned int nsectors, struct scsicmd_write16_s *cdb) 2664f9f848faSopenharmony_ci{ 2665f9f848faSopenharmony_ci struct scsicmd_write16_s *wr16 = (struct scsicmd_write16_s *)cdb; 2666f9f848faSopenharmony_ci 2667f9f848faSopenharmony_ci wr16->opcode = SCSI_CMD_WRITE16; 2668f9f848faSopenharmony_ci usbhost_putbe64(wr16->lba, startsector); 2669f9f848faSopenharmony_ci usbhost_putbe32(wr16->xfrlen, nsectors); 2670f9f848faSopenharmony_ci} 2671f9f848faSopenharmony_ci 2672f9f848faSopenharmony_civoid 2673f9f848faSopenharmony_ciusbhost_writecbw10(size_t startsector, uint16_t blocksize, 2674f9f848faSopenharmony_ci unsigned int nsectors, struct scsicmd_write10_s *cdb) 2675f9f848faSopenharmony_ci{ 2676f9f848faSopenharmony_ci struct scsicmd_write10_s *wr10 = (struct scsicmd_write10_s *)cdb; 2677f9f848faSopenharmony_ci 2678f9f848faSopenharmony_ci wr10->opcode = SCSI_CMD_WRITE10; 2679f9f848faSopenharmony_ci usbhost_putbe32(wr10->lba, startsector); 2680f9f848faSopenharmony_ci usbhost_putbe16(wr10->xfrlen, nsectors); 2681f9f848faSopenharmony_ci} 2682f9f848faSopenharmony_ci 2683f9f848faSopenharmony_ciint 2684f9f848faSopenharmony_ciumass_test_unit_ready(struct umass_softc *sc) 2685f9f848faSopenharmony_ci{ 2686f9f848faSopenharmony_ci uint32_t status; 2687f9f848faSopenharmony_ci int32_t res; 2688f9f848faSopenharmony_ci 2689f9f848faSopenharmony_ci if((sc == NULL) || (sc->data_ccb == NULL)) { 2690f9f848faSopenharmony_ci return (-1); 2691f9f848faSopenharmony_ci } 2692f9f848faSopenharmony_ci 2693f9f848faSopenharmony_ci (void)umass_scsi_transform(sc, scsi_test_unit_ready, SCSICMD_TESTUNITREADY8_SIZEOF); 2694f9f848faSopenharmony_ci res = umass_command_start(sc, DIR_NONE, NULL, 0, 1000, umass_cam_cb, sc->data_ccb); 2695f9f848faSopenharmony_ci if (STATUS_CMD_OK != res) { 2696f9f848faSopenharmony_ci return (-1); 2697f9f848faSopenharmony_ci } 2698f9f848faSopenharmony_ci 2699f9f848faSopenharmony_ci status = sc->data_ccb->csio.status; 2700f9f848faSopenharmony_ci if (status != STATUS_CMD_OK) { 2701f9f848faSopenharmony_ci return (-1); 2702f9f848faSopenharmony_ci } 2703f9f848faSopenharmony_ci 2704f9f848faSopenharmony_ci return (0); 2705f9f848faSopenharmony_ci} 2706f9f848faSopenharmony_ci 2707f9f848faSopenharmony_ciint 2708f9f848faSopenharmony_ciumass_read_capacity_16(struct umass_softc *sc) 2709f9f848faSopenharmony_ci{ 2710f9f848faSopenharmony_ci struct scsiresp_readcapacity16_s resp; 2711f9f848faSopenharmony_ci uint32_t res; 2712f9f848faSopenharmony_ci int ret; 2713f9f848faSopenharmony_ci 2714f9f848faSopenharmony_ci (void)umass_scsi_transform(sc, scsi_read_capacity_16, SCSICMD_READCAPACITY16_SIZEOF); 2715f9f848faSopenharmony_ci res = (uint32_t)umass_command_start(sc, DIR_IN, sc->data_ccb->csio.data_ptr, 2716f9f848faSopenharmony_ci (uint32_t)SCSIRESP_READCAPACITY16_SIZEOF, 2717f9f848faSopenharmony_ci (uint32_t)1000, umass_cam_cb, sc->data_ccb); 2718f9f848faSopenharmony_ci if (STATUS_CMD_OK != res) { 2719f9f848faSopenharmony_ci return (-1); 2720f9f848faSopenharmony_ci } 2721f9f848faSopenharmony_ci 2722f9f848faSopenharmony_ci ret = memcpy_s((void *)&resp, sizeof(resp), sc->data_ccb->csio.data_ptr, 2723f9f848faSopenharmony_ci SCSIRESP_READCAPACITY16_SIZEOF); 2724f9f848faSopenharmony_ci if (ret != EOK) { 2725f9f848faSopenharmony_ci usb_err("memcpy_s failed, %d\n", ret); 2726f9f848faSopenharmony_ci return (-1); 2727f9f848faSopenharmony_ci } 2728f9f848faSopenharmony_ci 2729f9f848faSopenharmony_ci sc->info.sectornum= usbhost_getbe64(resp.lba) + 1; 2730f9f848faSopenharmony_ci sc->info.sectorsize= usbhost_getbe32(resp.blklen); 2731f9f848faSopenharmony_ci 2732f9f848faSopenharmony_ci return (0); 2733f9f848faSopenharmony_ci} 2734f9f848faSopenharmony_ci 2735f9f848faSopenharmony_ciint 2736f9f848faSopenharmony_ciumass_read_capacity(struct umass_softc *sc) 2737f9f848faSopenharmony_ci{ 2738f9f848faSopenharmony_ci struct scsiresp_readcapacity10_s resp; 2739f9f848faSopenharmony_ci int32_t ret; 2740f9f848faSopenharmony_ci 2741f9f848faSopenharmony_ci if ((sc == NULL) || (sc->data_ccb == NULL)) { 2742f9f848faSopenharmony_ci return (-1); 2743f9f848faSopenharmony_ci } 2744f9f848faSopenharmony_ci 2745f9f848faSopenharmony_ci (void)umass_scsi_transform(sc, scsi_read_capacity, SCSICMD_READCAPACITY10_SIZEOF); 2746f9f848faSopenharmony_ci ret = umass_command_start(sc, DIR_IN, sc->data_ccb->csio.data_ptr, 2747f9f848faSopenharmony_ci SCSIRESP_READCAPACITY10_SIZEOF, 2748f9f848faSopenharmony_ci 1000, umass_cam_cb, sc->data_ccb); 2749f9f848faSopenharmony_ci if (STATUS_CMD_OK != ret) { 2750f9f848faSopenharmony_ci return (-1); 2751f9f848faSopenharmony_ci } 2752f9f848faSopenharmony_ci 2753f9f848faSopenharmony_ci ret = memcpy_s((void *)&resp, sizeof(resp), sc->data_ccb->csio.data_ptr, 2754f9f848faSopenharmony_ci SCSIRESP_READCAPACITY10_SIZEOF); 2755f9f848faSopenharmony_ci if (ret != EOK) { 2756f9f848faSopenharmony_ci usb_err("memcpy_s failed, %d\n", ret); 2757f9f848faSopenharmony_ci return (-1); 2758f9f848faSopenharmony_ci } 2759f9f848faSopenharmony_ci 2760f9f848faSopenharmony_ci /* The disk Capacity is bigger than 2T */ 2761f9f848faSopenharmony_ci if (usbhost_getbe32(resp.lba) == 0xffffffff) { 2762f9f848faSopenharmony_ci ret = umass_read_capacity_16(sc); 2763f9f848faSopenharmony_ci if (ret != 0) { 2764f9f848faSopenharmony_ci usb_err("Read Capacity failed, %d\n", ret); 2765f9f848faSopenharmony_ci return (-1); 2766f9f848faSopenharmony_ci } 2767f9f848faSopenharmony_ci sc->sc_super_disk = TRUE; 2768f9f848faSopenharmony_ci 2769f9f848faSopenharmony_ci return (0); 2770f9f848faSopenharmony_ci } 2771f9f848faSopenharmony_ci 2772f9f848faSopenharmony_ci sc->info.sectornum= usbhost_getbe32(resp.lba) + 1; 2773f9f848faSopenharmony_ci sc->info.sectorsize= usbhost_getbe32(resp.blklen); 2774f9f848faSopenharmony_ci sc->sc_super_disk = FALSE; 2775f9f848faSopenharmony_ci 2776f9f848faSopenharmony_ci return (0); 2777f9f848faSopenharmony_ci} 2778f9f848faSopenharmony_ci 2779f9f848faSopenharmony_ciint 2780f9f848faSopenharmony_ciumass_read10(struct umass_softc *sc, size_t startsector, uint16_t blocksize, 2781f9f848faSopenharmony_ci unsigned int nsectors, unsigned char *buf) 2782f9f848faSopenharmony_ci{ 2783f9f848faSopenharmony_ci struct scsicmd_read10_s cdb; 2784f9f848faSopenharmony_ci uint8_t *data_buf = buf; 2785f9f848faSopenharmony_ci uint32_t status; 2786f9f848faSopenharmony_ci int32_t ret; 2787f9f848faSopenharmony_ci uint32_t flag = 0; 2788f9f848faSopenharmony_ci 2789f9f848faSopenharmony_ci if ((sc == NULL) || (sc->data_ccb == NULL)) { 2790f9f848faSopenharmony_ci return (-1); 2791f9f848faSopenharmony_ci } 2792f9f848faSopenharmony_ci 2793f9f848faSopenharmony_ci if ((sc->info.sectornum < (startsector + nsectors)) || (sc->info.sectorsize < blocksize)) 2794f9f848faSopenharmony_ci return (-1); 2795f9f848faSopenharmony_ci 2796f9f848faSopenharmony_ci if (((uintptr_t)data_buf & (USB_CACHE_ALIGN_SIZE - 1)) != 0) 2797f9f848faSopenharmony_ci { 2798f9f848faSopenharmony_ci data_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(nsectors * blocksize)); 2799f9f848faSopenharmony_ci if (data_buf == NULL) { 2800f9f848faSopenharmony_ci PRINT_ERR("Malloc failed!->%s %d\n", __FUNCTION__, __LINE__); 2801f9f848faSopenharmony_ci return (-1); 2802f9f848faSopenharmony_ci } 2803f9f848faSopenharmony_ci flag = 1; 2804f9f848faSopenharmony_ci } 2805f9f848faSopenharmony_ci 2806f9f848faSopenharmony_ci (void)memset_s(&cdb, sizeof(struct scsicmd_read10_s), 0, sizeof(struct scsicmd_read10_s)); 2807f9f848faSopenharmony_ci usbhost_readcdb10(startsector, blocksize, nsectors, &cdb); 2808f9f848faSopenharmony_ci (void)umass_scsi_transform(sc, (uint8_t *)&cdb, SCSICMD_READ10_SIZEOF); 2809f9f848faSopenharmony_ci ret = umass_command_start(sc, DIR_IN, (void *)data_buf, blocksize * nsectors, 0, 2810f9f848faSopenharmony_ci umass_cam_cb, sc->data_ccb); 2811f9f848faSopenharmony_ci if (ret != STATUS_CMD_OK) { 2812f9f848faSopenharmony_ci if (flag == 1) 2813f9f848faSopenharmony_ci free(data_buf); 2814f9f848faSopenharmony_ci return (-1); 2815f9f848faSopenharmony_ci } 2816f9f848faSopenharmony_ci 2817f9f848faSopenharmony_ci if (flag == 1) { 2818f9f848faSopenharmony_ci if (!LOS_IsUserAddressRange((vaddr_t)buf, blocksize * nsectors - sc->data_ccb->csio.resid)) { 2819f9f848faSopenharmony_ci ret = memcpy_s(buf, nsectors * blocksize, data_buf, blocksize * nsectors - sc->data_ccb->csio.resid); 2820f9f848faSopenharmony_ci } else { 2821f9f848faSopenharmony_ci ret = ((nsectors * blocksize >= blocksize * nsectors - sc->data_ccb->csio.resid) ? 2822f9f848faSopenharmony_ci LOS_ArchCopyToUser(buf, data_buf, blocksize * nsectors - sc->data_ccb->csio.resid) : ERANGE_AND_RESET); 2823f9f848faSopenharmony_ci } 2824f9f848faSopenharmony_ci free(data_buf); 2825f9f848faSopenharmony_ci if (ret != EOK) { 2826f9f848faSopenharmony_ci return (-1); 2827f9f848faSopenharmony_ci } 2828f9f848faSopenharmony_ci } 2829f9f848faSopenharmony_ci 2830f9f848faSopenharmony_ci status = sc->data_ccb->csio.status; 2831f9f848faSopenharmony_ci if (status != STATUS_CMD_OK) { 2832f9f848faSopenharmony_ci return (-1); 2833f9f848faSopenharmony_ci } 2834f9f848faSopenharmony_ci 2835f9f848faSopenharmony_ci return (0); 2836f9f848faSopenharmony_ci} 2837f9f848faSopenharmony_ci 2838f9f848faSopenharmony_ciint 2839f9f848faSopenharmony_ciumass_read16(struct umass_softc *sc, uint64_t startsector, uint16_t blocksize, 2840f9f848faSopenharmony_ci unsigned int nsectors, unsigned char *buf) 2841f9f848faSopenharmony_ci{ 2842f9f848faSopenharmony_ci struct scsicmd_read16_s cdb; 2843f9f848faSopenharmony_ci uint8_t *data_buf = buf; 2844f9f848faSopenharmony_ci uint32_t status; 2845f9f848faSopenharmony_ci uint32_t res; 2846f9f848faSopenharmony_ci uint32_t flag = 0; 2847f9f848faSopenharmony_ci int ret; 2848f9f848faSopenharmony_ci 2849f9f848faSopenharmony_ci if ((sc == NULL) || (sc->data_ccb == NULL)) { 2850f9f848faSopenharmony_ci return (-1); 2851f9f848faSopenharmony_ci } 2852f9f848faSopenharmony_ci 2853f9f848faSopenharmony_ci if ((sc->info.sectornum < (startsector + nsectors)) || (sc->info.sectorsize < blocksize)) 2854f9f848faSopenharmony_ci return (-1); 2855f9f848faSopenharmony_ci 2856f9f848faSopenharmony_ci if (((uintptr_t)data_buf & (USB_CACHE_ALIGN_SIZE - 1)) != 0) { 2857f9f848faSopenharmony_ci data_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(nsectors * blocksize)); 2858f9f848faSopenharmony_ci if (data_buf == NULL) { 2859f9f848faSopenharmony_ci PRINT_ERR("Malloc failed!->%s %d\n", __FUNCTION__, __LINE__); 2860f9f848faSopenharmony_ci return (-1); 2861f9f848faSopenharmony_ci } 2862f9f848faSopenharmony_ci flag = 1; 2863f9f848faSopenharmony_ci } 2864f9f848faSopenharmony_ci 2865f9f848faSopenharmony_ci (void)memset_s(&cdb, sizeof(struct scsicmd_read16_s), 0, sizeof(struct scsicmd_read16_s)); 2866f9f848faSopenharmony_ci usbhost_readcdb16(startsector, blocksize, nsectors, &cdb); 2867f9f848faSopenharmony_ci (void)umass_scsi_transform(sc, (uint8_t *)&cdb, SCSICMD_READ16_SIZEOF); 2868f9f848faSopenharmony_ci res = umass_command_start(sc, DIR_IN, (void *)data_buf, blocksize * nsectors, 0, 2869f9f848faSopenharmony_ci umass_cam_cb, sc->data_ccb); 2870f9f848faSopenharmony_ci if (STATUS_CMD_OK != res) { 2871f9f848faSopenharmony_ci if (flag == 1) 2872f9f848faSopenharmony_ci free(data_buf); 2873f9f848faSopenharmony_ci return (-1); 2874f9f848faSopenharmony_ci } 2875f9f848faSopenharmony_ci 2876f9f848faSopenharmony_ci if (flag == 1) { 2877f9f848faSopenharmony_ci if (!LOS_IsUserAddressRange((vaddr_t)buf, blocksize * nsectors - sc->data_ccb->csio.resid)) { 2878f9f848faSopenharmony_ci ret = memcpy_s(buf, nsectors * blocksize, data_buf, blocksize * nsectors - sc->data_ccb->csio.resid); 2879f9f848faSopenharmony_ci } else { 2880f9f848faSopenharmony_ci ret = ((nsectors * blocksize >= blocksize * nsectors - sc->data_ccb->csio.resid) ? 2881f9f848faSopenharmony_ci LOS_ArchCopyToUser(buf, data_buf, blocksize * nsectors - sc->data_ccb->csio.resid) : ERANGE_AND_RESET); 2882f9f848faSopenharmony_ci } 2883f9f848faSopenharmony_ci free(data_buf); 2884f9f848faSopenharmony_ci if (ret != EOK) { 2885f9f848faSopenharmony_ci return (-1); 2886f9f848faSopenharmony_ci } 2887f9f848faSopenharmony_ci } 2888f9f848faSopenharmony_ci 2889f9f848faSopenharmony_ci status = sc->data_ccb->csio.status; 2890f9f848faSopenharmony_ci if (status != STATUS_CMD_OK) { 2891f9f848faSopenharmony_ci return (-1); 2892f9f848faSopenharmony_ci } 2893f9f848faSopenharmony_ci 2894f9f848faSopenharmony_ci return (0); 2895f9f848faSopenharmony_ci} 2896f9f848faSopenharmony_ci 2897f9f848faSopenharmony_ciint 2898f9f848faSopenharmony_ciumass_write10(struct umass_softc *sc, size_t startsector, uint16_t blocksize, 2899f9f848faSopenharmony_ci unsigned int nsectors, const unsigned char *buf) 2900f9f848faSopenharmony_ci{ 2901f9f848faSopenharmony_ci struct scsicmd_write10_s cdb; 2902f9f848faSopenharmony_ci uint8_t *data_buf = (uint8_t *)buf; 2903f9f848faSopenharmony_ci uint32_t status; 2904f9f848faSopenharmony_ci int32_t ret; 2905f9f848faSopenharmony_ci uint32_t flag = 0; 2906f9f848faSopenharmony_ci 2907f9f848faSopenharmony_ci if((sc == NULL) || (sc->data_ccb == NULL)) { 2908f9f848faSopenharmony_ci return (-1); 2909f9f848faSopenharmony_ci } 2910f9f848faSopenharmony_ci 2911f9f848faSopenharmony_ci if ((sc->info.sectornum < (startsector + nsectors)) || (sc->info.sectorsize < blocksize)) 2912f9f848faSopenharmony_ci return (-1); 2913f9f848faSopenharmony_ci 2914f9f848faSopenharmony_ci if (((uintptr_t)data_buf & (USB_CACHE_ALIGN_SIZE - 1)) != 0) { 2915f9f848faSopenharmony_ci data_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(nsectors * blocksize)); 2916f9f848faSopenharmony_ci if (data_buf == NULL) { 2917f9f848faSopenharmony_ci PRINT_ERR("Malloc failed!->%s %d\n", __FUNCTION__, __LINE__); 2918f9f848faSopenharmony_ci return (-1); 2919f9f848faSopenharmony_ci } 2920f9f848faSopenharmony_ci 2921f9f848faSopenharmony_ci if (!LOS_IsUserAddressRange((vaddr_t)buf, blocksize * nsectors)) { 2922f9f848faSopenharmony_ci (void)memcpy_s(data_buf, blocksize * nsectors, buf, blocksize * nsectors); 2923f9f848faSopenharmony_ci } else { 2924f9f848faSopenharmony_ci ret = LOS_ArchCopyFromUser(data_buf, buf, blocksize * nsectors); 2925f9f848faSopenharmony_ci if (ret != 0) { 2926f9f848faSopenharmony_ci free(data_buf); 2927f9f848faSopenharmony_ci PRINT_ERR("copy failed!->%s %d\n", __FUNCTION__, __LINE__); 2928f9f848faSopenharmony_ci return (-1); 2929f9f848faSopenharmony_ci } 2930f9f848faSopenharmony_ci } 2931f9f848faSopenharmony_ci flag = 1; 2932f9f848faSopenharmony_ci } 2933f9f848faSopenharmony_ci 2934f9f848faSopenharmony_ci (void)memset_s(&cdb, sizeof(struct scsicmd_write10_s), 0, sizeof(struct scsicmd_write10_s)); 2935f9f848faSopenharmony_ci usbhost_writecbw10(startsector, blocksize, nsectors, &cdb); 2936f9f848faSopenharmony_ci (void)umass_scsi_transform(sc, (uint8_t *)&cdb, SCSICMD_WRITE10_SIZEOF); 2937f9f848faSopenharmony_ci ret = umass_command_start(sc, DIR_OUT, (void *)data_buf, blocksize * nsectors, 1000, 2938f9f848faSopenharmony_ci umass_cam_cb, sc->data_ccb); 2939f9f848faSopenharmony_ci 2940f9f848faSopenharmony_ci if (flag == 1) { 2941f9f848faSopenharmony_ci free(data_buf); 2942f9f848faSopenharmony_ci } 2943f9f848faSopenharmony_ci 2944f9f848faSopenharmony_ci status = sc->data_ccb->csio.status; 2945f9f848faSopenharmony_ci if ((ret != STATUS_CMD_OK) || (status != STATUS_CMD_OK)) { 2946f9f848faSopenharmony_ci return (-1); 2947f9f848faSopenharmony_ci } 2948f9f848faSopenharmony_ci 2949f9f848faSopenharmony_ci return (0); 2950f9f848faSopenharmony_ci} 2951f9f848faSopenharmony_ci 2952f9f848faSopenharmony_ciint 2953f9f848faSopenharmony_ciumass_write16(struct umass_softc *sc, uint64_t startsector, uint16_t blocksize, 2954f9f848faSopenharmony_ci unsigned int nsectors, const unsigned char *buf) 2955f9f848faSopenharmony_ci{ 2956f9f848faSopenharmony_ci struct scsicmd_write16_s cdb; 2957f9f848faSopenharmony_ci uint8_t *data_buf = (uint8_t *)buf; 2958f9f848faSopenharmony_ci uint32_t status; 2959f9f848faSopenharmony_ci int32_t res; 2960f9f848faSopenharmony_ci int32_t ret; 2961f9f848faSopenharmony_ci uint32_t flag = 0; 2962f9f848faSopenharmony_ci 2963f9f848faSopenharmony_ci if((sc == NULL) || (sc->data_ccb == NULL)) { 2964f9f848faSopenharmony_ci return (-1); 2965f9f848faSopenharmony_ci } 2966f9f848faSopenharmony_ci 2967f9f848faSopenharmony_ci if ((sc->info.sectornum < (startsector + nsectors)) || (sc->info.sectorsize < blocksize)) { 2968f9f848faSopenharmony_ci return (-1); 2969f9f848faSopenharmony_ci } 2970f9f848faSopenharmony_ci 2971f9f848faSopenharmony_ci if (((uintptr_t)data_buf & (USB_CACHE_ALIGN_SIZE - 1)) != 0) 2972f9f848faSopenharmony_ci { 2973f9f848faSopenharmony_ci data_buf = (uint8_t *)memalign(USB_CACHE_ALIGN_SIZE, SKB_DATA_ALIGN(nsectors * blocksize)); 2974f9f848faSopenharmony_ci if (data_buf == NULL) { 2975f9f848faSopenharmony_ci PRINT_ERR("Malloc failed!->%s %d\n", __FUNCTION__, __LINE__); 2976f9f848faSopenharmony_ci return (-1); 2977f9f848faSopenharmony_ci } 2978f9f848faSopenharmony_ci 2979f9f848faSopenharmony_ci if (!LOS_IsUserAddressRange((vaddr_t)buf, blocksize * nsectors)) { 2980f9f848faSopenharmony_ci (void)memcpy_s(data_buf, blocksize * nsectors, buf, blocksize * nsectors); 2981f9f848faSopenharmony_ci } else { 2982f9f848faSopenharmony_ci ret = LOS_ArchCopyFromUser(data_buf, buf, blocksize * nsectors); 2983f9f848faSopenharmony_ci if (ret != 0) { 2984f9f848faSopenharmony_ci free(data_buf); 2985f9f848faSopenharmony_ci PRINT_ERR("copy failed!->%s %d\n", __FUNCTION__, __LINE__); 2986f9f848faSopenharmony_ci return (-1); 2987f9f848faSopenharmony_ci } 2988f9f848faSopenharmony_ci } 2989f9f848faSopenharmony_ci flag = 1; 2990f9f848faSopenharmony_ci } 2991f9f848faSopenharmony_ci 2992f9f848faSopenharmony_ci (void)memset_s(&cdb, sizeof(struct scsicmd_write16_s), 0, sizeof(struct scsicmd_write16_s)); 2993f9f848faSopenharmony_ci usbhost_writecbw16(startsector, blocksize, nsectors, &cdb); 2994f9f848faSopenharmony_ci (void)umass_scsi_transform(sc, (uint8_t *)&cdb, SCSICMD_WRITE16_SIZEOF); 2995f9f848faSopenharmony_ci res = umass_command_start(sc, DIR_OUT, (void *)data_buf, blocksize * nsectors, 1000, 2996f9f848faSopenharmony_ci umass_cam_cb, sc->data_ccb); 2997f9f848faSopenharmony_ci 2998f9f848faSopenharmony_ci if (flag == 1) 2999f9f848faSopenharmony_ci { 3000f9f848faSopenharmony_ci free(data_buf); 3001f9f848faSopenharmony_ci } 3002f9f848faSopenharmony_ci 3003f9f848faSopenharmony_ci status = sc->data_ccb->csio.status; 3004f9f848faSopenharmony_ci if ((res != STATUS_CMD_OK) || (status != STATUS_CMD_OK)) { 3005f9f848faSopenharmony_ci return (-1); 3006f9f848faSopenharmony_ci } 3007f9f848faSopenharmony_ci 3008f9f848faSopenharmony_ci return (0); 3009f9f848faSopenharmony_ci} 3010f9f848faSopenharmony_ci 3011f9f848faSopenharmony_ciint 3012f9f848faSopenharmony_ciumass_inquiry(struct umass_softc *sc) 3013f9f848faSopenharmony_ci{ 3014f9f848faSopenharmony_ci uint32_t status; 3015f9f848faSopenharmony_ci int32_t ret; 3016f9f848faSopenharmony_ci 3017f9f848faSopenharmony_ci if ((sc == NULL) || (sc->data_ccb == NULL)) { 3018f9f848faSopenharmony_ci goto error; 3019f9f848faSopenharmony_ci } 3020f9f848faSopenharmony_ci 3021f9f848faSopenharmony_ci (void)umass_scsi_transform(sc, scsi_inquiry, SCSICMD_INQUIRY_SIZEOF); 3022f9f848faSopenharmony_ci ret = umass_command_start(sc, DIR_IN, sc->data_ccb->csio.data_ptr, SCSIRESP_INQUIRY_SIZEOF, 3023f9f848faSopenharmony_ci 1000, umass_cam_cb, sc->data_ccb); 3024f9f848faSopenharmony_ci if (ret != STATUS_CMD_OK) { 3025f9f848faSopenharmony_ci goto error; 3026f9f848faSopenharmony_ci } 3027f9f848faSopenharmony_ci 3028f9f848faSopenharmony_ci status = sc->data_ccb->csio.status; 3029f9f848faSopenharmony_ci if (status != STATUS_CMD_OK) { 3030f9f848faSopenharmony_ci PRINT_WARN("Failed to get the inquiry_status [status=%d].\n", status); 3031f9f848faSopenharmony_ci goto error; 3032f9f848faSopenharmony_ci } 3033f9f848faSopenharmony_ci 3034f9f848faSopenharmony_ci ret = umass_scsi_inquiry_data(sc, sc->data_ccb->csio.data_ptr, SCSIRESP_INQUIRY_SIZEOF); 3035f9f848faSopenharmony_ci if (ret == -1){ 3036f9f848faSopenharmony_ci PRINT_WARN("Failed to get the scsi_inquiry data .\n"); 3037f9f848faSopenharmony_ci goto error; 3038f9f848faSopenharmony_ci }else if (ret == 1) { 3039f9f848faSopenharmony_ci /* find Direct-access LUN */ 3040f9f848faSopenharmony_ci return (0); 3041f9f848faSopenharmony_ci } 3042f9f848faSopenharmony_ci 3043f9f848faSopenharmony_cierror: 3044f9f848faSopenharmony_ci return (-1); 3045f9f848faSopenharmony_ci} 3046f9f848faSopenharmony_ci 3047f9f848faSopenharmony_ciint 3048f9f848faSopenharmony_ciumass_request_sense(struct umass_softc *sc) 3049f9f848faSopenharmony_ci{ 3050f9f848faSopenharmony_ci uint32_t status; 3051f9f848faSopenharmony_ci int32_t ret; 3052f9f848faSopenharmony_ci if ((sc == NULL) || (sc->data_ccb == NULL)) { 3053f9f848faSopenharmony_ci return (-1); 3054f9f848faSopenharmony_ci } 3055f9f848faSopenharmony_ci 3056f9f848faSopenharmony_ci (void)umass_scsi_transform(sc, scsi_request_sense, SCSICMD_REQUESTSENSE_SIZEOF); 3057f9f848faSopenharmony_ci ret = umass_command_start(sc, DIR_IN, sc->data_ccb->csio.data_ptr, SCSIRESP_FIXEDSENSEDATA_SIZEOF, 3058f9f848faSopenharmony_ci 1000, umass_cam_cb, sc->data_ccb); 3059f9f848faSopenharmony_ci if (ret != STATUS_CMD_OK) { 3060f9f848faSopenharmony_ci return (-1); 3061f9f848faSopenharmony_ci } 3062f9f848faSopenharmony_ci 3063f9f848faSopenharmony_ci status = sc->data_ccb->csio.status; 3064f9f848faSopenharmony_ci if (status != STATUS_CMD_OK) { 3065f9f848faSopenharmony_ci return (-1); 3066f9f848faSopenharmony_ci } 3067f9f848faSopenharmony_ci 3068f9f848faSopenharmony_ci return (0); 3069f9f848faSopenharmony_ci} 3070f9f848faSopenharmony_ci 3071f9f848faSopenharmony_civoid * 3072f9f848faSopenharmony_ciumass_bind(void) 3073f9f848faSopenharmony_ci{ 3074f9f848faSopenharmony_ci return ((void*)p_umsf); 3075f9f848faSopenharmony_ci} 3076f9f848faSopenharmony_ci 3077f9f848faSopenharmony_civoid 3078f9f848faSopenharmony_ciumass_status(void) 3079f9f848faSopenharmony_ci{ 3080f9f848faSopenharmony_ci struct umass_softc *sc = p_umsf; 3081f9f848faSopenharmony_ci UINT8 cmd; 3082f9f848faSopenharmony_ci UINT8 lun; 3083f9f848faSopenharmony_ci UINT8 max; 3084f9f848faSopenharmony_ci UINT8 speed; 3085f9f848faSopenharmony_ci UINT8 phase; 3086f9f848faSopenharmony_ci UINT8 state; 3087f9f848faSopenharmony_ci UINT16 vid; 3088f9f848faSopenharmony_ci UINT16 pid; 3089f9f848faSopenharmony_ci UINT32 tag, residuce; 3090f9f848faSopenharmony_ci 3091f9f848faSopenharmony_ci if (sc == NULL) { 3092f9f848faSopenharmony_ci return; 3093f9f848faSopenharmony_ci } 3094f9f848faSopenharmony_ci 3095f9f848faSopenharmony_ci cmd = sc->sc_transfer.cmd_data[0]; 3096f9f848faSopenharmony_ci lun = sc->sc_transfer.lun; 3097f9f848faSopenharmony_ci max = sc->sc_maxlun + 1; 3098f9f848faSopenharmony_ci speed = sc->sc_udev->speed; 3099f9f848faSopenharmony_ci phase = sc->sc_last_xfer_index; 3100f9f848faSopenharmony_ci state = USB_GET_STATE(sc->sc_xfer[phase]); 3101f9f848faSopenharmony_ci vid = UGETW(sc->sc_udev->ddesc.idVendor); 3102f9f848faSopenharmony_ci pid = UGETW(sc->sc_udev->ddesc.idProduct); 3103f9f848faSopenharmony_ci tag = UGETDW(sc->cbw.dCBWTag); 3104f9f848faSopenharmony_ci residuce = UGETDW(sc->csw.dCSWDataResidue); 3105f9f848faSopenharmony_ci 3106f9f848faSopenharmony_ci dprintf("VID:%04X/PID:%04X/SPD:%02d",vid,pid,speed); 3107f9f848faSopenharmony_ci if (sc->sc_transfer.ccb) { 3108f9f848faSopenharmony_ci dprintf("/ST:%02d ",state); 3109f9f848faSopenharmony_ci if (state == USB_ST_SETUP) { 3110f9f848faSopenharmony_ci dprintf("[SP]"); 3111f9f848faSopenharmony_ci } else if (state == USB_ST_TRANSFERRED) { 3112f9f848faSopenharmony_ci dprintf("[TD]"); 3113f9f848faSopenharmony_ci } 3114f9f848faSopenharmony_ci dprintf("/cPHASE:%02d ",phase); 3115f9f848faSopenharmony_ci } else { 3116f9f848faSopenharmony_ci dprintf("/nPHASE:%02d ",phase); 3117f9f848faSopenharmony_ci } 3118f9f848faSopenharmony_ci if (phase == UMASS_T_BBB_COMMAND) { 3119f9f848faSopenharmony_ci dprintf("[CBW]"); 3120f9f848faSopenharmony_ci } else if (phase == UMASS_T_BBB_DATA_READ) { 3121f9f848faSopenharmony_ci dprintf("[DATA]"); 3122f9f848faSopenharmony_ci } else if (phase == UMASS_T_BBB_DATA_WRITE) { 3123f9f848faSopenharmony_ci dprintf("[DATA]"); 3124f9f848faSopenharmony_ci } else if (phase == UMASS_T_BBB_STATUS) { 3125f9f848faSopenharmony_ci dprintf("[CSW]"); 3126f9f848faSopenharmony_ci } else if (phase == UMASS_T_BBB_DATA_RD_CS) { 3127f9f848faSopenharmony_ci dprintf("[STAL]"); 3128f9f848faSopenharmony_ci } else if (phase == UMASS_T_BBB_DATA_WR_CS) { 3129f9f848faSopenharmony_ci dprintf("[STAL]"); 3130f9f848faSopenharmony_ci } 3131f9f848faSopenharmony_ci dprintf("\n"); 3132f9f848faSopenharmony_ci 3133f9f848faSopenharmony_ci dprintf("CL:%d/ML:%d/TG:%08X/RDU:%d/CMD:%X ",lun,max,tag,residuce,cmd); 3134f9f848faSopenharmony_ci if (cmd == SCSI_CMD_READ10) { 3135f9f848faSopenharmony_ci dprintf("[RD]\n"); 3136f9f848faSopenharmony_ci } else if (cmd == SCSI_CMD_WRITE10) { 3137f9f848faSopenharmony_ci dprintf("[WR]\n"); 3138f9f848faSopenharmony_ci } else if (cmd == SCSI_CMD_INQUIRY) { 3139f9f848faSopenharmony_ci dprintf("[INQ]\n"); 3140f9f848faSopenharmony_ci } else if (cmd == SCSI_CMD_TESTUNITREADY) { 3141f9f848faSopenharmony_ci dprintf("[TUR]\n"); 3142f9f848faSopenharmony_ci } else if (cmd == SCSI_CMD_REQUESTSENSE) { 3143f9f848faSopenharmony_ci dprintf("[RS]\n"); 3144f9f848faSopenharmony_ci } else if (cmd == SCSI_CMD_READCAPACITY10) { 3145f9f848faSopenharmony_ci dprintf("[RC]\n"); 3146f9f848faSopenharmony_ci } else { 3147f9f848faSopenharmony_ci dprintf("\n"); 3148f9f848faSopenharmony_ci } 3149f9f848faSopenharmony_ci} 3150f9f848faSopenharmony_ci 3151f9f848faSopenharmony_cistatic int 3152f9f848faSopenharmony_ciumass_open(struct Vnode *filep) 3153f9f848faSopenharmony_ci{ 3154f9f848faSopenharmony_ci (void)filep; 3155f9f848faSopenharmony_ci return (0); 3156f9f848faSopenharmony_ci} 3157f9f848faSopenharmony_ci 3158f9f848faSopenharmony_cistatic int 3159f9f848faSopenharmony_ciumass_close(struct Vnode *filep) 3160f9f848faSopenharmony_ci{ 3161f9f848faSopenharmony_ci (void)filep; 3162f9f848faSopenharmony_ci return (0); 3163f9f848faSopenharmony_ci} 3164f9f848faSopenharmony_ci 3165f9f848faSopenharmony_cistatic ssize_t 3166f9f848faSopenharmony_ciumass_read(struct Vnode *umass_inode, unsigned char *buffer, 3167f9f848faSopenharmony_ci uint64_t start_sector, unsigned int nsectors) 3168f9f848faSopenharmony_ci{ 3169f9f848faSopenharmony_ci int status; 3170f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)((struct drv_data*)umass_inode->data)->priv; 3171f9f848faSopenharmony_ci 3172f9f848faSopenharmony_ci mtx_lock(&sc->sc_umass_mtx); 3173f9f848faSopenharmony_ci if (sc->sc_super_disk == TRUE) { 3174f9f848faSopenharmony_ci status = umass_read16(sc, start_sector, (uint16_t)sc->info.sectorsize, nsectors, buffer); 3175f9f848faSopenharmony_ci } else { 3176f9f848faSopenharmony_ci status = umass_read10(sc, (size_t)start_sector, (uint16_t)sc->info.sectorsize, nsectors, buffer); 3177f9f848faSopenharmony_ci } 3178f9f848faSopenharmony_ci mtx_unlock(&sc->sc_umass_mtx); 3179f9f848faSopenharmony_ci 3180f9f848faSopenharmony_ci if(status) 3181f9f848faSopenharmony_ci return (-1); 3182f9f848faSopenharmony_ci else 3183f9f848faSopenharmony_ci return ((ssize_t)nsectors); 3184f9f848faSopenharmony_ci} 3185f9f848faSopenharmony_ci 3186f9f848faSopenharmony_cistatic ssize_t 3187f9f848faSopenharmony_ciumass_write(struct Vnode *umass_inode, const unsigned char *buffer, 3188f9f848faSopenharmony_ci uint64_t start_sector, unsigned int nsectors) 3189f9f848faSopenharmony_ci{ 3190f9f848faSopenharmony_ci int status; 3191f9f848faSopenharmony_ci struct umass_softc *sc = (struct umass_softc *)((struct drv_data*)umass_inode->data)->priv; 3192f9f848faSopenharmony_ci 3193f9f848faSopenharmony_ci mtx_lock(&sc->sc_umass_mtx); 3194f9f848faSopenharmony_ci if (sc->sc_super_disk == TRUE) { 3195f9f848faSopenharmony_ci status = umass_write16(sc, start_sector, (uint16_t)sc->info.sectorsize, nsectors, buffer); 3196f9f848faSopenharmony_ci } else { 3197f9f848faSopenharmony_ci status = umass_write10(sc, (size_t)start_sector, (uint16_t)sc->info.sectorsize, nsectors, buffer); 3198f9f848faSopenharmony_ci } 3199f9f848faSopenharmony_ci mtx_unlock(&sc->sc_umass_mtx); 3200f9f848faSopenharmony_ci 3201f9f848faSopenharmony_ci if(status) 3202f9f848faSopenharmony_ci return (-1); 3203f9f848faSopenharmony_ci else 3204f9f848faSopenharmony_ci return ((ssize_t)nsectors); 3205f9f848faSopenharmony_ci} 3206f9f848faSopenharmony_ci 3207f9f848faSopenharmony_cistatic int 3208f9f848faSopenharmony_ciumass_geometry(struct Vnode *umass_inode, struct geometry *ugeometry) 3209f9f848faSopenharmony_ci{ 3210f9f848faSopenharmony_ci struct umass_softc *sc; 3211f9f848faSopenharmony_ci 3212f9f848faSopenharmony_ci if ((ugeometry == NULL) || (umass_inode == NULL)) 3213f9f848faSopenharmony_ci return (-1); 3214f9f848faSopenharmony_ci 3215f9f848faSopenharmony_ci sc = (struct umass_softc *)(struct umass_softc *)((struct drv_data*)umass_inode->data)->priv; 3216f9f848faSopenharmony_ci 3217f9f848faSopenharmony_ci if (sc == NULL) 3218f9f848faSopenharmony_ci return (-1); 3219f9f848faSopenharmony_ci 3220f9f848faSopenharmony_ci mtx_lock(&sc->sc_umass_mtx); 3221f9f848faSopenharmony_ci ugeometry->geo_available = true; 3222f9f848faSopenharmony_ci ugeometry->geo_mediachanged = false; 3223f9f848faSopenharmony_ci ugeometry->geo_writeenabled = true; 3224f9f848faSopenharmony_ci ugeometry->geo_nsectors = sc->info.sectornum; 3225f9f848faSopenharmony_ci ugeometry->geo_sectorsize = sc->info.sectorsize; 3226f9f848faSopenharmony_ci mtx_unlock(&sc->sc_umass_mtx); 3227f9f848faSopenharmony_ci 3228f9f848faSopenharmony_ci return (0); 3229f9f848faSopenharmony_ci} 3230f9f848faSopenharmony_ci 3231f9f848faSopenharmony_cistatic int 3232f9f848faSopenharmony_ciumass_ioctl(struct Vnode *umass_inode, int cmd, unsigned long arg) 3233f9f848faSopenharmony_ci{ 3234f9f848faSopenharmony_ci (void)umass_inode; 3235f9f848faSopenharmony_ci (void)cmd; 3236f9f848faSopenharmony_ci (void)arg; 3237f9f848faSopenharmony_ci return (0); 3238f9f848faSopenharmony_ci} 3239f9f848faSopenharmony_ci 3240f9f848faSopenharmony_ciconst struct block_operations g_dev_umass_ops = { 3241f9f848faSopenharmony_ci .open = umass_open, 3242f9f848faSopenharmony_ci .close = umass_close, 3243f9f848faSopenharmony_ci .read = umass_read, 3244f9f848faSopenharmony_ci .write = umass_write, 3245f9f848faSopenharmony_ci .geometry = umass_geometry, 3246f9f848faSopenharmony_ci .ioctl = umass_ioctl, 3247f9f848faSopenharmony_ci .unlink = NULL 3248f9f848faSopenharmony_ci}; 3249f9f848faSopenharmony_ci 3250f9f848faSopenharmony_cistatic int 3251f9f848faSopenharmony_ciumass_dev_is_ready(struct umass_softc *sc) 3252f9f848faSopenharmony_ci{ 3253f9f848faSopenharmony_ci int lun; 3254f9f848faSopenharmony_ci int ret; 3255f9f848faSopenharmony_ci uint8_t valid_lun; 3256f9f848faSopenharmony_ci 3257f9f848faSopenharmony_ci mtx_lock(&sc->sc_umass_mtx); 3258f9f848faSopenharmony_ci for (lun = 0; lun <= sc->sc_maxlun; lun++) { 3259f9f848faSopenharmony_ci sc->sc_transfer.lun = lun; 3260f9f848faSopenharmony_ci if (umass_inquiry(sc) < 0) 3261f9f848faSopenharmony_ci continue; 3262f9f848faSopenharmony_ci 3263f9f848faSopenharmony_ci valid_lun = lun; 3264f9f848faSopenharmony_ci ret = umass_test_unit_ready(sc); 3265f9f848faSopenharmony_ci if(ret == 0) { 3266f9f848faSopenharmony_ci sc->sc_transfer.lun = valid_lun; 3267f9f848faSopenharmony_ci ret = umass_read_capacity(sc); 3268f9f848faSopenharmony_ci if (ret < 0) { 3269f9f848faSopenharmony_ci mtx_unlock(&sc->sc_umass_mtx); 3270f9f848faSopenharmony_ci PRINT_ERR("umass read capacity fail!\n"); 3271f9f848faSopenharmony_ci return (0); 3272f9f848faSopenharmony_ci } 3273f9f848faSopenharmony_ci mtx_unlock(&sc->sc_umass_mtx); 3274f9f848faSopenharmony_ci return (1); 3275f9f848faSopenharmony_ci } 3276f9f848faSopenharmony_ci 3277f9f848faSopenharmony_ci ret = umass_request_sense(sc); 3278f9f848faSopenharmony_ci if(ret < 0) { 3279f9f848faSopenharmony_ci PRINT_ERR("Request sense fail!\n"); 3280f9f848faSopenharmony_ci mtx_unlock(&sc->sc_umass_mtx); 3281f9f848faSopenharmony_ci return (0); 3282f9f848faSopenharmony_ci } 3283f9f848faSopenharmony_ci } 3284f9f848faSopenharmony_ci mtx_unlock(&sc->sc_umass_mtx); 3285f9f848faSopenharmony_ci return (0); 3286f9f848faSopenharmony_ci} 3287f9f848faSopenharmony_ci 3288f9f848faSopenharmony_cistatic int 3289f9f848faSopenharmony_ciumass_attach_dev_sub(struct umass_softc *sc, unsigned int dev_unit) 3290f9f848faSopenharmony_ci{ 3291f9f848faSopenharmony_ci int ret; 3292f9f848faSopenharmony_ci int disk_id; 3293f9f848faSopenharmony_ci char devname[MASS_NAME]= {0}; 3294f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 3295f9f848faSopenharmony_ci device_t dev; 3296f9f848faSopenharmony_ci struct usb_device *udev; 3297f9f848faSopenharmony_ci usbd_bt_node *cur_node; 3298f9f848faSopenharmony_ci struct node_info parent_info; 3299f9f848faSopenharmony_ci struct node_info cur_info; 3300f9f848faSopenharmony_ci#endif 3301f9f848faSopenharmony_ci 3302f9f848faSopenharmony_ci umass_dev_lock(dev_unit); 3303f9f848faSopenharmony_ci 3304f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 3305f9f848faSopenharmony_ci dev = sc->sc_dev; 3306f9f848faSopenharmony_ci udev = sc->sc_udev; 3307f9f848faSopenharmony_ci dev_quantity |= 1ull << (unsigned int)device_get_unit(dev); 3308f9f848faSopenharmony_ci#endif 3309f9f848faSopenharmony_ci 3310f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 3311f9f848faSopenharmony_ci if (!umass_dev_is_attached(dev_unit)) 3312f9f848faSopenharmony_ci#endif 3313f9f848faSopenharmony_ci { 3314f9f848faSopenharmony_ci devunit_to_devname(dev_unit, devname); 3315f9f848faSopenharmony_ci disk_id = los_alloc_diskid_byname(devname); 3316f9f848faSopenharmony_ci OsSetUsbStatus(disk_id); 3317f9f848faSopenharmony_ci ret = los_disk_init(devname, &g_dev_umass_ops, (void *)sc, disk_id, NULL); 3318f9f848faSopenharmony_ci if (ret) { 3319f9f848faSopenharmony_ci PRINT_ERR("umass_attach_dev : los_disk_init fail!\n"); 3320f9f848faSopenharmony_ci goto error; 3321f9f848faSopenharmony_ci } 3322f9f848faSopenharmony_ci } 3323f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 3324f9f848faSopenharmony_ci umass_dev_attach_flag_set(dev_unit); 3325f9f848faSopenharmony_ci#endif 3326f9f848faSopenharmony_ci 3327f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 3328f9f848faSopenharmony_ci cur_info.nameunit = device_get_nameunit(dev); 3329f9f848faSopenharmony_ci cur_info.port_no = udev->port_no; 3330f9f848faSopenharmony_ci cur_node = usbd_create_bt_node(&cur_info); 3331f9f848faSopenharmony_ci if (cur_node == NULL) { 3332f9f848faSopenharmony_ci goto error; 3333f9f848faSopenharmony_ci } 3334f9f848faSopenharmony_ci 3335f9f848faSopenharmony_ci parent_info.nameunit = device_get_nameunit(device_get_parent(dev)); 3336f9f848faSopenharmony_ci parent_info.port_no = udev->port_no; 3337f9f848faSopenharmony_ci 3338f9f848faSopenharmony_ci (void)usbd_insert_bt_node(cur_node, hub_tree, &parent_info); 3339f9f848faSopenharmony_ci#endif 3340f9f848faSopenharmony_ci 3341f9f848faSopenharmony_ci umass_dev_unlock(dev_unit); 3342f9f848faSopenharmony_ci return (0); 3343f9f848faSopenharmony_ci 3344f9f848faSopenharmony_cierror: 3345f9f848faSopenharmony_ci umass_dev_unlock(dev_unit); 3346f9f848faSopenharmony_ci return (-1); 3347f9f848faSopenharmony_ci} 3348f9f848faSopenharmony_ci 3349f9f848faSopenharmony_cistatic void 3350f9f848faSopenharmony_ciumass_detach_dev_sub(struct umass_softc *sc, int dev_unit, int flag) 3351f9f848faSopenharmony_ci{ 3352f9f848faSopenharmony_ci int disk_id; 3353f9f848faSopenharmony_ci char devname[MASS_NAME]= {0}; 3354f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 3355f9f848faSopenharmony_ci struct node_info cur_info; 3356f9f848faSopenharmony_ci struct node_info parent_info; 3357f9f848faSopenharmony_ci device_t dev = NULL; 3358f9f848faSopenharmony_ci struct usb_device *udev = NULL; 3359f9f848faSopenharmony_ci#endif 3360f9f848faSopenharmony_ci 3361f9f848faSopenharmony_ci umass_dev_lock(dev_unit); 3362f9f848faSopenharmony_ci 3363f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 3364f9f848faSopenharmony_ci dev = sc->sc_dev; 3365f9f848faSopenharmony_ci udev = sc->sc_udev; 3366f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 3367f9f848faSopenharmony_ci if (umass_dev_is_attached(dev_unit)) 3368f9f848faSopenharmony_ci#endif 3369f9f848faSopenharmony_ci { 3370f9f848faSopenharmony_ci parent_info.nameunit = device_get_nameunit(device_get_parent(dev)); 3371f9f848faSopenharmony_ci parent_info.port_no = udev->port_no; 3372f9f848faSopenharmony_ci 3373f9f848faSopenharmony_ci cur_info.nameunit = device_get_nameunit(dev); 3374f9f848faSopenharmony_ci cur_info.port_no = udev->port_no; 3375f9f848faSopenharmony_ci (void)usbd_remove_bt_node(hub_tree, &parent_info, &cur_info); 3376f9f848faSopenharmony_ci } 3377f9f848faSopenharmony_ci#endif 3378f9f848faSopenharmony_ci 3379f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 3380f9f848faSopenharmony_ci if (umass_dev_is_attached(dev_unit)) 3381f9f848faSopenharmony_ci#endif 3382f9f848faSopenharmony_ci { 3383f9f848faSopenharmony_ci devunit_to_devname(dev_unit, devname); 3384f9f848faSopenharmony_ci disk_id = los_get_diskid_byname(devname); 3385f9f848faSopenharmony_ci (void)los_disk_deinit(disk_id); 3386f9f848faSopenharmony_ci (void)OsClearUsbStatus(disk_id); 3387f9f848faSopenharmony_ci } 3388f9f848faSopenharmony_ci 3389f9f848faSopenharmony_ci if (flag == 0) { /* 0: This interface is called from umass_detach, or is called elsewhere. */ 3390f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 3391f9f848faSopenharmony_ci umass_dev_delete(sc, dev_unit); 3392f9f848faSopenharmony_ci#endif 3393f9f848faSopenharmony_ci } 3394f9f848faSopenharmony_ci 3395f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 3396f9f848faSopenharmony_ci dev_quantity &= ~(1ull << (unsigned int)device_get_unit(dev)); 3397f9f848faSopenharmony_ci#endif 3398f9f848faSopenharmony_ci 3399f9f848faSopenharmony_ci umass_dev_unlock(dev_unit); 3400f9f848faSopenharmony_ci} 3401f9f848faSopenharmony_ci 3402f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 3403f9f848faSopenharmony_civoid 3404f9f848faSopenharmony_ciumass_dev_status_check(UINTPTR arg) 3405f9f848faSopenharmony_ci{ 3406f9f848faSopenharmony_ci (void)arg; 3407f9f848faSopenharmony_ci int ret; 3408f9f848faSopenharmony_ci int i; 3409f9f848faSopenharmony_ci struct umass_dev_info *dev = g_umass_dev_array; 3410f9f848faSopenharmony_ci struct umass_softc *sc; 3411f9f848faSopenharmony_ci 3412f9f848faSopenharmony_ci while(1) { 3413f9f848faSopenharmony_ci for (i = 0; i < MAX_DEVICE; i++) { 3414f9f848faSopenharmony_ci umass_dev_lock(i); 3415f9f848faSopenharmony_ci if (dev[i].used == 1) { 3416f9f848faSopenharmony_ci sc = dev[i].sc; 3417f9f848faSopenharmony_ci ret = umass_dev_is_ready(sc); 3418f9f848faSopenharmony_ci if (ret == 0) { 3419f9f848faSopenharmony_ci if (dev[i].attached == 1) { 3420f9f848faSopenharmony_ci umass_detach_dev_sub(sc, dev[i].dev_unit, 1); 3421f9f848faSopenharmony_ci dev[i].attached = 0; 3422f9f848faSopenharmony_ci } 3423f9f848faSopenharmony_ci umass_dev_unlock(i); 3424f9f848faSopenharmony_ci continue; 3425f9f848faSopenharmony_ci } 3426f9f848faSopenharmony_ci 3427f9f848faSopenharmony_ci if (dev[i].attached == 1) { 3428f9f848faSopenharmony_ci umass_dev_unlock(i); 3429f9f848faSopenharmony_ci continue; 3430f9f848faSopenharmony_ci } 3431f9f848faSopenharmony_ci 3432f9f848faSopenharmony_ci ret = umass_attach_dev_sub(sc, dev[i].dev_unit); 3433f9f848faSopenharmony_ci if (ret< 0) { 3434f9f848faSopenharmony_ci umass_dev_unlock(i); 3435f9f848faSopenharmony_ci PRINT_ERR("umass attach device sub failed!\n"); 3436f9f848faSopenharmony_ci continue; 3437f9f848faSopenharmony_ci } 3438f9f848faSopenharmony_ci } 3439f9f848faSopenharmony_ci umass_dev_unlock(i); 3440f9f848faSopenharmony_ci } 3441f9f848faSopenharmony_ci (void)LOS_Msleep(1000); 3442f9f848faSopenharmony_ci } 3443f9f848faSopenharmony_ci} 3444f9f848faSopenharmony_ci 3445f9f848faSopenharmony_ciint 3446f9f848faSopenharmony_ciumass_dev_is_attached(unsigned int dev_unit) 3447f9f848faSopenharmony_ci{ 3448f9f848faSopenharmony_ci if (dev_unit >= MAX_DEVICE) { 3449f9f848faSopenharmony_ci PRINT_ERR("%s %d, The device unit is wrong!\n", __FUNCTION__, __LINE__); 3450f9f848faSopenharmony_ci return (-1); 3451f9f848faSopenharmony_ci } 3452f9f848faSopenharmony_ci 3453f9f848faSopenharmony_ci return (g_umass_dev_array[dev_unit].attached); 3454f9f848faSopenharmony_ci} 3455f9f848faSopenharmony_ci 3456f9f848faSopenharmony_cistatic void 3457f9f848faSopenharmony_ciumass_dev_add(struct umass_softc *sc, int dev_unit) 3458f9f848faSopenharmony_ci{ 3459f9f848faSopenharmony_ci int id = dev_unit; 3460f9f848faSopenharmony_ci 3461f9f848faSopenharmony_ci if (g_umass_dev_array[id].used == 1) { 3462f9f848faSopenharmony_ci PRINT_ERR("The id of umass device array is used!, id=%d\n", dev_unit); 3463f9f848faSopenharmony_ci return; 3464f9f848faSopenharmony_ci } 3465f9f848faSopenharmony_ci 3466f9f848faSopenharmony_ci g_umass_dev_array[id].sc = sc; 3467f9f848faSopenharmony_ci g_umass_dev_array[id].dev_unit = dev_unit; 3468f9f848faSopenharmony_ci g_umass_dev_array[id].used = 1; 3469f9f848faSopenharmony_ci umass_dev_mtx_init(id, MTX_DEF | MTX_RECURSE); 3470f9f848faSopenharmony_ci} 3471f9f848faSopenharmony_ci 3472f9f848faSopenharmony_cistatic void 3473f9f848faSopenharmony_ciumass_dev_delete(struct umass_softc *sc, unsigned int dev_unit) 3474f9f848faSopenharmony_ci{ 3475f9f848faSopenharmony_ci unsigned int id = dev_unit; 3476f9f848faSopenharmony_ci 3477f9f848faSopenharmony_ci if (g_umass_dev_array[id].used == 0) { 3478f9f848faSopenharmony_ci PRINT_ERR("The id of umass device array is not used!\n"); 3479f9f848faSopenharmony_ci return; 3480f9f848faSopenharmony_ci } 3481f9f848faSopenharmony_ci 3482f9f848faSopenharmony_ci if (g_umass_dev_array[id].dev_unit == dev_unit && 3483f9f848faSopenharmony_ci g_umass_dev_array[id].sc == sc) { 3484f9f848faSopenharmony_ci g_umass_dev_array[id].used = 0; 3485f9f848faSopenharmony_ci g_umass_dev_array[id].sc = NULL; 3486f9f848faSopenharmony_ci g_umass_dev_array[id].attached = 0; 3487f9f848faSopenharmony_ci umass_dev_mtx_destroy(id); 3488f9f848faSopenharmony_ci } else { 3489f9f848faSopenharmony_ci PRINT_ERR("Can not find the umass device!\n"); 3490f9f848faSopenharmony_ci } 3491f9f848faSopenharmony_ci} 3492f9f848faSopenharmony_ci 3493f9f848faSopenharmony_cistatic void 3494f9f848faSopenharmony_ciumass_dev_attach_flag_set(int dev_unit) 3495f9f848faSopenharmony_ci{ 3496f9f848faSopenharmony_ci g_umass_dev_array[dev_unit].attached = 1; 3497f9f848faSopenharmony_ci} 3498f9f848faSopenharmony_ci 3499f9f848faSopenharmony_cistatic void 3500f9f848faSopenharmony_ciumass_task_check(int flag) 3501f9f848faSopenharmony_ci{ 3502f9f848faSopenharmony_ci int i; 3503f9f848faSopenharmony_ci int ret; 3504f9f848faSopenharmony_ci 3505f9f848faSopenharmony_ci for (i = 0; i < MAX_DEVICE; i++) { 3506f9f848faSopenharmony_ci if (g_umass_dev_array[i].used) 3507f9f848faSopenharmony_ci break; 3508f9f848faSopenharmony_ci } 3509f9f848faSopenharmony_ci 3510f9f848faSopenharmony_ci if (i == MAX_DEVICE) { 3511f9f848faSopenharmony_ci if (flag == 0) { /* create task */ 3512f9f848faSopenharmony_ci ret = usb_os_task_creat(&umass_taskid, (TSK_ENTRY_FUNC)umass_dev_status_check, 3513f9f848faSopenharmony_ci LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO, "umass_task", 0); 3514f9f848faSopenharmony_ci if (ret) { 3515f9f848faSopenharmony_ci PRINT_ERR("Create umass task fail!\n"); 3516f9f848faSopenharmony_ci return; 3517f9f848faSopenharmony_ci } 3518f9f848faSopenharmony_ci } else if (flag == 1) { /* delete task */ 3519f9f848faSopenharmony_ci ret = usb_os_task_delete(umass_taskid); 3520f9f848faSopenharmony_ci if (ret) { 3521f9f848faSopenharmony_ci PRINT_ERR("Delete umass task fail!\n"); 3522f9f848faSopenharmony_ci return; 3523f9f848faSopenharmony_ci } 3524f9f848faSopenharmony_ci } else { 3525f9f848faSopenharmony_ci PRINT_ERR("%s flag error!\n", __FUNCTION__); 3526f9f848faSopenharmony_ci } 3527f9f848faSopenharmony_ci } 3528f9f848faSopenharmony_ci} 3529f9f848faSopenharmony_ci#endif 3530f9f848faSopenharmony_ci 3531f9f848faSopenharmony_cistatic void 3532f9f848faSopenharmony_cidevunit_to_devname(unsigned int dev_unit, char *devname) 3533f9f848faSopenharmony_ci{ 3534f9f848faSopenharmony_ci char name_suf; 3535f9f848faSopenharmony_ci int ret; 3536f9f848faSopenharmony_ci 3537f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 3538f9f848faSopenharmony_ci if (!(0x1 & (dev_quantity >> dev_unit))) 3539f9f848faSopenharmony_ci#else 3540f9f848faSopenharmony_ci if (dev_unit >= MAX_DEVICE) 3541f9f848faSopenharmony_ci#endif 3542f9f848faSopenharmony_ci { 3543f9f848faSopenharmony_ci dprintf("sorry, we don't support so many devices\n"); 3544f9f848faSopenharmony_ci return; 3545f9f848faSopenharmony_ci } 3546f9f848faSopenharmony_ci 3547f9f848faSopenharmony_ci name_suf = 'a' + dev_unit; 3548f9f848faSopenharmony_ci ret = snprintf_s(devname, MASS_NAME, MASS_NAME - 1, "%s%c", UMASS_ATTACH_PRENAME, name_suf); 3549f9f848faSopenharmony_ci if (ret < 0) { 3550f9f848faSopenharmony_ci usb_err("snprintf_s failed!, ret:%d\n", ret); 3551f9f848faSopenharmony_ci return; 3552f9f848faSopenharmony_ci } 3553f9f848faSopenharmony_ci} 3554f9f848faSopenharmony_cistatic int32_t 3555f9f848faSopenharmony_ciumass_attach_dev(struct umass_softc *sc, unsigned int dev_unit) 3556f9f848faSopenharmony_ci{ 3557f9f848faSopenharmony_ci int ret; 3558f9f848faSopenharmony_ci 3559f9f848faSopenharmony_ci if (dev_unit >= MAX_DEVICE) { 3560f9f848faSopenharmony_ci PRINT_ERR("sorry, we don't support so many devices\n"); 3561f9f848faSopenharmony_ci return (-1); 3562f9f848faSopenharmony_ci } 3563f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 3564f9f848faSopenharmony_ci umass_task_check(0); 3565f9f848faSopenharmony_ci umass_dev_add(sc, dev_unit); 3566f9f848faSopenharmony_ci#endif 3567f9f848faSopenharmony_ci 3568f9f848faSopenharmony_ci ret = umass_dev_is_ready(sc); 3569f9f848faSopenharmony_ci if (ret) { 3570f9f848faSopenharmony_ci ret = umass_attach_dev_sub(sc, dev_unit); 3571f9f848faSopenharmony_ci if (ret < 0) { 3572f9f848faSopenharmony_ci#if USB_SUPPORT_SD_HOT_PLUG 3573f9f848faSopenharmony_ci umass_dev_delete(sc, dev_unit); 3574f9f848faSopenharmony_ci#endif 3575f9f848faSopenharmony_ci PRINT_ERR("umass attach device fail!\n"); 3576f9f848faSopenharmony_ci return (-1); 3577f9f848faSopenharmony_ci } 3578f9f848faSopenharmony_ci } 3579f9f848faSopenharmony_ci 3580f9f848faSopenharmony_ci return (0); 3581f9f848faSopenharmony_ci} 3582f9f848faSopenharmony_ci 3583f9f848faSopenharmony_ci#if USB_HAVE_DEVICE_TOPOLOGY 3584f9f848faSopenharmony_ciint 3585f9f848faSopenharmony_ciumass_medium_probe(uint8_t medium, char *devname) 3586f9f848faSopenharmony_ci{ 3587f9f848faSopenharmony_ci struct usbd_bt_node *node; 3588f9f848faSopenharmony_ci uint8_t dev_unit; 3589f9f848faSopenharmony_ci 3590f9f848faSopenharmony_ci if ((devname == NULL) || strlen(devname) > 7) { /* /dev/sd* */ 3591f9f848faSopenharmony_ci return (-1); 3592f9f848faSopenharmony_ci } 3593f9f848faSopenharmony_ci 3594f9f848faSopenharmony_ci if ((medium < 1) || (medium > usbd_get_hub_quantity())) { 3595f9f848faSopenharmony_ci return (-1); 3596f9f848faSopenharmony_ci } 3597f9f848faSopenharmony_ci 3598f9f848faSopenharmony_ci node = usbd_per_order_probe(hub_tree, "umass", &medium); 3599f9f848faSopenharmony_ci if (node != NULL) { 3600f9f848faSopenharmony_ci dev_unit = usbd_atoi(node->info.nameunit + 5); /* 5 = umass */ 3601f9f848faSopenharmony_ci devunit_to_devname(dev_unit, devname); 3602f9f848faSopenharmony_ci } else { 3603f9f848faSopenharmony_ci return (-1); 3604f9f848faSopenharmony_ci } 3605f9f848faSopenharmony_ci return (0); 3606f9f848faSopenharmony_ci} 3607f9f848faSopenharmony_ci#endif 3608f9f848faSopenharmony_ci 3609