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