int sd_vpd_block_limits(struct sd_softc *sc, int flags) { struct scsi_vpd_disk_limits *pg; int rv; pg = dma_alloc(sizeof(*pg), (ISSET(flags, SCSI_NOSLEEP) ? PR_NOWAIT : PR_WAITOK) | PR_ZERO); if (pg == NULL) return (ENOMEM); rv = scsi_inquire_vpd(sc->sc_link, pg, sizeof(*pg), SI_PG_DISK_LIMITS, flags); if (rv != 0) goto done; if (_2btol(pg->hdr.page_length) == SI_PG_DISK_LIMITS_LEN_THIN) { sc->params.unmap_sectors = _4btol(pg->max_unmap_lba_count); sc->params.unmap_descs = _4btol(pg->max_unmap_desc_count); } else rv = EOPNOTSUPP; done: dma_free(pg, sizeof(*pg)); return (rv); }
/* * sd_read_capacity: * * Find out from the device what its capacity is. */ static uint64_t sd_read_capacity(struct sd_softc *sd, int *blksize) { union { struct scsipi_read_capacity_10 cmd; struct scsipi_read_capacity_16 cmd16; } cmd; union { struct scsipi_read_capacity_10_data data; struct scsipi_read_capacity_16_data data16; } data; uint64_t rv; memset(&cmd, 0, sizeof(cmd)); cmd.cmd.opcode = READ_CAPACITY_10; /* * If the command works, interpret the result as a 4 byte * number of blocks */ rv = 0; memset(&data, 0, sizeof(data.data)); if (scsi_command(sd, (void *)&cmd.cmd, sizeof(cmd.cmd), (void *)&data, sizeof(data.data)) != 0) goto out; if (_4btol(data.data.addr) != 0xffffffff) { *blksize = _4btol(data.data.length); rv = _4btol(data.data.addr) + 1; goto out; } /* * Device is larger than can be reflected by READ CAPACITY (10). * Try READ CAPACITY (16). */ memset(&cmd, 0, sizeof(cmd)); cmd.cmd16.opcode = READ_CAPACITY_16; cmd.cmd16.byte2 = SRC16_SERVICE_ACTION; _lto4b(sizeof(data.data16), cmd.cmd16.len); memset(&data, 0, sizeof(data.data16)); if (scsi_command(sd, (void *)&cmd.cmd16, sizeof(cmd.cmd16), (void *)&data, sizeof(data.data16)) != 0) goto out; *blksize = _4btol(data.data16.length); rv = _8btol(data.data16.addr) + 1; out: return rv; }
int sd_read_cap_10(struct sd_softc *sc, int flags) { struct scsi_read_capacity cdb; struct scsi_read_cap_data *rdcap; struct scsi_xfer *xs; int rv = ENOMEM; CLR(flags, SCSI_IGNORE_ILLEGAL_REQUEST); rdcap = dma_alloc(sizeof(*rdcap), (ISSET(flags, SCSI_NOSLEEP) ? PR_NOWAIT : PR_WAITOK) | PR_ZERO); if (rdcap == NULL) return (ENOMEM); xs = scsi_xs_get(sc->sc_link, flags | SCSI_DATA_IN | SCSI_SILENT); if (xs == NULL) goto done; bzero(&cdb, sizeof(cdb)); cdb.opcode = READ_CAPACITY; memcpy(xs->cmd, &cdb, sizeof(cdb)); xs->cmdlen = sizeof(cdb); xs->data = (void *)rdcap; xs->datalen = sizeof(*rdcap); xs->timeout = 20000; rv = scsi_xs_sync(xs); scsi_xs_put(xs); if (rv == 0) { sc->params.disksize = _4btol(rdcap->addr) + 1ll; sc->params.secsize = _4btol(rdcap->length); CLR(sc->flags, SDF_THIN); } done: dma_free(rdcap, sizeof(*rdcap)); return (rv); }
SANE_Status sane_start (SANE_Handle handle) { char *mode_str; Ibm_Scanner *s = handle; SANE_Status status; struct ibm_window_data wbuf; struct measurements_units_page mup; DBG (11, ">> sane_start\n"); /* First make sure we have a current parameter set. Some of the parameters will be overwritten below, but that's OK. */ status = sane_get_parameters (s, 0); if (status != SANE_STATUS_GOOD) return status; status = sanei_scsi_open (s->hw->sane.name, &s->fd, 0, 0); if (status != SANE_STATUS_GOOD) { DBG (1, "open of %s failed: %s\n", s->hw->sane.name, sane_strstatus (status)); return (status); } mode_str = s->val[OPT_MODE].s; s->xres = s->val[OPT_X_RESOLUTION].w; s->yres = s->val[OPT_Y_RESOLUTION].w; s->ulx = s->val[OPT_TL_X].w; s->uly = s->val[OPT_TL_Y].w; s->width = s->val[OPT_BR_X].w - s->val[OPT_TL_X].w; s->length = s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w; s->brightness = s->val[OPT_BRIGHTNESS].w; s->contrast = s->val[OPT_CONTRAST].w; s->bpp = s->params.depth; if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_LINEART) == 0) { s->image_composition = IBM_BINARY_MONOCHROME; } else if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_HALFTONE) == 0) { s->image_composition = IBM_DITHERED_MONOCHROME; } else if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_GRAY) == 0) { s->image_composition = IBM_GRAYSCALE; } memset (&wbuf, 0, sizeof (wbuf)); /* next line commented out by mf */ /* _lto2b(sizeof(wbuf) - 8, wbuf.len); */ /* next line by mf */ _lto2b(IBM_WINDOW_DATA_SIZE, wbuf.len); /* size=320 */ _lto2b(s->xres, wbuf.x_res); _lto2b(s->yres, wbuf.y_res); _lto4b(s->ulx, wbuf.x_org); _lto4b(s->uly, wbuf.y_org); _lto4b(s->width, wbuf.width); _lto4b(s->length, wbuf.length); wbuf.image_comp = s->image_composition; /* if you throw the MRIF bit the brighness control reverses too */ /* so I reverse the reversal in software for symmetry's sake */ if (wbuf.image_comp == IBM_GRAYSCALE || wbuf.image_comp == IBM_DITHERED_MONOCHROME) { if (wbuf.image_comp == IBM_GRAYSCALE) wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x80; /* it was 0x90 */ if (wbuf.image_comp == IBM_DITHERED_MONOCHROME) wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x10; wbuf.brightness = 256 - (SANE_Byte) s->brightness; /* if (is50) wbuf.contrast = (SANE_Byte) s->contrast; else */ wbuf.contrast = 256 - (SANE_Byte) s->contrast; } else /* wbuf.image_comp == IBM_BINARY_MONOCHROME */ { wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x00; wbuf.brightness = (SANE_Byte) s->brightness; wbuf.contrast = (SANE_Byte) s->contrast; } wbuf.threshold = 0; wbuf.bits_per_pixel = s->bpp; wbuf.halftone_code = 2; /* diithering */ wbuf.halftone_id = 0x0A; /* 8x8 Bayer pattenr */ wbuf.pad_type = 3; wbuf.bit_ordering[0] = 0; wbuf.bit_ordering[1] = 7; /* modified by mf (it was 3) */ DBG (5, "xres=%d\n", _2btol(wbuf.x_res)); DBG (5, "yres=%d\n", _2btol(wbuf.y_res)); DBG (5, "ulx=%d\n", _4btol(wbuf.x_org)); DBG (5, "uly=%d\n", _4btol(wbuf.y_org)); DBG (5, "width=%d\n", _4btol(wbuf.width)); DBG (5, "length=%d\n", _4btol(wbuf.length)); DBG (5, "image_comp=%d\n", wbuf.image_comp); DBG (11, "sane_start: sending SET WINDOW\n"); status = set_window (s->fd, &wbuf); if (status != SANE_STATUS_GOOD) { DBG (1, "SET WINDOW failed: %s\n", sane_strstatus (status)); return (status); } DBG (11, "sane_start: sending GET WINDOW\n"); memset (&wbuf, 0, sizeof (wbuf)); status = get_window (s->fd, &wbuf); if (status != SANE_STATUS_GOOD) { DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status)); return (status); } DBG (5, "xres=%d\n", _2btol(wbuf.x_res)); DBG (5, "yres=%d\n", _2btol(wbuf.y_res)); DBG (5, "ulx=%d\n", _4btol(wbuf.x_org)); DBG (5, "uly=%d\n", _4btol(wbuf.y_org)); DBG (5, "width=%d\n", _4btol(wbuf.width)); DBG (5, "length=%d\n", _4btol(wbuf.length)); DBG (5, "image_comp=%d\n", wbuf.image_comp); DBG (11, "sane_start: sending MODE SELECT\n"); memset (&mup, 0, sizeof (mup)); mup.page_code = MEASUREMENTS_PAGE; mup.parameter_length = 0x06; mup.bmu = INCHES; mup.mud[0] = (DEFAULT_MUD >> 8) & 0xff; mup.mud[1] = (DEFAULT_MUD & 0xff); /* next lines by mf */ mup.adf_page_code = 0x26; mup.adf_parameter_length = 6; if (s->adf_state == ADF_ARMED) mup.adf_control = 1; else mup.adf_control = 0; /* end lines by mf */ status = mode_select (s->fd, (struct mode_pages *) &mup); if (status != SANE_STATUS_GOOD) { DBG (1, "attach: MODE_SELECT failed\n"); return (SANE_STATUS_INVAL); } status = trigger_scan (s->fd); if (status != SANE_STATUS_GOOD) { DBG (1, "start of scan failed: %s\n", sane_strstatus (status)); /* next line introduced not to freeze xscanimage */ do_cancel(s); return status; } /* Wait for scanner to become ready to transmit data */ status = ibm_wait_ready (s); if (status != SANE_STATUS_GOOD) { DBG (1, "GET DATA STATUS failed: %s\n", sane_strstatus (status)); return (status); } s->bytes_to_read = s->params.bytes_per_line * s->params.lines; DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, " "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line, s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_Y_RESOLUTION].w); s->scanning = SANE_TRUE; DBG (11, "<< sane_start\n"); return (SANE_STATUS_GOOD); }
void vdsk_scsi_cmd(struct scsi_xfer *xs) { struct scsi_rw *rw; struct scsi_rw_big *rwb; struct scsi_rw_12 *rw12; struct scsi_rw_16 *rw16; u_int64_t lba; u_int32_t sector_count; uint8_t operation; switch (xs->cmd->opcode) { case READ_BIG: case READ_COMMAND: case READ_12: case READ_16: operation = VD_OP_BREAD; break; case WRITE_BIG: case WRITE_COMMAND: case WRITE_12: case WRITE_16: operation = VD_OP_BWRITE; break; case SYNCHRONIZE_CACHE: operation = VD_OP_FLUSH; break; case INQUIRY: vdsk_scsi_inq(xs); return; case READ_CAPACITY: vdsk_scsi_capacity(xs); return; case READ_CAPACITY_16: vdsk_scsi_capacity16(xs); return; case TEST_UNIT_READY: case START_STOP: case PREVENT_ALLOW: vdsk_scsi_done(xs, XS_NOERROR); return; default: printf("%s cmd 0x%02x\n", __func__, xs->cmd->opcode); case MODE_SENSE: case MODE_SENSE_BIG: case REPORT_LUNS: case READ_TOC: vdsk_scsi_done(xs, XS_DRIVER_STUFFUP); return; } /* * READ/WRITE/SYNCHRONIZE commands. SYNCHRONIZE CACHE has same * layout as 10-byte READ/WRITE commands. */ if (xs->cmdlen == 6) { rw = (struct scsi_rw *)xs->cmd; lba = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff); sector_count = rw->length ? rw->length : 0x100; } else if (xs->cmdlen == 10) { rwb = (struct scsi_rw_big *)xs->cmd; lba = _4btol(rwb->addr); sector_count = _2btol(rwb->length); } else if (xs->cmdlen == 12) { rw12 = (struct scsi_rw_12 *)xs->cmd; lba = _4btol(rw12->addr); sector_count = _4btol(rw12->length); } else if (xs->cmdlen == 16) { rw16 = (struct scsi_rw_16 *)xs->cmd; lba = _8btol(rw16->addr); sector_count = _4btol(rw16->length); } { struct vdsk_softc *sc = xs->sc_link->adapter_softc; struct ldc_map *map = sc->sc_lm; struct vio_dring_msg dm; vaddr_t va; paddr_t pa; psize_t nbytes; int len, ncookies; int desc, s; int timeout; s = splbio(); desc = sc->sc_tx_prod; ncookies = 0; len = xs->datalen; va = (vaddr_t)xs->data; while (len > 0) { KASSERT(ncookies < MAXPHYS / PAGE_SIZE); pmap_extract(pmap_kernel(), va, &pa); while (map->lm_slot[map->lm_next].entry != 0) { map->lm_next++; map->lm_next &= (map->lm_nentries - 1); } map->lm_slot[map->lm_next].entry = (pa & LDC_MTE_RA_MASK); map->lm_slot[map->lm_next].entry |= LDC_MTE_CPR | LDC_MTE_CPW; map->lm_slot[map->lm_next].entry |= LDC_MTE_IOR | LDC_MTE_IOW; map->lm_slot[map->lm_next].entry |= LDC_MTE_R | LDC_MTE_W; map->lm_count++; nbytes = MIN(len, PAGE_SIZE - (pa & PAGE_MASK)); sc->sc_vd->vd_desc[desc].cookie[ncookies].addr = map->lm_next << PAGE_SHIFT | (pa & PAGE_MASK); sc->sc_vd->vd_desc[desc].cookie[ncookies].size = nbytes; sc->sc_vsd[desc].vsd_map_idx[ncookies] = map->lm_next; va += nbytes; len -= nbytes; ncookies++; } sc->sc_vd->vd_desc[desc].hdr.ack = 1; sc->sc_vd->vd_desc[desc].operation = operation; sc->sc_vd->vd_desc[desc].slice = VD_SLICE_NONE; sc->sc_vd->vd_desc[desc].status = 0xffffffff; sc->sc_vd->vd_desc[desc].offset = lba; sc->sc_vd->vd_desc[desc].size = xs->datalen; sc->sc_vd->vd_desc[desc].ncookies = ncookies; membar(Sync); sc->sc_vd->vd_desc[desc].hdr.dstate = VIO_DESC_READY; sc->sc_vsd[desc].vsd_xs = xs; sc->sc_vsd[desc].vsd_ncookies = ncookies; sc->sc_tx_prod++; sc->sc_tx_prod &= (sc->sc_vd->vd_nentries - 1); bzero(&dm, sizeof(dm)); dm.tag.type = VIO_TYPE_DATA; dm.tag.stype = VIO_SUBTYPE_INFO; dm.tag.stype_env = VIO_DRING_DATA; dm.tag.sid = sc->sc_local_sid; dm.seq_no = sc->sc_seq_no++; dm.dring_ident = sc->sc_dring_ident; dm.start_idx = dm.end_idx = desc; vdsk_sendmsg(sc, &dm, sizeof(dm)); if (!ISSET(xs->flags, SCSI_POLL)) { splx(s); return; } timeout = 1000; do { if (vdsk_rx_intr(sc) && sc->sc_vd->vd_desc[desc].status == VIO_DESC_FREE) break; delay(1000); } while(--timeout > 0); splx(s); } }
void scsipi_print_sense_data_real(struct scsi_sense_data *sense, int verbosity) { int32_t info; int i, j, k; char *sbs, *s = (char *) sense; /* * Basics- print out SENSE KEY */ printf(" SENSE KEY: %s", scsipi_decode_sense(s, 0)); /* * Print out, unqualified but aligned, FMK, EOM and ILI status. */ if (s[2] & 0xe0) { char pad; printf("\n "); pad = ' '; if (s[2] & SSD_FILEMARK) { printf("%c Filemark Detected", pad); pad = ','; } if (s[2] & SSD_EOM) { printf("%c EOM Detected", pad); pad = ','; } if (s[2] & SSD_ILI) printf("%c Incorrect Length Indicator Set", pad); } /* * Now we should figure out, based upon device type, how * to format the information field. Unfortunately, that's * not convenient here, so we'll print it as a signed * 32 bit integer. */ info = _4btol(&s[3]); if (info) printf("\n INFO FIELD: %d", info); /* * Now we check additional length to see whether there is * more information to extract. */ /* enough for command specific information? */ if (((unsigned int) s[7]) < 4) { printf("\n"); return; } info = _4btol(&s[8]); if (info) printf("\n COMMAND INFO: %d (0x%x)", info, info); /* * Decode ASC && ASCQ info, plus FRU, plus the rest... */ sbs = scsipi_decode_sense(s, 1); if (sbs) printf("\n ASC/ASCQ: %s", sbs); if (s[14] != 0) printf("\n FRU CODE: 0x%x", s[14] & 0xff); sbs = scsipi_decode_sense(s, 3); if (sbs) printf("\n SKSV: %s", sbs); printf("\n"); if (verbosity == 0) { printf("\n"); return; } /* * Now figure whether we should print any additional informtion. * * Where should we start from? If we had SKSV data, * start from offset 18, else from offset 15. * * From that point until the end of the buffer, check for any * nonzero data. If we have some, go back and print the lot, * otherwise we're done. */ if (sbs) i = 18; else i = 15; for (j = i; j < sizeof (*sense); j++) if (s[j]) break; if (j == sizeof (*sense)) return; printf("\n Additional Sense Information (byte %d out...):\n", i); if (i == 15) { printf("\n\t%2d:", i); k = 7; } else { printf("\n\t%2d:", i); k = 2; j -= 2; } while (j > 0) { if (i >= sizeof (*sense)) break; if (k == 8) { k = 0; printf("\n\t%2d:", i); } printf(" 0x%02x", s[i] & 0xff); k++; j--; i++; } printf("\n\n"); }
/*--------------------------------------------------------------------------- * *--------------------------------------------------------------------------*/ int scsi_init(char *devname) { char *inq_buf; #ifdef DIXTRAC_LINUX_SG #ifdef SG_NONBLOCKING int ictl_val; #endif #ifdef SG_NONBLOCKING int fd = open(devname, O_RDWR | O_NONBLOCK); #else int fd = open(devname, O_RDWR); #endif if (fd < 0) { error_handler("Device %s not defined or no R/W permmissions.\n",devname); } #ifdef SG_NONBLOCKING ictl_val = 1; if ( 0 > ioctl(fd,SG_SET_COMMAND_Q,&ictl_val)) { if (errno == ENOTTY) ictl_val = 0; else error_handler("Problems with ioctl on device %s \n",devname); } /* #ifndef SILENT */ #if 0 printf("Command queueing%s allowed.\n",(ictl_val == 1 ? "" : " not")); #endif ictl_val = 0; /* if ( 0 > ioctl(fd,SG_SET_FORCE_PACK_ID,&ictl_val)) { error_handler("Could not set FORCE_PACK_ID on device %s \n",devname); } */ ictl_val = BIG_BUF_SIZE; if ( 0 > ioctl(fd,SG_SET_RESERVED_SIZE,&ictl_val)) { error_handler("Problems with ioctl on device %s!\n",devname); } ioctl(fd,SG_GET_RESERVED_SIZE,&ictl_val); /* #ifndef SILENT */ #if 0 fprintf(stderr, "*** The size of the RESERVED kernel buffer: %d\n",ictl_val); /* ioctl(fd,SG_GET_SG_TABLESIZE,&ictl_val); */ /* printf("TABLESIZE: %d\n",ictl_val); */ #endif #endif #ifdef STATE_THREADS if (st_init()) { error_handler("Problems with st_init!\n"); } if (!(scsidev_fd = st_netfd_open(fd))) { error_handler("Opening sthread fd failed\n", devname); } #else scsidev_fd = fd; #endif /* DIXTRAC_LINUX_SG */ #endif #ifdef DIXTRAC_FREEBSD_CAM if (cam_open_pass(devname, O_RDWR, &cam_device) == NULL) { error_handler("Opening pass device (%s) failed\n", devname); } #endif inq_buf = scsi_alloc_buffer(); /* get_scsi_version */ send_scsi_command(inq_buf, SCSI_inq_command(),0); recv_scsi_command(inq_buf); scsi_version = ((u_int8_t) inq_buf[2]); /* get the device block size (not all disks use 512-byte sector) */ exec_scsi_command(inq_buf,SCSI_read_capacity(0,0)); /* this is a global that is accessed through te SECT_SIZE macro */ blksize = _4btol((u_int8_t *) &inq_buf[4]); return(0); }
int scsi_probe_target(struct scsibus_softc *sc, int target) { struct scsi_link *alink = sc->adapter_link; struct scsi_link *link; struct scsi_report_luns_data *report; int i, nluns, lun; if (scsi_probe_lun(sc, target, 0) == EINVAL) return (EINVAL); link = sc->sc_link[target][0]; if (link == NULL) return (ENXIO); if ((link->flags & (SDEV_UMASS | SDEV_ATAPI)) == 0 && SCSISPC(link->inqdata.version) > 2) { report = malloc(sizeof(*report), M_TEMP, M_WAITOK); if (report == NULL) goto dumbscan; if (scsi_report_luns(link, REPORT_NORMAL, report, sizeof(*report), scsi_autoconf | SCSI_SILENT | SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY | SCSI_IGNORE_MEDIA_CHANGE, 10000) != 0) { free(report, M_TEMP); goto dumbscan; } /* * XXX In theory we should check if data is full, which * would indicate it needs to be enlarged and REPORT * LUNS tried again. Solaris tries up to 3 times with * larger sizes for data. */ nluns = _4btol(report->length) / RPL_LUNDATA_SIZE; for (i = 0; i < nluns; i++) { if (report->luns[i].lundata[0] != 0) continue; lun = report->luns[i].lundata[RPL_LUNDATA_T0LUN]; if (lun == 0) continue; /* Probe the provided LUN. Don't check LUN 0. */ sc->sc_link[target][0] = NULL; scsi_probe_lun(sc, target, lun); sc->sc_link[target][0] = link; } free(report, M_TEMP); return (0); } dumbscan: for (i = 1; i < alink->luns; i++) { if (scsi_probe_lun(sc, target, i) == EINVAL) break; } return (0); }
/* * Get the scsi driver to send a full inquiry to the * device and use the * results to fill out the disk parameter structure. */ static int sd_get_capacity(struct sd_softc *sd) { struct disk_parms *dp = &sd->sc_params; uint64_t blocks; int error, blksize; dp->disksize = blocks = sd_read_capacity(sd, &blksize); if (blocks == 0) { struct scsipi_read_format_capacities cmd; struct { struct scsipi_capacity_list_header header; struct scsipi_capacity_descriptor desc; } __packed data; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = READ_FORMAT_CAPACITIES; _lto2b(sizeof(data), cmd.length); error = scsi_command(sd, (void *)&cmd, sizeof(cmd), (void *)&data, sizeof(data)); if (error == EFTYPE) /* Medium Format Corrupted, handle as not formatted */ return SDGP_RESULT_UNFORMATTED; if (error || data.header.length == 0) return SDGP_RESULT_OFFLINE; switch (data.desc.byte5 & SCSIPI_CAP_DESC_CODE_MASK) { case SCSIPI_CAP_DESC_CODE_RESERVED: case SCSIPI_CAP_DESC_CODE_FORMATTED: break; case SCSIPI_CAP_DESC_CODE_UNFORMATTED: return SDGP_RESULT_UNFORMATTED; case SCSIPI_CAP_DESC_CODE_NONE: return SDGP_RESULT_OFFLINE; } dp->disksize = blocks = _4btol(data.desc.nblks); if (blocks == 0) return SDGP_RESULT_OFFLINE; /* XXX? */ blksize = _3btol(data.desc.blklen); } else if (!sd_validate_blksize(blksize)) { struct sd_mode_sense_data scsipi_sense; int bsize; memset(&scsipi_sense, 0, sizeof(scsipi_sense)); error = scsi_mode_sense(sd, 0, 0, &scsipi_sense.header, sizeof(struct scsi_mode_parameter_header_6) + sizeof(scsipi_sense.blk_desc)); if (!error) { bsize = scsipi_sense.header.blk_desc_len; if (bsize >= 8) blksize = _3btol(scsipi_sense.blk_desc.blklen); } } if (!sd_validate_blksize(blksize)) blksize = SD_DEFAULT_BLKSIZE; dp->blksize = blksize; dp->disksize512 = (blocks * dp->blksize) / DEV_BSIZE; return 0; }
/* * scsi_interpret_sense: * * Look at the returned sense and act on the error, determining * the unix error number to pass back. (0 = report no error) * * NOTE: If we return ERESTART, we are expected to haved * thawed the device! * * THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES. */ static int scsi_interpret_sense(struct siop_adapter *adp, struct scsi_xfer *xs) { struct scsi_sense_data *sense; u_int8_t key; int error; uint32_t info; static const char *error_mes[] = { "soft error (corrected)", "not ready", "medium error", "non-media hardware failure", "illegal request", "unit attention", "readonly device", "no data found", "vendor unique", "copy aborted", "command aborted", "search returned equal", "volume overflow", "verify miscompare", "unknown error key" }; sense = (struct scsi_sense_data *)xs->data; DPRINTF((" sense debug information:\n")); DPRINTF(("\tcode 0x%x valid %d\n", SSD_RCODE(sense->response_code), sense->response_code & SSD_RCODE_VALID ? 1 : 0)); DPRINTF(("\tseg 0x%x key 0x%x ili 0x%x eom 0x%x fmark 0x%x\n", sense->segment, SSD_SENSE_KEY(sense->flags), sense->flags & SSD_ILI ? 1 : 0, sense->flags & SSD_EOM ? 1 : 0, sense->flags & SSD_FILEMARK ? 1 : 0)); DPRINTF(("\ninfo: 0x%x 0x%x 0x%x 0x%x followed by %d " "extra bytes\n", sense->info[0], sense->info[1], sense->info[2], sense->info[3], sense->extra_len)); switch (SSD_RCODE(sense->response_code)) { /* * Old SCSI-1 and SASI devices respond with * codes other than 70. */ case 0x00: /* no error (command completed OK) */ return 0; case 0x04: /* drive not ready after it was selected */ if (adp->sd->sc_flags & FLAGS_REMOVABLE) adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED; /* XXX - display some sort of error here? */ return EIO; case 0x20: /* invalid command */ return EINVAL; case 0x25: /* invalid LUN (Adaptec ACB-4000) */ return EACCES; /* * If it's code 70, use the extended stuff and * interpret the key */ case 0x71: /* delayed error */ key = SSD_SENSE_KEY(sense->flags); printf(" DEFERRED ERROR, key = 0x%x\n", key); /* FALLTHROUGH */ case 0x70: if ((sense->response_code & SSD_RCODE_VALID) != 0) info = _4btol(sense->info); else info = 0; key = SSD_SENSE_KEY(sense->flags); switch (key) { case SKEY_NO_SENSE: case SKEY_RECOVERED_ERROR: if (xs->resid == xs->datalen && xs->datalen) { /* * Why is this here? */ xs->resid = 0; /* not short read */ } case SKEY_EQUAL: error = 0; break; case SKEY_NOT_READY: if (adp->sd->sc_flags & FLAGS_REMOVABLE) adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED; if (sense->asc == 0x3A) { error = ENODEV; /* Medium not present */ } else error = EIO; break; case SKEY_ILLEGAL_REQUEST: error = EINVAL; break; case SKEY_UNIT_ATTENTION: if (sense->asc == 0x29 && sense->ascq == 0x00) { /* device or bus reset */ return ERESTART; } if (adp->sd->sc_flags & FLAGS_REMOVABLE) adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED; if (!(adp->sd->sc_flags & FLAGS_REMOVABLE)) return ERESTART; error = EIO; break; case SKEY_DATA_PROTECT: error = EROFS; break; case SKEY_BLANK_CHECK: error = 0; break; case SKEY_ABORTED_COMMAND: break; case SKEY_VOLUME_OVERFLOW: error = ENOSPC; break; default: error = EIO; break; } /* Print brief(er) sense information */ printf("%s", error_mes[key - 1]); if ((sense->response_code & SSD_RCODE_VALID) != 0) { switch (key) { case SKEY_NOT_READY: case SKEY_ILLEGAL_REQUEST: case SKEY_UNIT_ATTENTION: case SKEY_DATA_PROTECT: break; case SKEY_BLANK_CHECK: printf(", requested size: %d (decimal)", info); break; case SKEY_ABORTED_COMMAND: printf(", cmd 0x%x, info 0x%x", xs->cmd->opcode, info); break; default: printf(", info = %d (decimal)", info); } } if (sense->extra_len != 0) { int n; printf(", data ="); for (n = 0; n < sense->extra_len; n++) printf(" %x", sense->csi[n]); } printf("\n"); return error; /* * Some other code, just report it */ default: printf("Sense Error Code 0x%x", SSD_RCODE(sense->response_code)); if ((sense->response_code & SSD_RCODE_VALID) != 0) { struct scsi_sense_data_unextended *usense = (struct scsi_sense_data_unextended *)sense; printf(" at block no. %d (decimal)", _3btol(usense->block)); } printf("\n"); return EIO; } }