1*e979c658Sreinoud /* $NetBSD: uscsi_subr.c,v 1.1 2008/05/14 16:49:48 reinoud Exp $ */ 2*e979c658Sreinoud 3*e979c658Sreinoud /*- 4*e979c658Sreinoud * Copyright (c) 1998 The NetBSD Foundation, Inc. 5*e979c658Sreinoud * All rights reserved. 6*e979c658Sreinoud * 7*e979c658Sreinoud * This code is derived from software contributed to The NetBSD Foundation 8*e979c658Sreinoud * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace 9*e979c658Sreinoud * Simulation Facility, NASA Ames Research Center. 10*e979c658Sreinoud * 11*e979c658Sreinoud * Redistribution and use in source and binary forms, with or without 12*e979c658Sreinoud * modification, are permitted provided that the following conditions 13*e979c658Sreinoud * are met: 14*e979c658Sreinoud * 1. Redistributions of source code must retain the above copyright 15*e979c658Sreinoud * notice, this list of conditions and the following disclaimer. 16*e979c658Sreinoud * 2. Redistributions in binary form must reproduce the above copyright 17*e979c658Sreinoud * notice, this list of conditions and the following disclaimer in the 18*e979c658Sreinoud * documentation and/or other materials provided with the distribution. 19*e979c658Sreinoud * 20*e979c658Sreinoud * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21*e979c658Sreinoud * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22*e979c658Sreinoud * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23*e979c658Sreinoud * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24*e979c658Sreinoud * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25*e979c658Sreinoud * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26*e979c658Sreinoud * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27*e979c658Sreinoud * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28*e979c658Sreinoud * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29*e979c658Sreinoud * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30*e979c658Sreinoud * POSSIBILITY OF SUCH DAMAGE. 31*e979c658Sreinoud * 32*e979c658Sreinoud * Small changes, generalisations and Linux support by Reinoud Zandijk 33*e979c658Sreinoud * <reinoud@netbsd.org>. 34*e979c658Sreinoud * 35*e979c658Sreinoud */ 36*e979c658Sreinoud 37*e979c658Sreinoud 38*e979c658Sreinoud /* 39*e979c658Sreinoud * SCSI support subroutines. 40*e979c658Sreinoud */ 41*e979c658Sreinoud 42*e979c658Sreinoud #include <sys/param.h> 43*e979c658Sreinoud #include <sys/ioctl.h> 44*e979c658Sreinoud #include <err.h> 45*e979c658Sreinoud #include <errno.h> 46*e979c658Sreinoud #include <stdio.h> 47*e979c658Sreinoud #include <stdlib.h> 48*e979c658Sreinoud #include <string.h> 49*e979c658Sreinoud #include <unistd.h> 50*e979c658Sreinoud #include <fcntl.h> 51*e979c658Sreinoud #include <sys/types.h> 52*e979c658Sreinoud #include <inttypes.h> 53*e979c658Sreinoud #include <assert.h> 54*e979c658Sreinoud 55*e979c658Sreinoud #include "uscsilib.h" 56*e979c658Sreinoud 57*e979c658Sreinoud 58*e979c658Sreinoud int uscsilib_verbose = 0; 59*e979c658Sreinoud 60*e979c658Sreinoud 61*e979c658Sreinoud #ifdef USCSI_SCSIPI 62*e979c658Sreinoud /* 63*e979c658Sreinoud * scsipi is a integrated SCSI and ATAPI layer under NetBSD and exists 64*e979c658Sreinoud * in a modified form under OpenBSD and possibly also under other 65*e979c658Sreinoud * operating systems. 66*e979c658Sreinoud */ 67*e979c658Sreinoud 68*e979c658Sreinoud 69*e979c658Sreinoud #include <sys/scsiio.h> 70*e979c658Sreinoud #ifdef __OpenBSD__ 71*e979c658Sreinoud #include <scsi/uscsi_all.h> 72*e979c658Sreinoud #else 73*e979c658Sreinoud #include <dev/scsipi/scsipi_all.h> 74*e979c658Sreinoud #endif 75*e979c658Sreinoud 76*e979c658Sreinoud 77*e979c658Sreinoud int 78*e979c658Sreinoud uscsi_open(struct uscsi_dev *disc) 79*e979c658Sreinoud { 80*e979c658Sreinoud struct stat dstat; 81*e979c658Sreinoud 82*e979c658Sreinoud disc->fhandle = open(disc->dev_name, O_RDWR, 0); /* no create */ 83*e979c658Sreinoud if (disc->fhandle<0) { 84*e979c658Sreinoud perror("Failure to open device or file"); 85*e979c658Sreinoud return ENODEV; 86*e979c658Sreinoud } 87*e979c658Sreinoud 88*e979c658Sreinoud if (fstat(disc->fhandle, &dstat) < 0) { 89*e979c658Sreinoud perror("Can't stat device or file"); 90*e979c658Sreinoud uscsi_close(disc); 91*e979c658Sreinoud return ENODEV; 92*e979c658Sreinoud } 93*e979c658Sreinoud 94*e979c658Sreinoud return 0; 95*e979c658Sreinoud } 96*e979c658Sreinoud 97*e979c658Sreinoud 98*e979c658Sreinoud int 99*e979c658Sreinoud uscsi_close(struct uscsi_dev * disc) 100*e979c658Sreinoud { 101*e979c658Sreinoud close(disc->fhandle); 102*e979c658Sreinoud disc->fhandle = -1; 103*e979c658Sreinoud 104*e979c658Sreinoud return 0; 105*e979c658Sreinoud } 106*e979c658Sreinoud 107*e979c658Sreinoud 108*e979c658Sreinoud int 109*e979c658Sreinoud uscsi_command(int flags, struct uscsi_dev *disc, 110*e979c658Sreinoud void *cmd, size_t cmdlen, void *data, size_t datalen, 111*e979c658Sreinoud uint32_t timeout, struct uscsi_sense *uscsi_sense) 112*e979c658Sreinoud { 113*e979c658Sreinoud scsireq_t req; 114*e979c658Sreinoud 115*e979c658Sreinoud memset(&req, 0, sizeof(req)); 116*e979c658Sreinoud if (uscsi_sense) 117*e979c658Sreinoud bzero(uscsi_sense, sizeof(struct uscsi_sense)); 118*e979c658Sreinoud 119*e979c658Sreinoud memcpy(req.cmd, cmd, cmdlen); 120*e979c658Sreinoud req.cmdlen = cmdlen; 121*e979c658Sreinoud req.databuf = data; 122*e979c658Sreinoud req.datalen = datalen; 123*e979c658Sreinoud req.timeout = timeout; 124*e979c658Sreinoud req.flags = flags; 125*e979c658Sreinoud req.senselen = SENSEBUFLEN; 126*e979c658Sreinoud 127*e979c658Sreinoud if (ioctl(disc->fhandle, SCIOCCOMMAND, &req) == -1) 128*e979c658Sreinoud err(1, "SCIOCCOMMAND"); 129*e979c658Sreinoud 130*e979c658Sreinoud if (req.retsts == SCCMD_OK) 131*e979c658Sreinoud return 0; 132*e979c658Sreinoud 133*e979c658Sreinoud /* Some problem; report it and exit. */ 134*e979c658Sreinoud if (req.retsts == SCCMD_TIMEOUT) { 135*e979c658Sreinoud if (uscsilib_verbose) 136*e979c658Sreinoud fprintf(stderr, "%s: SCSI command timed out\n", 137*e979c658Sreinoud disc->dev_name); 138*e979c658Sreinoud return EAGAIN; 139*e979c658Sreinoud } else if (req.retsts == SCCMD_BUSY) { 140*e979c658Sreinoud if (uscsilib_verbose) 141*e979c658Sreinoud fprintf(stderr, "%s: device is busy\n", 142*e979c658Sreinoud disc->dev_name); 143*e979c658Sreinoud return EBUSY; 144*e979c658Sreinoud } else if (req.retsts == SCCMD_SENSE) { 145*e979c658Sreinoud if (uscsi_sense) { 146*e979c658Sreinoud uscsi_sense->asc = req.sense[12]; 147*e979c658Sreinoud uscsi_sense->ascq = req.sense[13]; 148*e979c658Sreinoud uscsi_sense->skey_valid = req.sense[15] & 128; 149*e979c658Sreinoud uscsi_sense->sense_key = (req.sense[16] << 8) | 150*e979c658Sreinoud (req.sense[17]); 151*e979c658Sreinoud } 152*e979c658Sreinoud if (uscsilib_verbose) 153*e979c658Sreinoud uscsi_print_sense((char *) disc->dev_name, 154*e979c658Sreinoud req.cmd, req.cmdlen, 155*e979c658Sreinoud req.sense, req.senselen_used, 1); 156*e979c658Sreinoud return EIO; 157*e979c658Sreinoud } else 158*e979c658Sreinoud if (uscsilib_verbose) 159*e979c658Sreinoud fprintf(stderr, "%s: device had unknown status %x\n", 160*e979c658Sreinoud disc->dev_name, 161*e979c658Sreinoud req.retsts); 162*e979c658Sreinoud 163*e979c658Sreinoud return EFAULT; 164*e979c658Sreinoud } 165*e979c658Sreinoud 166*e979c658Sreinoud 167*e979c658Sreinoud /* 168*e979c658Sreinoud * The reasoning behind this explicit copy is for compatibility with changes 169*e979c658Sreinoud * in our uscsi_addr structure. 170*e979c658Sreinoud */ 171*e979c658Sreinoud int 172*e979c658Sreinoud uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr) 173*e979c658Sreinoud { 174*e979c658Sreinoud struct scsi_addr raddr; 175*e979c658Sreinoud int error; 176*e979c658Sreinoud 177*e979c658Sreinoud bzero(saddr, sizeof(struct scsi_addr)); 178*e979c658Sreinoud error = ioctl(disc->fhandle, SCIOCIDENTIFY, &raddr); 179*e979c658Sreinoud if (error) return error; 180*e979c658Sreinoud 181*e979c658Sreinoud #ifdef __NetBSD__ 182*e979c658Sreinoud /* scsi and atapi are split up like in uscsi_addr */ 183*e979c658Sreinoud if (raddr.type == 0) { 184*e979c658Sreinoud saddr->type = USCSI_TYPE_SCSI; 185*e979c658Sreinoud saddr->addr.scsi.scbus = raddr.addr.scsi.scbus; 186*e979c658Sreinoud saddr->addr.scsi.target = raddr.addr.scsi.target; 187*e979c658Sreinoud saddr->addr.scsi.lun = raddr.addr.scsi.lun; 188*e979c658Sreinoud } else { 189*e979c658Sreinoud saddr->type = USCSI_TYPE_ATAPI; 190*e979c658Sreinoud saddr->addr.atapi.atbus = raddr.addr.atapi.atbus; 191*e979c658Sreinoud saddr->addr.atapi.drive = raddr.addr.atapi.drive; 192*e979c658Sreinoud } 193*e979c658Sreinoud #endif 194*e979c658Sreinoud #ifdef __OpenBSD__ 195*e979c658Sreinoud /* atapi's are shown as SCSI devices */ 196*e979c658Sreinoud if (raddr.type == 0) { 197*e979c658Sreinoud saddr->type = USCSI_TYPE_SCSI; 198*e979c658Sreinoud saddr->addr.scsi.scbus = raddr.scbus; 199*e979c658Sreinoud saddr->addr.scsi.target = raddr.target; 200*e979c658Sreinoud saddr->addr.scsi.lun = raddr.lun; 201*e979c658Sreinoud } else { 202*e979c658Sreinoud saddr->type = USCSI_TYPE_ATAPI; 203*e979c658Sreinoud saddr->addr.atapi.atbus = raddr.scbus; /* overload */ 204*e979c658Sreinoud saddr->addr.atapi.drive = raddr.target; /* overload */ 205*e979c658Sreinoud } 206*e979c658Sreinoud #endif 207*e979c658Sreinoud 208*e979c658Sreinoud return 0; 209*e979c658Sreinoud } 210*e979c658Sreinoud 211*e979c658Sreinoud 212*e979c658Sreinoud int 213*e979c658Sreinoud uscsi_check_for_scsi(struct uscsi_dev *disc) 214*e979c658Sreinoud { 215*e979c658Sreinoud struct uscsi_addr saddr; 216*e979c658Sreinoud 217*e979c658Sreinoud return uscsi_identify(disc, &saddr); 218*e979c658Sreinoud } 219*e979c658Sreinoud #endif /* SCSILIB_SCSIPI */ 220*e979c658Sreinoud 221*e979c658Sreinoud 222*e979c658Sreinoud 223*e979c658Sreinoud 224*e979c658Sreinoud #ifdef USCSI_LINUX_SCSI 225*e979c658Sreinoud /* 226*e979c658Sreinoud * Support code for Linux SCSI code. It uses the ioctl() way of 227*e979c658Sreinoud * communicating since this is more close to the origional NetBSD 228*e979c658Sreinoud * scsipi implementation. 229*e979c658Sreinoud */ 230*e979c658Sreinoud #include <scsi/sg.h> 231*e979c658Sreinoud #include <scsi/scsi.h> 232*e979c658Sreinoud 233*e979c658Sreinoud #define SENSEBUFLEN 48 234*e979c658Sreinoud 235*e979c658Sreinoud 236*e979c658Sreinoud int 237*e979c658Sreinoud uscsi_open(struct uscsi_dev * disc) 238*e979c658Sreinoud { 239*e979c658Sreinoud int flags; 240*e979c658Sreinoud struct stat stat; 241*e979c658Sreinoud 242*e979c658Sreinoud /* in Linux we are NOT allowed to open it blocking */ 243*e979c658Sreinoud /* no create! */ 244*e979c658Sreinoud disc->fhandle = open(disc->dev_name, O_RDWR | O_NONBLOCK, 0); 245*e979c658Sreinoud if (disc->fhandle<0) { 246*e979c658Sreinoud perror("Failure to open device or file"); 247*e979c658Sreinoud return ENODEV; 248*e979c658Sreinoud } 249*e979c658Sreinoud 250*e979c658Sreinoud /* explicitly mark it non blocking (again) (silly Linux) */ 251*e979c658Sreinoud flags = fcntl(disc->fhandle, F_GETFL); 252*e979c658Sreinoud flags &= ~O_NONBLOCK; 253*e979c658Sreinoud fcntl(disc->fhandle, F_SETFL, flags); 254*e979c658Sreinoud 255*e979c658Sreinoud if (fstat(disc->fhandle, &stat) < 0) { 256*e979c658Sreinoud perror("Can't stat device or file"); 257*e979c658Sreinoud uscsi_close(disc); 258*e979c658Sreinoud return ENODEV; 259*e979c658Sreinoud } 260*e979c658Sreinoud 261*e979c658Sreinoud return 0; 262*e979c658Sreinoud } 263*e979c658Sreinoud 264*e979c658Sreinoud 265*e979c658Sreinoud int 266*e979c658Sreinoud uscsi_close(struct uscsi_dev * disc) 267*e979c658Sreinoud { 268*e979c658Sreinoud close(disc->fhandle); 269*e979c658Sreinoud disc->fhandle = -1; 270*e979c658Sreinoud 271*e979c658Sreinoud return 0; 272*e979c658Sreinoud } 273*e979c658Sreinoud 274*e979c658Sreinoud 275*e979c658Sreinoud int 276*e979c658Sreinoud uscsi_command(int flags, struct uscsi_dev *disc, 277*e979c658Sreinoud void *cmd, size_t cmdlen, 278*e979c658Sreinoud void *data, size_t datalen, 279*e979c658Sreinoud uint32_t timeout, struct uscsi_sense *uscsi_sense) 280*e979c658Sreinoud { 281*e979c658Sreinoud struct sg_io_hdr req; 282*e979c658Sreinoud uint8_t sense_buffer[SENSEBUFLEN]; 283*e979c658Sreinoud int error; 284*e979c658Sreinoud 285*e979c658Sreinoud bzero(&req, sizeof(req)); 286*e979c658Sreinoud if (flags == SG_DXFER_FROM_DEV) bzero(data, datalen); 287*e979c658Sreinoud 288*e979c658Sreinoud req.interface_id = 'S'; 289*e979c658Sreinoud req.dxfer_direction = flags; 290*e979c658Sreinoud req.cmd_len = cmdlen; 291*e979c658Sreinoud req.mx_sb_len = SENSEBUFLEN; 292*e979c658Sreinoud req.iovec_count = 0; 293*e979c658Sreinoud req.dxfer_len = datalen; 294*e979c658Sreinoud req.dxferp = data; 295*e979c658Sreinoud req.cmdp = cmd; 296*e979c658Sreinoud req.sbp = sense_buffer; 297*e979c658Sreinoud req.flags = 0; 298*e979c658Sreinoud req.timeout = timeout; 299*e979c658Sreinoud 300*e979c658Sreinoud error = ioctl(disc->fhandle, SG_IO, &req); 301*e979c658Sreinoud 302*e979c658Sreinoud if (req.status) { 303*e979c658Sreinoud /* Is this OK? */ 304*e979c658Sreinoud if (uscsi_sense) { 305*e979c658Sreinoud uscsi_sense->asc = sense_buffer[12]; 306*e979c658Sreinoud uscsi_sense->ascq = sense_buffer[13]; 307*e979c658Sreinoud uscsi_sense->skey_valid = sense_buffer[15] & 128; 308*e979c658Sreinoud uscsi_sense->sense_key = (sense_buffer[16] << 8) | 309*e979c658Sreinoud (sense_buffer[17]); 310*e979c658Sreinoud } 311*e979c658Sreinoud if (uscsilib_verbose) { 312*e979c658Sreinoud uscsi_print_sense((char *) disc->dev_name, 313*e979c658Sreinoud cmd, cmdlen, sense_buffer, req.sb_len_wr, 1); 314*e979c658Sreinoud } 315*e979c658Sreinoud } 316*e979c658Sreinoud 317*e979c658Sreinoud return error; 318*e979c658Sreinoud } 319*e979c658Sreinoud 320*e979c658Sreinoud 321*e979c658Sreinoud int 322*e979c658Sreinoud uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr) 323*e979c658Sreinoud { 324*e979c658Sreinoud struct sg_scsi_id sg_scsi_id; 325*e979c658Sreinoud struct sg_id { 326*e979c658Sreinoud /* target | lun << 8 | channel << 16 | low_ino << 24 */ 327*e979c658Sreinoud uint32_t tlci; 328*e979c658Sreinoud uint32_t uniq_id; 329*e979c658Sreinoud } sg_id; 330*e979c658Sreinoud int emulated; 331*e979c658Sreinoud int error; 332*e979c658Sreinoud 333*e979c658Sreinoud /* clean result */ 334*e979c658Sreinoud bzero(saddr, sizeof(struct uscsi_addr)); 335*e979c658Sreinoud 336*e979c658Sreinoud /* check if its really SCSI or emulated SCSI (ATAPI f.e.) */ 337*e979c658Sreinoud saddr->type = USCSI_TYPE_SCSI; 338*e979c658Sreinoud ioctl(disc->fhandle, SG_EMULATED_HOST, &emulated); 339*e979c658Sreinoud if (emulated) saddr->type = USCSI_TYPE_ATAPI; 340*e979c658Sreinoud 341*e979c658Sreinoud /* try 2.4 kernel or older */ 342*e979c658Sreinoud error = ioctl(disc->fhandle, SG_GET_SCSI_ID, &sg_scsi_id); 343*e979c658Sreinoud if (!error) { 344*e979c658Sreinoud saddr->addr.scsi.target = sg_scsi_id.scsi_id; 345*e979c658Sreinoud saddr->addr.scsi.lun = sg_scsi_id.lun; 346*e979c658Sreinoud saddr->addr.scsi.scbus = sg_scsi_id.channel; 347*e979c658Sreinoud 348*e979c658Sreinoud return 0; 349*e979c658Sreinoud } 350*e979c658Sreinoud 351*e979c658Sreinoud /* 2.6 kernel or newer */ 352*e979c658Sreinoud error = ioctl(disc->fhandle, SCSI_IOCTL_GET_IDLUN, &sg_id); 353*e979c658Sreinoud if (error) return error; 354*e979c658Sreinoud 355*e979c658Sreinoud saddr->addr.scsi.target = (sg_id.tlci ) & 0xff; 356*e979c658Sreinoud saddr->addr.scsi.lun = (sg_id.tlci >> 8) & 0xff; 357*e979c658Sreinoud saddr->addr.scsi.scbus = (sg_id.tlci >> 16) & 0xff; 358*e979c658Sreinoud 359*e979c658Sreinoud return 0; 360*e979c658Sreinoud } 361*e979c658Sreinoud 362*e979c658Sreinoud 363*e979c658Sreinoud int uscsi_check_for_scsi(struct uscsi_dev *disc) { 364*e979c658Sreinoud struct uscsi_addr saddr; 365*e979c658Sreinoud 366*e979c658Sreinoud return uscsi_identify(disc, &saddr); 367*e979c658Sreinoud } 368*e979c658Sreinoud #endif /* USCSI_LINUX_SCSI */ 369*e979c658Sreinoud 370*e979c658Sreinoud 371*e979c658Sreinoud 372*e979c658Sreinoud 373*e979c658Sreinoud #ifdef USCSI_FREEBSD_CAM 374*e979c658Sreinoud 375*e979c658Sreinoud int 376*e979c658Sreinoud uscsi_open(struct uscsi_dev *disc) 377*e979c658Sreinoud { 378*e979c658Sreinoud disc->devhandle = cam_open_device(disc->dev_name, O_RDWR); 379*e979c658Sreinoud 380*e979c658Sreinoud if (disc->devhandle == NULL) { 381*e979c658Sreinoud disc->fhandle = open(disc->dev_name, O_RDWR | O_NONBLOCK, 0); 382*e979c658Sreinoud if (disc->fhandle < 0) { 383*e979c658Sreinoud perror("Failure to open device or file"); 384*e979c658Sreinoud return ENODEV; 385*e979c658Sreinoud } 386*e979c658Sreinoud } 387*e979c658Sreinoud 388*e979c658Sreinoud return 0; 389*e979c658Sreinoud } 390*e979c658Sreinoud 391*e979c658Sreinoud 392*e979c658Sreinoud int 393*e979c658Sreinoud uscsi_close(struct uscsi_dev *disc) 394*e979c658Sreinoud { 395*e979c658Sreinoud if (disc->devhandle != NULL) { 396*e979c658Sreinoud cam_close_device(disc->devhandle); 397*e979c658Sreinoud disc->devhandle = NULL; 398*e979c658Sreinoud } else { 399*e979c658Sreinoud close(disc->fhandle); 400*e979c658Sreinoud disc->fhandle = -1; 401*e979c658Sreinoud } 402*e979c658Sreinoud 403*e979c658Sreinoud return 0; 404*e979c658Sreinoud } 405*e979c658Sreinoud 406*e979c658Sreinoud 407*e979c658Sreinoud int 408*e979c658Sreinoud uscsi_command(int flags, struct uscsi_dev *disc, 409*e979c658Sreinoud void *cmd, size_t cmdlen, 410*e979c658Sreinoud void *data, size_t datalen, 411*e979c658Sreinoud uint32_t timeout, struct uscsi_sense *uscsi_sense) 412*e979c658Sreinoud { 413*e979c658Sreinoud struct cam_device *cam_dev; 414*e979c658Sreinoud struct scsi_sense_data *cam_sense_data; 415*e979c658Sreinoud union ccb ccb; 416*e979c658Sreinoud uint32_t cam_sense; 417*e979c658Sreinoud uint8_t *keypos; 418*e979c658Sreinoud int camflags; 419*e979c658Sreinoud 420*e979c658Sreinoud memset(&ccb, 0, sizeof(ccb)); 421*e979c658Sreinoud cam_dev = (struct cam_device *) disc->devhandle; 422*e979c658Sreinoud 423*e979c658Sreinoud if (datalen == 0) flags = SCSI_NODATACMD; 424*e979c658Sreinoud /* optional : */ 425*e979c658Sreinoud /* if (data) assert(flags == SCSI_NODATACMD); */ 426*e979c658Sreinoud 427*e979c658Sreinoud camflags = CAM_DIR_NONE; 428*e979c658Sreinoud if (flags & SCSI_READCMD) 429*e979c658Sreinoud camflags = CAM_DIR_IN; 430*e979c658Sreinoud if (flags & SCSI_WRITECMD) 431*e979c658Sreinoud camflags = CAM_DIR_OUT; 432*e979c658Sreinoud 433*e979c658Sreinoud cam_fill_csio( 434*e979c658Sreinoud &ccb.csio, 435*e979c658Sreinoud 0, /* retries */ 436*e979c658Sreinoud NULL, /* cbfcnp */ 437*e979c658Sreinoud camflags, /* flags */ 438*e979c658Sreinoud MSG_SIMPLE_Q_TAG, /* tag_action */ 439*e979c658Sreinoud (u_int8_t *) data, /* data_ptr */ 440*e979c658Sreinoud datalen, /* dxfer_len */ 441*e979c658Sreinoud SSD_FULL_SIZE, /* sense_len */ 442*e979c658Sreinoud cmdlen, /* cdb_len */ 443*e979c658Sreinoud timeout /* timeout */ 444*e979c658Sreinoud ); 445*e979c658Sreinoud 446*e979c658Sreinoud /* Disable freezing the device queue */ 447*e979c658Sreinoud ccb.ccb_h.flags |= CAM_DEV_QFRZDIS; 448*e979c658Sreinoud 449*e979c658Sreinoud memcpy(ccb.csio.cdb_io.cdb_bytes, cmd, cmdlen); 450*e979c658Sreinoud 451*e979c658Sreinoud /* Send the command down via the CAM interface */ 452*e979c658Sreinoud if (cam_send_ccb(cam_dev, &ccb) < 0) { 453*e979c658Sreinoud err(1, "cam_send_ccb"); 454*e979c658Sreinoud } 455*e979c658Sreinoud 456*e979c658Sreinoud if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 457*e979c658Sreinoud return 0; 458*e979c658Sreinoud 459*e979c658Sreinoud /* print error using the uscsi_sense routines? */ 460*e979c658Sreinoud 461*e979c658Sreinoud cam_sense = (ccb.ccb_h.status & (CAM_STATUS_MASK | CAM_AUTOSNS_VALID)); 462*e979c658Sreinoud if (cam_sense != (CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID)) 463*e979c658Sreinoud return EFAULT; 464*e979c658Sreinoud 465*e979c658Sreinoud /* drive responds with sense information */ 466*e979c658Sreinoud if (!uscsilib_verbose) 467*e979c658Sreinoud return EFAULT; 468*e979c658Sreinoud 469*e979c658Sreinoud /* print sense info */ 470*e979c658Sreinoud cam_sense_data = &ccb.csio.sense_data; 471*e979c658Sreinoud if (uscsi_sense) { 472*e979c658Sreinoud uscsi_sense->asc = cam_sense_data->add_sense_code; 473*e979c658Sreinoud uscsi_sense->ascq = cam_sense_data->add_sense_code_qual; 474*e979c658Sreinoud keypos = cam_sense_data->sense_key_spec; 475*e979c658Sreinoud uscsi_sense->skey_valid = keypos[0] & 128; 476*e979c658Sreinoud uscsi_sense->sense_key = (keypos[1] << 8) | (keypos[2]); 477*e979c658Sreinoud } 478*e979c658Sreinoud 479*e979c658Sreinoud uscsi_print_sense((char *) disc->dev_name, 480*e979c658Sreinoud cmd, cmdlen, 481*e979c658Sreinoud (uint8_t *) cam_sense_data, 8 + cam_sense_data->extra_len, 1); 482*e979c658Sreinoud 483*e979c658Sreinoud return EFAULT; 484*e979c658Sreinoud } 485*e979c658Sreinoud 486*e979c658Sreinoud 487*e979c658Sreinoud int 488*e979c658Sreinoud uscsi_identify(struct uscsi_dev *disc, struct uscsi_addr *saddr) 489*e979c658Sreinoud { 490*e979c658Sreinoud struct cam_device *cam_dev; 491*e979c658Sreinoud 492*e979c658Sreinoud /* clean result */ 493*e979c658Sreinoud bzero(saddr, sizeof(struct uscsi_addr)); 494*e979c658Sreinoud 495*e979c658Sreinoud cam_dev = (struct cam_device *) disc->devhandle; 496*e979c658Sreinoud if (!cam_dev) return ENODEV; 497*e979c658Sreinoud 498*e979c658Sreinoud /* check if its really SCSI or emulated SCSI (ATAPI f.e.) ? */ 499*e979c658Sreinoud saddr->type = USCSI_TYPE_SCSI; 500*e979c658Sreinoud saddr->addr.scsi.target = cam_dev->target_id; 501*e979c658Sreinoud saddr->addr.scsi.lun = cam_dev->target_lun; 502*e979c658Sreinoud saddr->addr.scsi.scbus = cam_dev->bus_id; 503*e979c658Sreinoud 504*e979c658Sreinoud return 0; 505*e979c658Sreinoud } 506*e979c658Sreinoud 507*e979c658Sreinoud 508*e979c658Sreinoud int 509*e979c658Sreinoud uscsi_check_for_scsi(struct uscsi_dev *disc) 510*e979c658Sreinoud { 511*e979c658Sreinoud struct uscsi_addr saddr; 512*e979c658Sreinoud 513*e979c658Sreinoud return uscsi_identify(disc, &saddr); 514*e979c658Sreinoud } 515*e979c658Sreinoud 516*e979c658Sreinoud #endif /* USCSI_FREEBSD_CAM */ 517*e979c658Sreinoud 518*e979c658Sreinoud 519*e979c658Sreinoud 520*e979c658Sreinoud /* 521*e979c658Sreinoud * Generic SCSI funtions also used by the sense printing functionality. 522*e979c658Sreinoud * FreeBSD support has it allready asked for by the CAM. 523*e979c658Sreinoud */ 524*e979c658Sreinoud 525*e979c658Sreinoud int 526*e979c658Sreinoud uscsi_mode_sense(struct uscsi_dev *dev, 527*e979c658Sreinoud uint8_t pgcode, uint8_t pctl, void *buf, size_t len) 528*e979c658Sreinoud { 529*e979c658Sreinoud scsicmd cmd; 530*e979c658Sreinoud 531*e979c658Sreinoud bzero(buf, len); /* initialise recieving buffer */ 532*e979c658Sreinoud 533*e979c658Sreinoud bzero(cmd, SCSI_CMD_LEN); 534*e979c658Sreinoud cmd[ 0] = 0x1a; /* MODE SENSE */ 535*e979c658Sreinoud cmd[ 1] = 0; /* - */ 536*e979c658Sreinoud cmd[ 2] = pgcode | pctl; /* page code and control flags */ 537*e979c658Sreinoud cmd[ 3] = 0; /* - */ 538*e979c658Sreinoud cmd[ 4] = len; /* length of recieve buffer */ 539*e979c658Sreinoud cmd[ 5] = 0; /* control */ 540*e979c658Sreinoud 541*e979c658Sreinoud return uscsi_command(SCSI_READCMD, dev, &cmd, 6, buf, len, 10000, NULL); 542*e979c658Sreinoud } 543*e979c658Sreinoud 544*e979c658Sreinoud 545*e979c658Sreinoud int 546*e979c658Sreinoud uscsi_mode_select(struct uscsi_dev *dev, 547*e979c658Sreinoud uint8_t byte2, void *buf, size_t len) 548*e979c658Sreinoud { 549*e979c658Sreinoud scsicmd cmd; 550*e979c658Sreinoud 551*e979c658Sreinoud bzero(cmd, SCSI_CMD_LEN); 552*e979c658Sreinoud cmd[ 0] = 0x15; /* MODE SELECT */ 553*e979c658Sreinoud cmd[ 1] = 0x10 | byte2; /* SCSI-2 page format select */ 554*e979c658Sreinoud cmd[ 4] = len; /* length of page settings */ 555*e979c658Sreinoud cmd[ 5] = 0; /* control */ 556*e979c658Sreinoud 557*e979c658Sreinoud return uscsi_command(SCSI_WRITECMD, dev, &cmd, 6, buf, len, 558*e979c658Sreinoud 10000, NULL); 559*e979c658Sreinoud } 560*e979c658Sreinoud 561*e979c658Sreinoud 562*e979c658Sreinoud int 563*e979c658Sreinoud uscsi_request_sense(struct uscsi_dev *dev, void *buf, size_t len) 564*e979c658Sreinoud { 565*e979c658Sreinoud scsicmd cmd; 566*e979c658Sreinoud 567*e979c658Sreinoud bzero(buf, len); /* initialise recieving buffer */ 568*e979c658Sreinoud 569*e979c658Sreinoud bzero(cmd, SCSI_CMD_LEN); 570*e979c658Sreinoud cmd[ 0] = 0x03; /* REQUEST SENSE */ 571*e979c658Sreinoud cmd[ 4] = len; /* length of data to be read */ 572*e979c658Sreinoud cmd[ 5] = 0; /* control */ 573*e979c658Sreinoud 574*e979c658Sreinoud return uscsi_command(SCSI_WRITECMD, dev, &cmd, 6, buf, len, 575*e979c658Sreinoud 10000, NULL); 576*e979c658Sreinoud } 577*e979c658Sreinoud 578*e979c658Sreinoud 579*e979c658Sreinoud /* end of uscsi_subr.c */ 580*e979c658Sreinoud 581