/* * Load the current IE mode pages */ static int load_ie_modepage(ds_scsi_info_t *sip) { struct scsi_ms_hdrs junk_hdrs; int result; uint_t skey, asc, ascq; if (!(sip->si_supp_mode & MODEPAGE_SUPP_IEC)) return (0); bzero(&sip->si_iec_current, sizeof (sip->si_iec_current)); bzero(&sip->si_iec_changeable, sizeof (sip->si_iec_changeable)); if ((result = scsi_mode_sense(sip, MODEPAGE_INFO_EXCPT, PC_CURRENT, &sip->si_iec_current, MODEPAGE_INFO_EXCPT_LEN, &sip->si_hdrs, &skey, &asc, &ascq)) == 0) { result = scsi_mode_sense(sip, MODEPAGE_INFO_EXCPT, PC_CHANGEABLE, &sip->si_iec_changeable, MODEPAGE_INFO_EXCPT_LEN, &junk_hdrs, &skey, &asc, &ascq); } if (result != 0) { printf("failed to get IEC modepage (KEY=0x%x " "ASC=0x%x ASCQ=0x%x)", skey, asc, ascq); sip->si_supp_mode &= ~MODEPAGE_SUPP_IEC; } else { if (nvlist_add_boolean_value(sip->si_state_iec, "dexcpt", sip->si_iec_current.ie_dexcpt) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "logerr", sip->si_iec_current.ie_logerr) != 0 || nvlist_add_uint8(sip->si_state_iec, "mrie", sip->si_iec_current.ie_mrie) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "test", sip->si_iec_current.ie_test) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "ewasc", sip->si_iec_current.ie_ewasc) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "perf", sip->si_iec_current.ie_perf) != 0 || nvlist_add_boolean_value(sip->si_state_iec, "ebf", sip->si_iec_current.ie_ebf) != 0 || nvlist_add_uint32(sip->si_state_iec, "interval-timer", BE_32(sip->si_iec_current.ie_interval_timer)) != 0 || nvlist_add_uint32(sip->si_state_iec, "report-count", BE_32(sip->si_iec_current.ie_report_count)) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); } return (0); }
/* * Clear the GLTSD bit, indicating log pages should be saved to non-volatile * storage. */ static int clear_gltsd(ds_scsi_info_t *sip) { scsi_ms_hdrs_t hdrs, junk_hdrs; struct mode_control_scsi3 control_pg_cur, control_pg_chg; int result; uint_t skey, asc, ascq; bzero(&hdrs, sizeof (hdrs)); bzero(&control_pg_cur, sizeof (control_pg_cur)); bzero(&control_pg_chg, sizeof (control_pg_chg)); result = scsi_mode_sense(sip, MODEPAGE_CTRL_MODE, PC_CURRENT, &control_pg_cur, MODEPAGE_CTRL_MODE_LEN, &hdrs, &skey, &asc, &ascq); if (result != 0) { printf("failed to read Control mode page (KEY=0x%x " "ASC=0x%x ASCQ=0x%x)\n", skey, asc, ascq); } else if (control_pg_cur.mode_page.length != PAGELENGTH_MODE_CONTROL_SCSI3) { printf("SCSI-3 control mode page not supported\n"); } else if ((result = scsi_mode_sense(sip, MODEPAGE_CTRL_MODE, PC_CHANGEABLE, &control_pg_chg, MODEPAGE_CTRL_MODE_LEN, &junk_hdrs, &skey, &asc, &ascq)) != 0) { printf("failed to read changeable Control mode page (KEY=0x%x " "ASC=0x%x ASCQ=0x%x)\n", skey, asc, ascq); } else if (control_pg_cur.gltsd && !GLTSD_CHANGEABLE(control_pg_chg)) { printf("gltsd is set and not changeable\n"); if (nvlist_add_boolean_value(sip->si_dsp->ds_state, "gltsd", control_pg_cur.gltsd) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); } else if (control_pg_cur.gltsd) { control_pg_cur.gltsd = 0; result = scsi_mode_select(sip, MODEPAGE_CTRL_MODE, MODE_SELECT_PF, &control_pg_cur, MODEPAGE_CTRL_MODE_LEN, &hdrs, &skey, &asc, &ascq); if (result != 0) printf("failed to enable GLTSD (KEY=0x%x " "ASC=0x%x ASCQ=0x%x\n", skey, asc, ascq); if (nvlist_add_boolean_value(sip->si_dsp->ds_state, "gltsd", control_pg_cur.gltsd) != 0) return (scsi_set_errno(sip, EDS_NOMEM)); } return (0); }
static int sd_get_simplifiedparms(struct sd_softc *sd) { struct { struct scsi_mode_parameter_header_6 header; /* no block descriptor */ uint8_t pg_code; /* page code (should be 6) */ uint8_t pg_length; /* page length (should be 11) */ uint8_t wcd; /* bit0: cache disable */ uint8_t lbs[2]; /* logical block size */ uint8_t size[5]; /* number of log. blocks */ uint8_t pp; /* power/performance */ uint8_t flags; uint8_t resvd; } scsipi_sense; struct disk_parms *dp = &sd->sc_params; uint64_t blocks; int error, blksize; /* * sd_read_capacity (ie "read capacity") and mode sense page 6 * give the same information. Do both for now, and check * for consistency. * XXX probably differs for removable media */ dp->blksize = SD_DEFAULT_BLKSIZE; if ((blocks = sd_read_capacity(sd, &blksize)) == 0) return SDGP_RESULT_OFFLINE; /* XXX? */ error = scsi_mode_sense(sd, SMS_DBD, 6, &scsipi_sense.header, sizeof(scsipi_sense)); if (error != 0) return SDGP_RESULT_OFFLINE; /* XXX? */ dp->blksize = blksize; if (!sd_validate_blksize(dp->blksize)) dp->blksize = _2btol(scsipi_sense.lbs); if (!sd_validate_blksize(dp->blksize)) dp->blksize = SD_DEFAULT_BLKSIZE; /* * Create a pseudo-geometry. */ dp->heads = 64; dp->sectors = 32; dp->cyls = blocks / (dp->heads * dp->sectors); dp->disksize = _5btol(scsipi_sense.size); if (dp->disksize <= UINT32_MAX && dp->disksize != blocks) { printf("RBC size: mode sense=%llu, get cap=%llu\n", (unsigned long long)dp->disksize, (unsigned long long)blocks); dp->disksize = blocks; } dp->disksize512 = (dp->disksize * dp->blksize) / DEV_BSIZE; return SDGP_RESULT_OK; }
static ssize_t sd_store_cache_type(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int i, ct = -1, rcd, wce, sp; struct scsi_disk *sdkp = to_scsi_disk(dev); struct scsi_device *sdp = sdkp->device; char buffer[64]; char *buffer_data; struct scsi_mode_data data; struct scsi_sense_hdr sshdr; int len; if (sdp->type != TYPE_DISK) /* no cache control on RBC devices; theoretically they * can do it, but there's probably so many exceptions * it's not worth the risk */ return -EINVAL; for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) { len = strlen(sd_cache_types[i]); if (strncmp(sd_cache_types[i], buf, len) == 0 && buf[len] == '\n') { ct = i; break; } } if (ct < 0) return -EINVAL; rcd = ct & 0x01 ? 1 : 0; wce = ct & 0x02 ? 1 : 0; if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT, SD_MAX_RETRIES, &data, NULL)) return -EINVAL; len = min_t(size_t, sizeof(buffer), data.length - data.header_length - data.block_descriptor_length); buffer_data = buffer + data.header_length + data.block_descriptor_length; buffer_data[2] &= ~0x05; buffer_data[2] |= wce << 2 | rcd; sp = buffer_data[0] & 0x80 ? 1 : 0; if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT, SD_MAX_RETRIES, &data, &sshdr)) { if (scsi_sense_valid(&sshdr)) sd_print_sense_hdr(sdkp, &sshdr); return -EINVAL; } revalidate_disk(sdkp->disk); return count; }
/* * Load mode pages and check that the appropriate pages are supported. * * As part of this process, we determine which form of the MODE SENSE / MODE * SELECT command to use (the 6-byte or 10-byte version) by executing a MODE * SENSE command for a page that should be implemented by the device. */ static int load_modepages(ds_scsi_info_t *sip) { int allpages_buflen; uchar_t *allpages; scsi_ms_hdrs_t headers; int result; uint_t skey, asc, ascq; int datalength = 0; scsi_ms_header_t *smh = &headers.ms_hdr.g0; scsi_ms_header_g1_t *smh_g1 = &headers.ms_hdr.g1; nvlist_t *nvl; allpages_buflen = MAX_BUFLEN(scsi_ms_header_g1_t); if ((allpages = calloc(allpages_buflen, 1)) == NULL) return (scsi_set_errno(sip, EDS_NOMEM)); bzero(&headers, sizeof (headers)); /* * Attempt a mode sense(6). If that fails, try a mode sense(10) * * allpages is allocated to be of the maximum size for either a mode * sense(6) or mode sense(10) MODEPAGE_ALLPAGES response. * * Note that the length passed into uscsi_mode_sense should be set to * the maximum size of the parameter response, which in this case is * UCHAR_MAX - the size of the headers/block descriptors. */ sip->si_cdblen = MODE_CMD_LEN_6; if ((result = scsi_mode_sense(sip, MODEPAGE_ALLPAGES, PC_CURRENT, (caddr_t)allpages, UCHAR_MAX - sizeof (scsi_ms_header_t), &headers, &skey, &asc, &ascq)) == 0) { /* * Compute the data length of the page that contains all mode * sense pages. This is a bit tricky because the format of the * response from the lun is: * * header: <length> <medium type byte> <dev specific byte> * <block descriptor length> * [<optional block descriptor>] * data: [<mode page data> <mode page data> ...] * * Since the length field in the header describes the length of * the entire response. This includes the header, but NOT * the length field itself, which is 1 or 2 bytes depending on * which mode sense type (6- or 10- byte) is being executed. * * So, the data length equals the length value in the header * plus 1 (because the length byte was not included in the * length count), minus [[the sum of the length of the header * and the length of the block descriptor]]. */ datalength = (smh->ms_header.length + sizeof (smh->ms_header.length)) - (sizeof (struct mode_header) + smh->ms_header.bdesc_length); } else if (SCSI_INVALID_OPCODE(skey, asc, ascq)) { /* * Fallback and try the 10-byte version of the command. */ sip->si_cdblen = MODE_CMD_LEN_10; result = scsi_mode_sense(sip, MODEPAGE_ALLPAGES, PC_CURRENT, (caddr_t)allpages, allpages_buflen, &headers, &skey, &asc, &ascq); if (result == 0) { datalength = (BE_16(smh_g1->ms_header.length) + sizeof (smh_g1->ms_header.length)) - (sizeof (struct mode_header_g1) + BE_16(smh_g1->ms_header.bdesc_length)); } } if (result == 0 && datalength >= 0) { if (nvlist_add_int8(sip->si_dsp->ds_state, "command-length", sip->si_cdblen == MODE_CMD_LEN_6 ? 6 : 10) != 0) { free(allpages); return (scsi_set_errno(sip, EDS_NOMEM)); } nvl = NULL; if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || nvlist_add_nvlist(sip->si_dsp->ds_state, "modepages", nvl) != 0) { free(allpages); nvlist_free(nvl); return (scsi_set_errno(sip, EDS_NOMEM)); } nvlist_free(nvl); result = nvlist_lookup_nvlist(sip->si_dsp->ds_state, "modepages", &sip->si_state_modepage); assert(result == 0); /* * One of the sets of the commands (above) succeeded, so now * look for the mode pages we need and record them appropriately */ if (mode_page_present(allpages, datalength, MODEPAGE_INFO_EXCPT)) { nvl = NULL; if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 || nvlist_add_nvlist(sip->si_state_modepage, "informational-exceptions", nvl) != 0) { free(allpages); nvlist_free(nvl); return (scsi_set_errno(sip, EDS_NOMEM)); } nvlist_free(nvl); sip->si_supp_mode |= MODEPAGE_SUPP_IEC; result = nvlist_lookup_nvlist(sip->si_state_modepage, "informational-exceptions", &sip->si_state_iec); assert(result == 0); } } else { /* * If the device failed to respond to one of the basic commands, * then assume it's not a SCSI device or otherwise doesn't * support the necessary transport. */ if (datalength < 0) printf("command returned invalid data length (%d)\n", datalength); else printf("failed to load modepages (KEY=0x%x " "ASC=0x%x ASCQ=0x%x)\n", skey, asc, ascq); result = scsi_set_errno(sip, EDS_NO_TRANSPORT); } free(allpages); return (result); }
static int sd_get_parms_page5(struct sd_softc *sd, struct disk_parms *dp) { struct sd_mode_sense_data scsipi_sense; union scsi_disk_pages *pages; size_t poffset; int byte2, error; byte2 = SMS_DBD; again: memset(&scsipi_sense, 0, sizeof(scsipi_sense)); error = scsi_mode_sense(sd, 0, 5, &scsipi_sense.header, (byte2 ? 0 : sizeof(scsipi_sense.blk_desc)) + sizeof(scsipi_sense.pages.flex_geometry)); if (error) { if (byte2 == SMS_DBD) { /* No result; try once more with DBD off */ byte2 = 0; goto again; } return error; } poffset = sizeof(scsipi_sense.header); poffset += scsipi_sense.header.blk_desc_len; if (poffset > sizeof(scsipi_sense) - sizeof(pages->flex_geometry)) return ERESTART; pages = (void *)((u_long)&scsipi_sense + poffset); #if 0 { size_t i; u_int8_t *p; printf("page 5 sense:"); for (i = sizeof(scsipi_sense), p = (void *)&scsipi_sense; i; i--, p++) printf(" %02x", *p); printf("\n"); printf("page 5 pg_code=%d sense=%p/%p\n", pages->flex_geometry.pg_code, &scsipi_sense, pages); } #endif if ((pages->flex_geometry.pg_code & PGCODE_MASK) != 5) return ERESTART; dp->heads = pages->flex_geometry.nheads; dp->cyls = _2btol(pages->flex_geometry.ncyl); dp->sectors = pages->flex_geometry.ph_sec_tr; if (dp->heads == 0 || dp->cyls == 0 || dp->sectors == 0) return ERESTART; dp->rot_rate = _2btol(pages->rigid_geometry.rpm); if (dp->rot_rate == 0) dp->rot_rate = 3600; #if 0 printf("page 5 ok\n"); #endif return 0; }
static int sd_get_parms_page4(struct sd_softc *sd, struct disk_parms *dp) { struct sd_mode_sense_data scsipi_sense; union scsi_disk_pages *pages; size_t poffset; int byte2, error; byte2 = SMS_DBD; again: memset(&scsipi_sense, 0, sizeof(scsipi_sense)); error = scsi_mode_sense(sd, byte2, 4, &scsipi_sense.header, (byte2 ? 0 : sizeof(scsipi_sense.blk_desc)) + sizeof(scsipi_sense.pages.rigid_geometry)); if (error) { if (byte2 == SMS_DBD) { /* No result; try once more with DBD off */ byte2 = 0; goto again; } return error; } poffset = sizeof(scsipi_sense.header); poffset += scsipi_sense.header.blk_desc_len; if (poffset > sizeof(scsipi_sense) - sizeof(pages->rigid_geometry)) return ERESTART; pages = (void *)((u_long)&scsipi_sense + poffset); #if 0 { size_t i; u_int8_t *p; printf("page 4 sense:"); for (i = sizeof(scsipi_sense), p = (void *)&scsipi_sense; i; i--, p++) printf(" %02x", *p); printf("\n"); printf("page 4 pg_code=%d sense=%p/%p\n", pages->rigid_geometry.pg_code, &scsipi_sense, pages); } #endif if ((pages->rigid_geometry.pg_code & PGCODE_MASK) != 4) return ERESTART; /* * KLUDGE!! (for zone recorded disks) * give a number of sectors so that sec * trks * cyls * is <= disk_size * can lead to wasted space! THINK ABOUT THIS ! */ dp->heads = pages->rigid_geometry.nheads; dp->cyls = _3btol(pages->rigid_geometry.ncyl); if (dp->heads == 0 || dp->cyls == 0) return ERESTART; dp->sectors = dp->disksize / (dp->heads * dp->cyls); /* XXX */ dp->rot_rate = _2btol(pages->rigid_geometry.rpm); if (dp->rot_rate == 0) dp->rot_rate = 3600; #if 0 printf("page 4 ok\n"); #endif 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; }
/*ARGSUSED*/ scsi_ret_t scdisk_open( target_info_t *tgt, io_req_t req) { register int i; register scsi_ret_t ret = SCSI_RET_SUCCESS; unsigned int disk_size, secs_per_cyl, sector_size; unsigned int nsectors, ntracks, ncylinders; scsi_rcap_data_t *cap; struct disklabel *label = 0; io_req_t ior; void (*readfun)( target_info_t *tgt, unsigned int secno, io_req_t ior) = scdisk_read; char *data, *rdata = 0; boolean_t look_for_label; if (tgt->flags & TGT_ONLINE) return SCSI_RET_SUCCESS; tgt->lun = rzlun(req->io_unit); /* * Dummy ior for proper sync purposes */ io_req_alloc(ior); bzero((char *)ior, sizeof(*ior)); simple_lock_init(&(ior)->io_req_lock, ETAP_IO_REQ); #if 0 /* * Set the LBN to tgt->block_size with a MODE SELECT. * xxx do a MODE SENSE instead ? */ /* * Ugh. Can't use tgt->block_size here -- not set up * yet. Also can't use DEV_BSIZE. So...since MK6 * dispenses with this command entirely, let's do * so as well. */ for (i = 0; i < 5; i++) { ior->io_op = IO_INTERNAL; ior->io_error = 0; ret = scdisk_mode_select(tgt, tgt->block_size, ior,0,0,FALSE); if (ret == SCSI_RET_SUCCESS) break; if (ret == SCSI_RET_RETRY) { timeout((timeout_fcn_t)wakeup, tgt, 2*hz); await(tgt); } if (ret == SCSI_RET_DEVICE_DOWN) goto done; } if (ret != SCSI_RET_SUCCESS) { scsi_error( tgt, SCSI_ERR_MSEL, ret, 0); ret = D_INVALID_SIZE; goto done; } #endif #ifdef hp_pa if (tgt->flags & TGT_REMOVABLE_MEDIA) { scsi_mode_sense_page5_t *page5; unsigned char mode_save[0xff]; scsi_mode_select_param_t *parm; int length; if((ret = scsi_mode_sense(tgt, 0x05, 0xff, 0)) != SCSI_RET_SUCCESS) goto done; length = *tgt->cmd_ptr + 1; bcopy(tgt->cmd_ptr, mode_save, length); page5 = (scsi_mode_sense_page5_t *)(mode_save + 4 + mode_save[3]); #if 1 /* force sector size to 512 */ parm = (scsi_mode_select_param_t *)mode_save; parm->reserved1 = 0; parm->medium_type = 2; parm->device_spec &= ~0x90; parm->descs[0].density_code = 2; parm->descs[0].nblocks1 = 0; parm->descs[0].nblocks2 = 0; parm->descs[0].nblocks3 = 0; parm->descs[0].reclen1 = 0x2; parm->descs[0].reclen2 = 0; parm->descs[0].reclen3 = 0; page5->ps = 0; page5->page_code &= ~0x80; page5->sectors_per_track = page5->sectors_per_track * (page5->bytes_per_sector_msb << 8 | page5->bytes_per_sector_lsb) / 512; page5->bytes_per_sector_msb = 2; page5->bytes_per_sector_lsb = 0; length -= parm->desc_len; parm->desc_len = 0; bcopy((const char*)page5, mode_save+4, sizeof(*page5)); if((ret = scdisk_mode_select(tgt, 0, 0, mode_save, length, 0)) != SCSI_RET_SUCCESS) goto done; if((ret = scsi_mode_sense(tgt, 0x05, 0xff, 0)) != SCSI_RET_SUCCESS) goto done; length = *tgt->cmd_ptr + 1; bcopy(tgt->cmd_ptr, mode_save, length); #endif ntracks = page5->number_of_heads; nsectors = page5->sectors_per_track; sector_size = page5->bytes_per_sector_msb << 8 | page5->bytes_per_sector_lsb; ncylinders = page5->number_of_cylinders_msb << 8 | page5->number_of_cylinders_lsb; secs_per_cyl = nsectors * ntracks; look_for_label = FALSE; geom_done = TRUE; } #endif /* * Do a READ CAPACITY to get max size. Check LBN too. */ for (i = 0; i < 5; i++) { ior->io_op = IO_INTERNAL; ior->io_error = 0; ret = scsi_read_capacity(tgt, 0, ior); if (ret == SCSI_RET_SUCCESS) break; if (ret == SCSI_RET_RETRY) { timeout((timeout_fcn_t)wakeup, tgt, 2*hz); await(tgt); } if (ret == SCSI_RET_DEVICE_DOWN) goto done; } if (ret != SCSI_RET_SUCCESS) { scsi_error( tgt, SCSI_ERR_MSEL, ret, 0); ret = D_INVALID_SIZE; goto done; } cap = (scsi_rcap_data_t*) tgt->cmd_ptr; disk_size = (cap->lba1<<24) | (cap->lba2<<16) | (cap->lba3<< 8) | cap->lba4 + 1; if (scsi_debug) printf("rz%d holds %d blocks\n", tgt->unit_no, disk_size); tgt->block_size = (cap->blen1<<24) | (cap->blen2<<16) | (cap->blen3<<8 ) | cap->blen4; if (scsi_debug) { printf("rz%d block size is %d bytes/block\n", tgt->unit_no, tgt->block_size); } if (tgt->block_size > RZDISK_MAX_SECTOR || tgt->block_size <= 0) { ret = D_INVALID_SIZE; goto done; } rdata = (char *) kalloc(2*tgt->block_size); if (round_page(rdata) == round_page(rdata + tgt->block_size)) data = rdata; else data = (char *)round_page(rdata); #ifdef POWERMAC /* XXX TODO NMGS remove! must be cache aligned for now */ if ((unsigned long)data & 0x1f) data = (char*)((unsigned long)(data + 0x1f) & ~0x1f); if (round_page(data) != round_page(data + tgt->block_size)) data = (char *)round_page(data); #endif /* POWERMAC */ if (disk_size > SCSI_CMD_READ_MAX_LBA) tgt->flags |= TGT_BIG; /* * Mandatory long-form commands ? */ if (BGET(scsi_use_long_form,(unsigned char)tgt->masterno,tgt->target_id)) tgt->flags |= TGT_BIG; if (tgt->flags & TGT_BIG) readfun = scsi_long_read; ior->io_op = IO_INTERNAL; ior->io_error = 0; #ifdef hp_pa if(geom_done) goto setup_label; #endif /* * Find out about the phys disk geometry */ #if PARAGON860 /* * The NCR RAID controller does not support a read capacity command * with the Partial Medium Indicator (PMI) bit set. Therefore we * have to calculate the number of sectors per cylinder from data * in the mode select pages. This method should work for standalone * disks as well. */ /* * Read page 3 to find the number of sectors/track and bytes/sector */ ret = scsi_mode_sense(tgt, 0x03, 0xff, ior); /* scsi_error(...) */ { scsi_mode_sense_page3_t *page3; page3 = (scsi_mode_sense_page3_t *) (((scsi_mode_sense_data_t *)tgt->cmd_ptr) + 1); nsectors = (page3->sectors_per_track_msb << 8) | page3->sectors_per_track_lsb; sector_size = (page3->bytes_per_sector_msb << 8) | page3->bytes_per_sector_lsb; } ior->io_op = IO_INTERNAL; ior->io_error = 0; /* * Read page 4 to find the number of cylinders and tracks/cylinder */ ret = scsi_mode_sense(tgt, 0x04, 0xff, ior); /* scsi_error(...) */ { scsi_mode_sense_page4_t *page4; page4 = (scsi_mode_sense_page4_t *) (((scsi_mode_sense_data_t *)tgt->cmd_ptr) + 1); ncylinders = (page4->number_of_cylinders_msb << 16) | (page4->number_of_cylinders << 8) | page4->number_of_cylinders_lsb; ntracks = page4->number_of_heads; } /* * Calculate the sectors per cylinder (sec/track * tracks/cyl) */ secs_per_cyl = nsectors * ntracks; if (scsi_debug) { printf("rz%d: %d bytes/sec %d sec/track\n", tgt->unit_no, sector_size, nsectors); printf(" %d tracks/cyl %d cyl/unit\n", ntracks, ncylinders); } #else /* PARAGON860 */ /* Read page one to get read / write error recovery info */ ret = scsi_mode_sense(tgt, 0x01, 0xff, ior); if(ret == SCSI_RET_SUCCESS) { scsi_mode_sense_page1_t *page1; unsigned char mode_save[0xff]; int length; length = *tgt->cmd_ptr + 1; bcopy(tgt->cmd_ptr, mode_save, length); page1 = (scsi_mode_sense_page1_t *)(mode_save + 4 + mode_save[3]); *mode_save = 0; /* mode data length */ page1->ps = 0; page1->flags = PAGE1_AWRE | PAGE1_ARRE | PAGE1_TB | PAGE1_PER; /* * Enable automatic reallocation of bad blocks, * Report any recovered errors. */ ior->io_op = IO_INTERNAL; ior->io_error = 0; ret = scdisk_mode_select(tgt, 0, ior, mode_save, length, 0); if(ret != SCSI_RET_SUCCESS) { if (scsi_debug) printf("rz%d: Can't change error recovery parameters\n", tgt->unit_no); } } ior->io_op = IO_INTERNAL; ior->io_error = 0; #ifdef POWERMAC tgt->flags |= TGT_OPTIONAL_CMD; #endif ret = scsi_read_capacity( tgt, 1, ior); #ifdef POWERMAC tgt->flags &= ~TGT_OPTIONAL_CMD; #endif /* scsi_error(...) */ if (ret) { secs_per_cyl = 16; sector_size = tgt->block_size; } else { cap = (scsi_rcap_data_t*) tgt->cmd_ptr; secs_per_cyl = (cap->lba1<<24) | (cap->lba2<<16) | (cap->lba3<< 8) | cap->lba4; secs_per_cyl += 1; sector_size = (cap->blen1<<24) | (cap->blen2<<16) | (cap->blen3<<8 ) | cap->blen4; } if (scsi_debug) printf("rz%d: %d sect/cyl %d bytes/sec\n", tgt->unit_no, secs_per_cyl, sector_size); #endif /* PARAGON860 */ #if NSCSI2 > 0 /* * ... and a bunch of other things for scsi2 */ #endif /* NSCSI2 > 0 */ /* * Get partition table off pack */ if (tgt->dev_ops == &scsi_devsw[SCSI_CDROM]) { /* no label on a CD-ROM */ look_for_label = FALSE; } else { look_for_label = TRUE; } setup_label: if (look_for_label) { /* first look for a BSD label */ ior->io_data = data; ior->io_count = tgt->block_size; ior->io_op = IO_READ; ior->io_error = 0; tgt->ior = ior; (*readfun)( tgt, LABELOFFSET/tgt->block_size, ior); iowait(ior); if (!ior->io_error) { /* Search for BSD label, might be a bit further along */ register int j; for (i = LABELOFFSET % tgt->block_size; i < (tgt->block_size-sizeof(struct disklabel)); i += sizeof(int)) { label = (struct disklabel *) &data[i]; if (label->d_magic == DISKMAGIC && label->d_magic2 == DISKMAGIC) { break; } else label = (struct disklabel *) 0; } } } else { label = (struct disklabel *) 0; } if (label) { if (scsi_debug) printf("{Using BSD label}"); tgt->dev_info.disk.l = *label; } else { /* then look for a vendor's label, but first fill in defaults and what we found */ label = &tgt->dev_info.disk.l; *label = scsi_default_label; label->d_secsize = sector_size; label->d_nsectors = nsectors; label->d_ntracks = ntracks; label->d_ncylinders = ncylinders; label->d_secpercyl = secs_per_cyl; label->d_secperunit = disk_size; ior->io_data = data; if (!look_for_label || !rz_vendor_label(tgt, label, ior)) { if (look_for_label) { printf("%s rz%d, %s\n", "WARNING: No valid disk label on", tgt->unit_no, "using defaults"); } /* Validate partitions a and c for initialization */ tgt->dev_info.disk.l.d_partitions[0].p_offset = 0; tgt->dev_info.disk.l.d_partitions[0].p_size = disk_size; tgt->dev_info.disk.l.d_partitions[2].p_offset = 0; tgt->dev_info.disk.l.d_partitions[2].p_size = disk_size; tgt->dev_info.disk.l.d_partitions[MAXPARTITIONS].p_offset = 0; tgt->dev_info.disk.l.d_partitions[MAXPARTITIONS].p_size = -1; } label->d_checksum = 0; label->d_checksum = dkcksum(label); } ret = SCSI_RET_SUCCESS; done: if (rdata) kfree((vm_offset_t) rdata, 2 * tgt->block_size); io_req_free(ior); return ret; }
void scsi_proc(void) { if (USBD_ep_buffer_full(BOMS_EP_DATA_OUT)) { if (sizeof(BOMSCmd) == USBD_transfer(BOMS_EP_DATA_OUT, (uint8_t *)&BOMSCmd, sizeof(BOMSCmd))) { if (BOMSCmd.dCBWSignature == BOMS_USBC) { if (BOMSCmd.CBWCB.unit_ready.op_code == BOMS_SCSI_TEST_UNIT_READY) // SCSI Test Unit Ready { scsi_test_unit_ready(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_READ) // SCSI Read { scsi_read(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_WRITE) // SCSI Write { scsi_write(&BOMSCmd); } else if (BOMSCmd.CBWCB.inquiry.op_code == BOMS_SCSI_INQUIRY) // SCSI Inquiry { scsi_inquiry(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_REQUEST_SENSE) // SCSI Request Sense { scsi_request_sense(&BOMSCmd); } else if (BOMSCmd.CBWCB.read_capacity.op_code == BOMS_SCSI_READ_CAPACITY) // SCSI Read Capacity (10) { scsi_read_capacity(&BOMSCmd); } else if (BOMSCmd.CBWCB.read_capacity.op_code == BOMS_SCSI_READ_FORMAT_CAPACITY) // SCSI Read Format Capacity (10) { scsi_read_format_capacity(&BOMSCmd); } else if (BOMSCmd.CBWCB.mode_sense.op_code == BOMS_SCSI_MODE_SENSE) // SCSI Mode Sense { scsi_mode_sense(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_READ_CAPACITY_16) // SCSI Read Capacity (16) { scsi_read_capacity(&BOMSCmd); } else if (BOMSCmd.CBWCB.request_sense.op_code == BOMS_SCSI_PREVENT_ALLOW_REMOVAL) // SCSI Prevent Allow Removal { scsi_prevent_allow_removal(&BOMSCmd); } else { // Send IN a zero length packet. if (BOMSCmd.dCBWDataTransferLength) { USBD_stall_endpoint(BOMS_EP_DATA_IN); } boms_send_status(BOMS_STATUS_COMMAND_FAILED, &BOMSCmd); scsi_sense_illegal_request_command(); } } else { // Was not a USBC signature. boms_send_status(BOMS_STATUS_PHASE_ERROR, &BOMSCmd); scsi_sense_illegal_request_cdb(); } }else{ // Wrong command size. boms_send_status(BOMS_STATUS_COMMAND_FAILED, &BOMSCmd); scsi_sense_illegal_request_parm(); } } }