diff options
Diffstat (limited to 'sys/cam/ctl/ctl.c')
-rw-r--r-- | sys/cam/ctl/ctl.c | 537 |
1 files changed, 472 insertions, 65 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index 91c9fdb..1364f3c 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #include <cam/cam.h> #include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_cd.h> #include <cam/scsi/scsi_da.h> #include <cam/ctl/ctl_io.h> #include <cam/ctl/ctl.h> @@ -3821,8 +3822,14 @@ ctl_init_page_index(struct ctl_lun *lun) for (i = 0; i < CTL_NUM_MODE_PAGES; i++) { page_index = &lun->mode_pages.index[i]; - if (lun->be_lun->lun_type != T_DIRECT && - (page_index->page_flags & CTL_PAGE_FLAG_DISK_ONLY)) + if (lun->be_lun->lun_type == T_DIRECT && + (page_index->page_flags & CTL_PAGE_FLAG_DIRECT) == 0) + continue; + if (lun->be_lun->lun_type == T_PROCESSOR && + (page_index->page_flags & CTL_PAGE_FLAG_PROC) == 0) + continue; + if (lun->be_lun->lun_type == T_CDROM && + (page_index->page_flags & CTL_PAGE_FLAG_CDROM) == 0) continue; switch (page_index->page_code & SMPH_PC_MASK) { @@ -4207,8 +4214,14 @@ ctl_init_log_page_index(struct ctl_lun *lun) for (i = 0, j = 0, k = 0; i < CTL_NUM_LOG_PAGES; i++) { page_index = &lun->log_pages.index[i]; - if (lun->be_lun->lun_type != T_DIRECT && - (page_index->page_flags & CTL_PAGE_FLAG_DISK_ONLY)) + if (lun->be_lun->lun_type == T_DIRECT && + (page_index->page_flags & CTL_PAGE_FLAG_DIRECT) == 0) + continue; + if (lun->be_lun->lun_type == T_PROCESSOR && + (page_index->page_flags & CTL_PAGE_FLAG_PROC) == 0) + continue; + if (lun->be_lun->lun_type == T_CDROM && + (page_index->page_flags & CTL_PAGE_FLAG_CDROM) == 0) continue; if (page_index->page_code == SLS_LOGICAL_BLOCK_PROVISIONING && @@ -4284,7 +4297,7 @@ ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *ctl_lun, struct ctl_lun *nlun, *lun; struct scsi_vpd_id_descriptor *desc; struct scsi_vpd_id_t10 *t10id; - const char *eui, *naa, *scsiname, *vendor; + const char *eui, *naa, *scsiname, *vendor, *value; int lun_number, i, lun_malloced; int devidlen, idlen1, idlen2 = 0, len; @@ -4296,8 +4309,8 @@ ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *ctl_lun, */ switch (be_lun->lun_type) { case T_DIRECT: - break; case T_PROCESSOR: + case T_CDROM: break; case T_SEQUENTIAL: case T_CHANGER: @@ -4450,6 +4463,13 @@ ctl_alloc_lun(struct ctl_softc *ctl_softc, struct ctl_lun *ctl_lun, if (be_lun->flags & CTL_LUN_FLAG_PRIMARY) lun->flags |= CTL_LUN_PRIMARY_SC; + value = ctl_get_opt(&be_lun->options, "removable"); + if (value != NULL) { + if (strcmp(value, "on") == 0) + lun->flags |= CTL_LUN_REMOVABLE; + } else if (be_lun->lun_type == T_CDROM) + lun->flags |= CTL_LUN_REMOVABLE; + lun->ctl_softc = ctl_softc; #ifdef CTL_TIME_IO lun->last_busy = getsbinuptime(); @@ -5126,14 +5146,14 @@ ctl_start_stop(struct ctl_scsiio *ctsio) } } - /* - * If there is no backend on this device, we can't start or stop - * it. In theory we shouldn't get any start/stop commands in the - * first place at this level if the LUN doesn't have a backend. - * That should get stopped by the command decode code. - */ - if (lun->backend == NULL) { - ctl_set_invalid_opcode(ctsio); + if ((cdb->how & SSS_LOEJ) && + (lun->flags & CTL_LUN_REMOVABLE) == 0) { + ctl_set_invalid_field(ctsio, + /*sks_valid*/ 1, + /*command*/ 1, + /*field*/ 4, + /*bit_valid*/ 1, + /*bit*/ 1); ctl_done((union ctl_io *)ctsio); return (CTL_RETVAL_COMPLETE); } @@ -5163,6 +5183,26 @@ ctl_start_stop(struct ctl_scsiio *ctsio) return (retval); } +int +ctl_prevent_allow(struct ctl_scsiio *ctsio) +{ + struct ctl_lun *lun; + int retval; + + CTL_DEBUG_PRINT(("ctl_prevent_allow\n")); + + lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; + + if ((lun->flags & CTL_LUN_REMOVABLE) == 0) { + ctl_set_invalid_opcode(ctsio); + ctl_done((union ctl_io *)ctsio); + return (CTL_RETVAL_COMPLETE); + } + + retval = lun->backend->config_write((union ctl_io *)ctsio); + return (retval); +} + /* * We support the SYNCHRONIZE CACHE command (10 and 16 byte versions), but * we don't really do anything with the LBA and length fields if the user @@ -5224,15 +5264,6 @@ ctl_sync_cache(struct ctl_scsiio *ctsio) goto bailout; } - /* - * If this LUN has no backend, we can't flush the cache anyway. - */ - if (lun->backend == NULL) { - ctl_set_invalid_opcode(ctsio); - ctl_done((union ctl_io *)ctsio); - goto bailout; - } - lbalen = (struct ctl_lba_len_flags *)&ctsio->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; lbalen->lba = starting_lba; lbalen->len = block_count; @@ -5935,13 +5966,18 @@ do_next_page: * XXX KDM should we do something with the block descriptor? */ for (i = 0; i < CTL_NUM_MODE_PAGES; i++) { - - if (lun->be_lun->lun_type != T_DIRECT && - (lun->mode_pages.index[i].page_flags & - CTL_PAGE_FLAG_DISK_ONLY)) + page_index = &lun->mode_pages.index[i]; + if (lun->be_lun->lun_type == T_DIRECT && + (page_index->page_flags & CTL_PAGE_FLAG_DIRECT) == 0) + continue; + if (lun->be_lun->lun_type == T_PROCESSOR && + (page_index->page_flags & CTL_PAGE_FLAG_PROC) == 0) + continue; + if (lun->be_lun->lun_type == T_CDROM && + (page_index->page_flags & CTL_PAGE_FLAG_CDROM) == 0) continue; - if ((lun->mode_pages.index[i].page_code & SMPH_PC_MASK) != + if ((page_index->page_code & SMPH_PC_MASK) != (page_header->page_code & SMPH_PC_MASK)) continue; @@ -5949,9 +5985,8 @@ do_next_page: * If neither page has a subpage code, then we've got a * match. */ - if (((lun->mode_pages.index[i].page_code & SMPH_SPF) == 0) + if (((page_index->page_code & SMPH_SPF) == 0) && ((page_header->page_code & SMPH_SPF) == 0)) { - page_index = &lun->mode_pages.index[i]; page_len = page_header->page_length; break; } @@ -5960,15 +5995,12 @@ do_next_page: * If both pages have subpages, then the subpage numbers * have to match. */ - if ((lun->mode_pages.index[i].page_code & SMPH_SPF) + if ((page_index->page_code & SMPH_SPF) && (page_header->page_code & SMPH_SPF)) { struct scsi_mode_page_header_sp *sph; sph = (struct scsi_mode_page_header_sp *)page_header; - - if (lun->mode_pages.index[i].subpage == - sph->subpage) { - page_index = &lun->mode_pages.index[i]; + if (page_index->subpage == sph->subpage) { page_len = scsi_2btoul(sph->page_length); break; } @@ -5979,7 +6011,7 @@ do_next_page: * If we couldn't find the page, or if we don't have a mode select * handler for it, send back an error to the user. */ - if ((page_index == NULL) + if ((i >= CTL_NUM_MODE_PAGES) || (page_index->select_handler == NULL)) { ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, @@ -6238,7 +6270,6 @@ ctl_mode_sense(struct ctl_scsiio *ctsio) dbd = 0; llba = 0; block_desc = NULL; - page_index = NULL; CTL_DEBUG_PRINT(("ctl_mode_sense\n")); @@ -6315,26 +6346,33 @@ ctl_mode_sense(struct ctl_scsiio *ctsio) } for (i = 0; i < CTL_NUM_MODE_PAGES; i++) { - if (lun->be_lun->lun_type != T_DIRECT && - (lun->mode_pages.index[i].page_flags & - CTL_PAGE_FLAG_DISK_ONLY)) + page_index = &lun->mode_pages.index[i]; + + /* Make sure the page is supported for this dev type */ + if (lun->be_lun->lun_type == T_DIRECT && + (page_index->page_flags & CTL_PAGE_FLAG_DIRECT) == 0) + continue; + if (lun->be_lun->lun_type == T_PROCESSOR && + (page_index->page_flags & CTL_PAGE_FLAG_PROC) == 0) + continue; + if (lun->be_lun->lun_type == T_CDROM && + (page_index->page_flags & CTL_PAGE_FLAG_CDROM) == 0) continue; /* * We don't use this subpage if the user didn't * request all subpages. */ - if ((lun->mode_pages.index[i].subpage != 0) + if ((page_index->subpage != 0) && (subpage == SMS_SUBPAGE_PAGE_0)) continue; #if 0 printf("found page %#x len %d\n", - lun->mode_pages.index[i].page_code & - SMPH_PC_MASK, - lun->mode_pages.index[i].page_len); + page_index->page_code & SMPH_PC_MASK, + page_index->page_len); #endif - page_len += lun->mode_pages.index[i].page_len; + page_len += page_index->page_len; } break; } @@ -6344,30 +6382,35 @@ ctl_mode_sense(struct ctl_scsiio *ctsio) page_len = 0; for (i = 0; i < CTL_NUM_MODE_PAGES; i++) { + page_index = &lun->mode_pages.index[i]; + + /* Make sure the page is supported for this dev type */ + if (lun->be_lun->lun_type == T_DIRECT && + (page_index->page_flags & CTL_PAGE_FLAG_DIRECT) == 0) + continue; + if (lun->be_lun->lun_type == T_PROCESSOR && + (page_index->page_flags & CTL_PAGE_FLAG_PROC) == 0) + continue; + if (lun->be_lun->lun_type == T_CDROM && + (page_index->page_flags & CTL_PAGE_FLAG_CDROM) == 0) + continue; + /* Look for the right page code */ - if ((lun->mode_pages.index[i].page_code & - SMPH_PC_MASK) != page_code) + if ((page_index->page_code & SMPH_PC_MASK) != page_code) continue; /* Look for the right subpage or the subpage wildcard*/ - if ((lun->mode_pages.index[i].subpage != subpage) + if ((page_index->subpage != subpage) && (subpage != SMS_SUBPAGE_ALL)) continue; - /* Make sure the page is supported for this dev type */ - if (lun->be_lun->lun_type != T_DIRECT && - (lun->mode_pages.index[i].page_flags & - CTL_PAGE_FLAG_DISK_ONLY)) - continue; - #if 0 printf("found page %#x len %d\n", - lun->mode_pages.index[i].page_code & - SMPH_PC_MASK, - lun->mode_pages.index[i].page_len); + page_index->page_code & SMPH_PC_MASK, + page_index->page_len); #endif - page_len += lun->mode_pages.index[i].page_len; + page_len += page_index->page_len; } if (page_len == 0) { @@ -6475,9 +6518,14 @@ ctl_mode_sense(struct ctl_scsiio *ctsio) struct ctl_page_index *page_index; page_index = &lun->mode_pages.index[i]; - - if (lun->be_lun->lun_type != T_DIRECT && - (page_index->page_flags & CTL_PAGE_FLAG_DISK_ONLY)) + if (lun->be_lun->lun_type == T_DIRECT && + (page_index->page_flags & CTL_PAGE_FLAG_DIRECT) == 0) + continue; + if (lun->be_lun->lun_type == T_PROCESSOR && + (page_index->page_flags & CTL_PAGE_FLAG_PROC) == 0) + continue; + if (lun->be_lun->lun_type == T_CDROM && + (page_index->page_flags & CTL_PAGE_FLAG_CDROM) == 0) continue; /* @@ -6525,8 +6573,14 @@ ctl_mode_sense(struct ctl_scsiio *ctsio) continue; /* Make sure the page is supported for this dev type */ - if (lun->be_lun->lun_type != T_DIRECT && - (page_index->page_flags & CTL_PAGE_FLAG_DISK_ONLY)) + if (lun->be_lun->lun_type == T_DIRECT && + (page_index->page_flags & CTL_PAGE_FLAG_DIRECT) == 0) + continue; + if (lun->be_lun->lun_type == T_PROCESSOR && + (page_index->page_flags & CTL_PAGE_FLAG_PROC) == 0) + continue; + if (lun->be_lun->lun_type == T_CDROM && + (page_index->page_flags & CTL_PAGE_FLAG_CDROM) == 0) continue; /* @@ -10052,6 +10106,8 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio) inq_ptr->device = (SID_QUAL_LU_OFFLINE << 5) | lun->be_lun->lun_type; } + if (lun->flags & CTL_LUN_REMOVABLE) + inq_ptr->dev_qual2 |= SID_RMB; } else inq_ptr->device = (SID_QUAL_BAD_LU << 5) | T_NODEVICE; @@ -10116,6 +10172,10 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio) strncpy(inq_ptr->product, CTL_PROCESSOR_PRODUCT, sizeof(inq_ptr->product)); break; + case T_CDROM: + strncpy(inq_ptr->product, CTL_CDROM_PRODUCT, + sizeof(inq_ptr->product)); + break; default: strncpy(inq_ptr->product, CTL_UNKNOWN_PRODUCT, sizeof(inq_ptr->product)); @@ -10178,6 +10238,11 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio) scsi_ulto2b(0x0600, inq_ptr->version4); break; case T_PROCESSOR: + break; + case T_CDROM: + /* MMC-6 (no version claimed) */ + scsi_ulto2b(0x04E0, inq_ptr->version4); + break; default: break; } @@ -10217,6 +10282,344 @@ ctl_inquiry(struct ctl_scsiio *ctsio) return (retval); } +int +ctl_get_config(struct ctl_scsiio *ctsio) +{ + struct scsi_get_config_header *hdr; + struct scsi_get_config_feature *feature; + struct scsi_get_config *cdb; + struct ctl_lun *lun; + uint32_t alloc_len, data_len; + int rt, starting; + + lun = ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; + cdb = (struct scsi_get_config *)ctsio->cdb; + rt = (cdb->rt & SGC_RT_MASK); + starting = scsi_2btoul(cdb->starting_feature); + alloc_len = scsi_2btoul(cdb->length); + + data_len = sizeof(struct scsi_get_config_header) + + sizeof(struct scsi_get_config_feature) + 8 + + sizeof(struct scsi_get_config_feature) + 8 + + sizeof(struct scsi_get_config_feature) + 4 + + sizeof(struct scsi_get_config_feature) + 4 + + sizeof(struct scsi_get_config_feature) + 8 + + sizeof(struct scsi_get_config_feature) + + sizeof(struct scsi_get_config_feature) + 4 + + sizeof(struct scsi_get_config_feature) + 4; + ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO); + ctsio->kern_sg_entries = 0; + ctsio->kern_data_resid = 0; + ctsio->kern_rel_offset = 0; + + hdr = (struct scsi_get_config_header *)ctsio->kern_data_ptr; + if (lun->flags & CTL_LUN_OFFLINE) + scsi_ulto2b(0x0000, hdr->current_profile); + else + scsi_ulto2b(0x0010, hdr->current_profile); + feature = (struct scsi_get_config_feature *)(hdr + 1); + + if (starting > 0x001f) + goto done; + if (starting > 0x001e) + goto f1f; + if (starting > 0x001d) + goto f1e; + if (starting > 0x0010) + goto f1d; + if (starting > 0x0003) + goto f10; + if (starting > 0x0002) + goto f3; + if (starting > 0x0001) + goto f2; + if (starting > 0x0000) + goto f1; + + /* Profile List */ + scsi_ulto2b(0x0000, feature->feature_code); + feature->flags = SGC_F_PERSISTENT | SGC_F_CURRENT; + feature->add_length = 8; + scsi_ulto2b(0x0008, &feature->feature_data[0]); /* CD-ROM */ + feature->feature_data[2] = 0x00; + scsi_ulto2b(0x0010, &feature->feature_data[4]); /* DVD-ROM */ + feature->feature_data[6] = 0x01; + feature = (struct scsi_get_config_feature *) + &feature->feature_data[feature->add_length]; + +f1: /* Core */ + scsi_ulto2b(0x0001, feature->feature_code); + feature->flags = 0x08 | SGC_F_PERSISTENT | SGC_F_CURRENT; + feature->add_length = 8; + scsi_ulto4b(0x00000000, &feature->feature_data[0]); + feature->feature_data[4] = 0x03; + feature = (struct scsi_get_config_feature *) + &feature->feature_data[feature->add_length]; + +f2: /* Morphing */ + scsi_ulto2b(0x0002, feature->feature_code); + feature->flags = 0x04 | SGC_F_PERSISTENT | SGC_F_CURRENT; + feature->add_length = 4; + feature->feature_data[0] = 0x02; + feature = (struct scsi_get_config_feature *) + &feature->feature_data[feature->add_length]; + +f3: /* Removable Medium */ + scsi_ulto2b(0x0003, feature->feature_code); + feature->flags = 0x04 | SGC_F_PERSISTENT | SGC_F_CURRENT; + feature->add_length = 4; + feature->feature_data[0] = 0x39; + feature = (struct scsi_get_config_feature *) + &feature->feature_data[feature->add_length]; + + if (rt == SGC_RT_CURRENT && (lun->flags & CTL_LUN_OFFLINE)) + goto done; + +f10: /* Random Read */ + scsi_ulto2b(0x0010, feature->feature_code); + feature->flags = 0x00; + if ((lun->flags & CTL_LUN_OFFLINE) == 0) + feature->flags |= SGC_F_CURRENT; + feature->add_length = 8; + scsi_ulto4b(lun->be_lun->blocksize, &feature->feature_data[0]); + scsi_ulto2b(1, &feature->feature_data[4]); + feature->feature_data[6] = 0x00; + feature = (struct scsi_get_config_feature *) + &feature->feature_data[feature->add_length]; + +f1d: /* Multi-Read */ + scsi_ulto2b(0x001D, feature->feature_code); + feature->flags = 0x00; + if ((lun->flags & CTL_LUN_OFFLINE) == 0) + feature->flags |= SGC_F_CURRENT; + feature->add_length = 0; + feature = (struct scsi_get_config_feature *) + &feature->feature_data[feature->add_length]; + +f1e: /* CD Read */ + scsi_ulto2b(0x001E, feature->feature_code); + feature->flags = 0x00; + if ((lun->flags & CTL_LUN_OFFLINE) == 0) + feature->flags |= SGC_F_CURRENT; + feature->add_length = 4; + feature->feature_data[0] = 0x00; + feature = (struct scsi_get_config_feature *) + &feature->feature_data[feature->add_length]; + +f1f: /* DVD Read */ + scsi_ulto2b(0x001F, feature->feature_code); + feature->flags = 0x08; + if ((lun->flags & CTL_LUN_OFFLINE) == 0) + feature->flags |= SGC_F_CURRENT; + feature->add_length = 4; + feature->feature_data[0] = 0x01; + feature->feature_data[2] = 0x03; + feature = (struct scsi_get_config_feature *) + &feature->feature_data[feature->add_length]; + +done: + data_len = (uint8_t *)feature - (uint8_t *)hdr; + if (rt == SGC_RT_SPECIFIC && data_len > 4) { + feature = (struct scsi_get_config_feature *)(hdr + 1); + if (scsi_2btoul(feature->feature_code) == starting) + feature = (struct scsi_get_config_feature *) + &feature->feature_data[feature->add_length]; + data_len = (uint8_t *)feature - (uint8_t *)hdr; + } + scsi_ulto4b(data_len - 4, hdr->data_length); + if (data_len < alloc_len) { + ctsio->residual = alloc_len - data_len; + ctsio->kern_data_len = data_len; + ctsio->kern_total_len = data_len; + } else { + ctsio->residual = 0; + ctsio->kern_data_len = alloc_len; + ctsio->kern_total_len = alloc_len; + } + + ctl_set_success(ctsio); + ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; + ctsio->be_move_done = ctl_config_move_done; + ctl_datamove((union ctl_io *)ctsio); + return (CTL_RETVAL_COMPLETE); +} + +int +ctl_get_event_status(struct ctl_scsiio *ctsio) +{ + struct scsi_get_event_status_header *hdr; + struct scsi_get_event_status *cdb; + struct ctl_lun *lun; + uint32_t alloc_len, data_len; + int notif_class; + + lun = ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; + cdb = (struct scsi_get_event_status *)ctsio->cdb; + if ((cdb->byte2 & SGESN_POLLED) == 0) { + ctl_set_invalid_field(ctsio, /*sks_valid*/ 1, /*command*/ 1, + /*field*/ 1, /*bit_valid*/ 1, /*bit*/ 0); + ctl_done((union ctl_io *)ctsio); + return (CTL_RETVAL_COMPLETE); + } + notif_class = cdb->notif_class; + alloc_len = scsi_2btoul(cdb->length); + + data_len = sizeof(struct scsi_get_event_status_header); + ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO); + ctsio->kern_sg_entries = 0; + ctsio->kern_data_resid = 0; + ctsio->kern_rel_offset = 0; + + if (data_len < alloc_len) { + ctsio->residual = alloc_len - data_len; + ctsio->kern_data_len = data_len; + ctsio->kern_total_len = data_len; + } else { + ctsio->residual = 0; + ctsio->kern_data_len = alloc_len; + ctsio->kern_total_len = alloc_len; + } + + hdr = (struct scsi_get_event_status_header *)ctsio->kern_data_ptr; + scsi_ulto2b(0, hdr->descr_length); + hdr->nea_class = SGESN_NEA; + hdr->supported_class = 0; + + ctl_set_success(ctsio); + ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; + ctsio->be_move_done = ctl_config_move_done; + ctl_datamove((union ctl_io *)ctsio); + return (CTL_RETVAL_COMPLETE); +} + +int +ctl_mechanism_status(struct ctl_scsiio *ctsio) +{ + struct scsi_mechanism_status_header *hdr; + struct scsi_mechanism_status *cdb; + struct ctl_lun *lun; + uint32_t alloc_len, data_len; + + lun = ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; + cdb = (struct scsi_mechanism_status *)ctsio->cdb; + alloc_len = scsi_2btoul(cdb->length); + + data_len = sizeof(struct scsi_mechanism_status_header); + ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO); + ctsio->kern_sg_entries = 0; + ctsio->kern_data_resid = 0; + ctsio->kern_rel_offset = 0; + + if (data_len < alloc_len) { + ctsio->residual = alloc_len - data_len; + ctsio->kern_data_len = data_len; + ctsio->kern_total_len = data_len; + } else { + ctsio->residual = 0; + ctsio->kern_data_len = alloc_len; + ctsio->kern_total_len = alloc_len; + } + + hdr = (struct scsi_mechanism_status_header *)ctsio->kern_data_ptr; + hdr->state1 = 0x00; + hdr->state2 = 0xe0; + scsi_ulto3b(0, hdr->lba); + hdr->slots_num = 0; + scsi_ulto2b(0, hdr->slots_length); + + ctl_set_success(ctsio); + ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; + ctsio->be_move_done = ctl_config_move_done; + ctl_datamove((union ctl_io *)ctsio); + return (CTL_RETVAL_COMPLETE); +} + +static void +ctl_ultomsf(uint32_t lba, uint8_t *buf) +{ + + lba += 150; + buf[0] = 0; + buf[1] = bin2bcd((lba / 75) / 60); + buf[2] = bin2bcd((lba / 75) % 60); + buf[3] = bin2bcd(lba % 75); +} + +int +ctl_read_toc(struct ctl_scsiio *ctsio) +{ + struct scsi_read_toc_hdr *hdr; + struct scsi_read_toc_type01_descr *descr; + struct scsi_read_toc *cdb; + struct ctl_lun *lun; + uint32_t alloc_len, data_len; + int format, msf; + + lun = ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr; + cdb = (struct scsi_read_toc *)ctsio->cdb; + msf = (cdb->byte2 & CD_MSF) != 0; + format = cdb->format; + alloc_len = scsi_2btoul(cdb->data_len); + + data_len = sizeof(struct scsi_read_toc_hdr); + if (format == 0) + data_len += 2 * sizeof(struct scsi_read_toc_type01_descr); + else + data_len += sizeof(struct scsi_read_toc_type01_descr); + ctsio->kern_data_ptr = malloc(data_len, M_CTL, M_WAITOK | M_ZERO); + ctsio->kern_sg_entries = 0; + ctsio->kern_data_resid = 0; + ctsio->kern_rel_offset = 0; + + if (data_len < alloc_len) { + ctsio->residual = alloc_len - data_len; + ctsio->kern_data_len = data_len; + ctsio->kern_total_len = data_len; + } else { + ctsio->residual = 0; + ctsio->kern_data_len = alloc_len; + ctsio->kern_total_len = alloc_len; + } + + hdr = (struct scsi_read_toc_hdr *)ctsio->kern_data_ptr; + if (format == 0) { + scsi_ulto2b(0x12, hdr->data_length); + hdr->first = 1; + hdr->last = 1; + descr = (struct scsi_read_toc_type01_descr *)(hdr + 1); + descr->addr_ctl = 0x14; + descr->track_number = 1; + if (msf) + ctl_ultomsf(0, descr->track_start); + else + scsi_ulto4b(0, descr->track_start); + descr++; + descr->addr_ctl = 0x14; + descr->track_number = 0xaa; + if (msf) + ctl_ultomsf(lun->be_lun->maxlba+1, descr->track_start); + else + scsi_ulto4b(lun->be_lun->maxlba+1, descr->track_start); + } else { + scsi_ulto2b(0x0a, hdr->data_length); + hdr->first = 1; + hdr->last = 1; + descr = (struct scsi_read_toc_type01_descr *)(hdr + 1); + descr->addr_ctl = 0x14; + descr->track_number = 1; + if (msf) + ctl_ultomsf(0, descr->track_start); + else + scsi_ulto4b(0, descr->track_start); + } + + ctl_set_success(ctsio); + ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED; + ctsio->be_move_done = ctl_config_move_done; + ctl_datamove((union ctl_io *)ctsio); + return (CTL_RETVAL_COMPLETE); +} + /* * For known CDB types, parse the LBA and length. */ @@ -11266,12 +11669,16 @@ ctl_cmd_applicable(uint8_t lun_type, const struct ctl_cmd_entry *entry) { switch (lun_type) { + case T_DIRECT: + if ((entry->flags & CTL_CMD_FLAG_OK_ON_DIRECT) == 0) + return (0); + break; case T_PROCESSOR: if ((entry->flags & CTL_CMD_FLAG_OK_ON_PROC) == 0) return (0); break; - case T_DIRECT: - if ((entry->flags & CTL_CMD_FLAG_OK_ON_SLUN) == 0) + case T_CDROM: + if ((entry->flags & CTL_CMD_FLAG_OK_ON_CDROM) == 0) return (0); break; default: |