📄 scsi-bsd.c
字号:
* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#undef sense#define scsi_sense CAM_scsi_sense#define scsi_inquiry CAM_scsi_inquiry#include <sys/param.h>#include <cam/cam.h>#include <cam/cam_ccb.h>#include <cam/scsi/scsi_message.h>#include <cam/scsi/scsi_pass.h>#include <camlib.h>#define CAM_MAXDEVS 128struct cam_device *cam_devices[CAM_MAXDEVS + 1];/* * Build a list of everything we can find. */EXPORTint scsi_open(device, busno, tgt, tlun) char *device; int busno; int tgt; int tlun;{ struct cam_device *dev; char name[16]; int unit; int nopen = 0; union ccb ccb; int bufsize; struct periph_match_pattern *match_pat; int fd; for (unit = 0; unit <= CAM_MAXDEVS; unit++) { cam_devices[unit] = (struct cam_device *)-1; } /* * If we're not scanning the bus, just open one device. */ if (busno >= 0 && tgt >= 0 && tlun >= 0) { cam_devices[0] = cam_open_btl(busno, tgt, tlun, O_RDWR, NULL); if (cam_devices[0] == NULL) return(-1); nopen++; return(nopen); } /* * First open the transport layer device. There's no point in the * rest of this if we can't open it. */ if ((fd = open(XPT_DEVICE, O_RDWR)) < 0) { errmsg("Open of %s failed.\n", XPT_DEVICE); /* XXX Should be removed */ return(-1); } fillbytes(&ccb, sizeof(union ccb), '\0'); /* * Get a list of up to CAM_MAXDEVS passthrough devices in the * system. */ ccb.ccb_h.func_code = XPT_DEV_MATCH; /* * Setup the result buffer. */ bufsize = sizeof(struct dev_match_result) * CAM_MAXDEVS; ccb.cdm.match_buf_len = bufsize; ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); if (ccb.cdm.matches == NULL) { errmsg("Couldn't malloc match buffer.\n"); /* XXX Should be removed */ close(fd); return(-1); } ccb.cdm.num_matches = 0; /* * Setup the pattern buffer. We're matching against all * peripherals named "pass". */ ccb.cdm.num_patterns = 1; ccb.cdm.pattern_buf_len = sizeof(struct dev_match_pattern); ccb.cdm.patterns = (struct dev_match_pattern *)malloc( sizeof(struct dev_match_pattern)); if (ccb.cdm.patterns == NULL) { errmsg("Couldn't malloc pattern buffer.\n"); /* XXX Should be removed */ close(fd); free(ccb.cdm.matches); return(-1); } ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH; match_pat = &ccb.cdm.patterns[0].pattern.periph_pattern; sprintf(match_pat->periph_name, "pass"); match_pat->flags = PERIPH_MATCH_NAME; if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { errmsg("CAMIOCOMMAND ioctl failed.\n"); /* XXX Should be removed */ close(fd); free(ccb.cdm.matches); free(ccb.cdm.patterns); return(-1); } if ((ccb.ccb_h.status != CAM_REQ_CMP) || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { errmsgno(EX_BAD, "Got CAM error 0x%X, CDM error %d.\n", ccb.ccb_h.status, ccb.cdm.status); close(fd); free(ccb.cdm.matches); free(ccb.cdm.patterns); return(-1); } free(ccb.cdm.patterns); close(fd); for (unit = 0; unit < MIN(CAM_MAXDEVS, ccb.cdm.num_matches); unit++) { struct periph_match_result *periph_result; /* * We shouldn't have anything other than peripheral * matches in here. If we do, it means an error in the * device matching code in the transport layer. */ if (ccb.cdm.matches[unit].type != DEV_MATCH_PERIPH) { errmsgno(EX_BAD, "Kernel error! got periph match type %d!!\n", ccb.cdm.matches[unit].type); free(ccb.cdm.matches); return(-1); } periph_result = &ccb.cdm.matches[unit].result.periph_result; sprintf(name, "/dev/%s%d", periph_result->periph_name, periph_result->unit_number); /* * cam_open_pass() avoids all lookup and translation from * "regular device name" to passthrough unit number and * just opens the device in question as a passthrough device. */ cam_devices[unit] = cam_open_pass(name, O_RDWR, NULL); /* * If we get back NULL from the open routine, it wasn't * able to open the given passthrough device for one reason * or another. */ if (cam_devices[unit] == NULL) { errmsgno(EX_BAD, "Error opening /dev/%s%d\n", periph_result->periph_name, periph_result->unit_number); errmsgno(EX_BAD, "%s\n", cam_errbuf); break; } nopen++; } free(ccb.cdm.matches); return (nopen);}LOCALlong scsi_maxdma(){ return (MAXPHYS);}EXPORT void *scsi_getbuf(amt) long amt;{ void *ret; if (scg_maxdma == 0) scg_maxdma = MAXPHYS; if (amt <= 0 || amt > scg_maxdma) return ((void *)0); if (debug) printf("scsi_getbuf: %ld bytes\n", amt); ret = valloc((size_t)(amt)); return (ret);}EXPORTBOOL scsi_havebus(int busno){ int unit; /* * There's a "cleaner" way to do this, using the matching code, but * it would involve more code than this solution... */ for (unit = 0; cam_devices[unit] != (struct cam_device *)-1; unit++) { if (cam_devices[unit] == NULL) continue; if (cam_devices[unit]->path_id == busno) return (TRUE); } return (FALSE);}EXPORTint scsi_fileno(bus, unit, lun){ int i; for (i = 0; cam_devices[i] != (struct cam_device *)-1; i++) { if (cam_devices[i] == NULL) continue; if ((cam_devices[i]->path_id == bus) && (cam_devices[i]->target_id == unit) && (cam_devices[i]->target_lun == lun)) return (i); } return (-1);}EXPORTint scsi_isatapi(){ return (FALSE);}EXPORTint scsireset(){ /* XXX synchronous reset command - is this wise? */ return (-1);}LOCAL intscsi_send(int unit, struct scg_cmd *sp){ struct cam_device *dev; union ccb ccb_space; union ccb *ccb = &ccb_space; int rv, result; u_int32_t ccb_flags; if (unit < 0) {#if 0 fprintf(stderr, "attempt to reference invalid unit %d\n", unit);#endif sp->error = SCG_FATAL; return (0); } dev = cam_devices[unit]; fillbytes(&ccb->ccb_h, sizeof(struct ccb_hdr), '\0'); ccb->ccb_h.path_id = dev->path_id; ccb->ccb_h.target_id = dev->target_id; ccb->ccb_h.target_lun = dev->target_lun; /* Build the CCB */ fillbytes(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio), '\0'); movebytes(sp->cdb.cmd_cdb, &ccb->csio.cdb_io.cdb_bytes, sp->cdb_len); /* * Set the data direction flags. */ if (sp->size != 0) { ccb_flags = (sp->flags & SCG_RECV_DATA) ? CAM_DIR_IN : CAM_DIR_OUT; } else { ccb_flags = CAM_DIR_NONE; } ccb_flags |= CAM_DEV_QFRZDIS; /* * If you don't want to bother with sending tagged commands under CAM, * we don't need to do anything to cdrecord. If you want to send * tagged commands to those devices that support it, we'll need to set * the tag action valid field like this in scsi_send(): * * ccb_flags |= CAM_DEV_QFRZDIS | CAM_TAG_ACTION_VALID; */ cam_fill_csio(&ccb->csio, /* retries */ 1, /* cbfncp */ NULL, /* flags */ ccb_flags, /* tag_action */ MSG_SIMPLE_Q_TAG, /* data_ptr */ (u_int8_t *)sp->addr, /* dxfer_len */ sp->size, /* sense_len */ SSD_FULL_SIZE, /* cdb_len */ sp->cdb_len, /* timeout */ sp->timeout * 1000); /* Run the command */ errno = 0; if ((rv = cam_send_ccb(dev, ccb)) == -1) { return (rv); } else { /* * Check for command status. Selection timeouts are fatal. * For command timeouts, we pass back the appropriate * error. If we completed successfully, there's (obviously) * no error. We declare anything else "retryable". */ switch(ccb->ccb_h.status & CAM_STATUS_MASK) { case CAM_SEL_TIMEOUT: result = SCG_FATAL; break; case CAM_CMD_TIMEOUT: result = SCG_TIMEOUT; break; case CAM_REQ_CMP: result = SCG_NO_ERROR; break; default: result = SCG_RETRYABLE; break; } } sp->error = result; if (result != SCG_NO_ERROR) sp->ux_errno = EIO; /* Pass the result back up */ fillbytes(&sp->scb, sizeof(sp->scb), '\0'); fillbytes(&sp->u_sense.cmd_sense, sizeof(sp->u_sense.cmd_sense), '\0'); sp->resid = ccb->csio.resid; sp->sense_count = SSD_FULL_SIZE - ccb->csio.sense_resid; /* * Determine how much room we have for sense data. */ if (sp->sense_count > SCG_MAX_SENSE) sp->sense_count = SCG_MAX_SENSE; /* Copy the sense data out */ movebytes(&ccb->csio.sense_data, &sp->u_sense.cmd_sense, sp->sense_count); sp->u_scb.cmd_scb[0] = ccb->csio.scsi_status; return (0);}#undef scsi_sense#undef scsi_inquiry#define sense u_sense.Sense#endif /* BSD_CAM */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -