/* * move - move from one element to another * * entry - * library - library_t * * event - robo_event_t * */ int move( library_t *library, robo_event_t *event) { dev_ent_t *un; int err = -1, retry, timeout; char *l_mess = library->un->dis_mes[DIS_MES_NORM]; char *MES_9079 = catgets(catfd, SET, 9079, "move from %s to %s %s"); char *mess, *src_mess, *des_mess, *i_mess; robot_internal_t *cmd = &event->request.internal; int added_more_time = FALSE; sam_extended_sense_t *sense = (sam_extended_sense_t *) SHM_REF_ADDR(library->un->sense); int movmed_err; un = library->un; src_mess = element_string(element_type(library, cmd->source)); des_mess = element_string(element_type(library, cmd->destination1)); if (cmd->flags.b.invert1) i_mess = catgets(catfd, SET, 9084, "invert"); else i_mess = ""; mess = (char *)malloc_wait(strlen(MES_9079) + strlen(src_mess) + strlen(des_mess) + strlen(i_mess) + 10, 4, 0); sprintf(mess, MES_9079, src_mess, des_mess, i_mess); memccpy(l_mess, mess, '\0', DIS_MES_LEN); free(mess); DevLog(DL_DETAIL(5057), cmd->source, cmd->flags.b.invert1 ? "invert" : "asis", cmd->destination1); /* * A programming note from DocStore states that you should * allow up to 4 minutes for a move. This is to allow * for recovery and retry by the robot. If other robots need * different time outs, this is the place to put um. */ switch (library->un->type) { case DT_DLT2700: timeout = 300; break; case DT_DOCSTOR: timeout = 4 * 60; break; case DT_METD28: /* FALLTHROUGH */ case DT_METD360: /* FALLTHROUGH */ case DT_SPECLOG: /* FALLTHROUGH */ case DT_ATL1500: /* FALLTHROUGH */ case DT_ODI_NEO: /* FALLTHROUGH */ case DT_QUANTUMC4: /* FALLTHROUGH */ case DT_STK97XX: /* FALLTHROUGH */ case DT_FJNMXX: /* FALLTHROUGH */ case DT_SL3000: /* FALLTHROUGH */ case DT_SLPYTHON: timeout = 10 * 60; break; default: timeout = 5 * 60; break; } mutex_lock(&library->un->io_mutex); retry = 2; do { time_t start; TAPEALERT(library->open_fd, library->un); memset(sense, 0, sizeof (sam_extended_sense_t)); start = time(NULL); movmed_err = scsi_cmd(library->open_fd, library->un, SCMD_MOVE_MEDIUM, timeout, cmd->transport, cmd->source, cmd->destination1, (cmd->flags.b.invert1 ? 1 : 0)); TAPEALERT(library->open_fd, library->un); if (movmed_err < 0) { DevLog(DL_TIME(5177), cmd->source, cmd->flags.b.invert1 ? "invert" : "asis", cmd->destination1, time(NULL) - start); GENERIC_SCSI_ERROR_PROCESSING(library->un, library->scsi_err_tab, 0, err, added_more_time, retry, /* code for DOWN_EQU */ if (!cmd->flags.b.noerror) { err = DOWN_EQU; if (sense->es_add_code == 0x40 && sense->es_qual_code == 0x02) { move_drive_error(library, cmd->source, cmd->destination1, &err); } else { down_library(library, SAM_STATE_CHANGE); } retry = 1; /* MACRO for cstyle */ } break; /* MACRO for cstyle */,
void usb_msc_thread(void* param) { USB_MSC* msc = (USB_MSC*)param; for (;;) { event_wait_ms(msc->event, INFINITE); msc->state = MSC_STATE_DATA; //process received CBW if (msc->cbw.dCBWSignature == CBW_MAGIC && msc->cbw.bCBWCBLength <= MAX_CB_SIZE) { msc->csw_status = CSW_STATUS_OK; #if (USB_MSC_DEBUG_FLOW) printf("USB_MSC: dCBWTag: %08x\n\r", msc->cbw.dCBWTag); printf("USB_MSC: dCBWDataTransferLength: %08x\n\r", msc->cbw.dCBWDataTransferLength); printf("USB_MSC: dCBWDataFlags: %02x\n\r", msc->cbw.bmCBWFlags); printf("USB_MSC: dCBWLUN: %02x\n\r", msc->cbw.bCBWLUN); printf("USB_MSC: dCBWCB:"); int i; for (i = 0; i < msc->cbw.bCBWCBLength; ++i) printf(" %02x", msc->cbw.CBWCB[i]); printf(" (%d)\n\r", msc->cbw.bCBWCBLength); #endif if (!scsi_cmd(msc->scsi, (char*)msc->cbw.CBWCB, msc->cbw.bCBWCBLength)) msc->csw_status = CSW_STATUS_FAILED; //wait for transfer completed in any case event_wait_ms(msc->event, INFINITE); } //CBW invalid, phase ERROR else { #if (USB_DEBUG_ERRORS) printf("Invalid CBW\n\r"); #endif msc->csw_status = CSW_STATUS_ERROR; } event_clear(msc->event); msc->state = MSC_STATE_CSW; //need zlp? if ((msc->scsi_transferred % msc->ep_size) == 0 && msc->cbw.dCBWDataTransferLength != 0 && msc->scsi_transferred < msc->cbw.dCBWDataTransferLength) { if (msc->cbw.bmCBWFlags & 0x80) usb_write(usbd_get_usb(msc->usbd), EP_IN(msc->ep_num), NULL, 0); else usb_read(usbd_get_usb(msc->usbd), EP_OUT(msc->ep_num), NULL, 0); #if (USB_MSC_DEBUG_FLOW) if (msc->cbw.bmCBWFlags & 0x80) printf("USB_MSC: TX ZLP\n\r"); else printf("USB_MSC: RX ZLP\n\r"); #endif } //send csw directly else { if (msc->cbw.bmCBWFlags & 0x80) on_msc_sent(EP_IN(msc->ep_num), msc); else on_msc_received(EP_OUT(msc->ep_num), msc); } } }
static int inquiry( instance_data_t *sd ) { char inquiry_cmd[6] = { 0x12, 0, 0, 0, 32, 0 }; char start_stop_unit_cmd[6] = { 0x1b, 0, 0, 0, 1, 0 }; char test_unit_ready_cmd[6] = { 0x00, 0, 0, 0, 0, 0 }; char prev_allow_medium_removal[6] = { 0x1e, 0, 0, 0, 1, 0 }; char set_cd_speed_cmd[12] = { 0xbb, 0, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0 }; target_info_t *info = &scsi_devs[sd->target]; char ret[32]; int i, sense; if( sd->target >= MAX_TARGETS ) return -1; sd->info = info; if( info->probed ) return info->valid ? 0:-1; info->probed = 1; if( (sense=scsi_cmd_(sd, inquiry_cmd, 6, ret, 2, 0, 0)) ) { if( sense < 0 ) return -1; printk("INQUIRY failed\n"); return -1; } /* medium present? */ if( (scsi_cmd(sd, test_unit_ready_cmd, 6) >> 8) == 0x23a ) { printk("no media\n"); return -1; } info->is_cd = 0; info->blocksize = 512; if( ret[0] == 5 /* CD/DVD */ ) { info->blocksize = 2048; info->is_cd = 1; scsi_cmd( sd, prev_allow_medium_removal, 6 ); scsi_cmd( sd, set_cd_speed_cmd, 12 ); scsi_cmd( sd, start_stop_unit_cmd, 6 ); } else if( ret[0] == 0 /* DISK */ ) { scsi_cmd( sd, test_unit_ready_cmd, 6 ); scsi_cmd( sd, start_stop_unit_cmd, 6 ); } else { /* don't boot from this device (could be a scanner :-)) */ return -1; } /* wait for spin-up (or whatever) to complete */ for( i=0; ; i++ ) { if( i > 300 ) { printk("SCSI timeout (sense %x)\n", sense ); return -1; } sense = scsi_cmd( sd, test_unit_ready_cmd, 6 ); if( (sense & 0xf0000) == 0x20000 ) { OSI_USleep( 10000 ); continue; } break; } info->valid = 1; return 0; }
/* * -- tapealert - tapealert log sense page 0x2e processing * Process media changer or tape drive request for tapealert log sense * page 0x2e. An active tapealert never interferes with data * transfers. Active tapealert flags are written to the device log and * real-time notification is by a posted tapealert sysevent. See * www.t10.org SSC-2 and SMC-2 for additional tapealert information. */ int /* 0 successful */ tapealert( char *src_fn, /* source filename */ int src_ln, /* source file line number */ int fd, /* device file descriptor */ dev_ent_t *un, /* device */ uchar_t *logpage, /* existing tapealert log sense page */ int logpage_len) /* existing tapealert log sense page length */ { #define CLEAN_NOW 0x80000 #define CLEAN_PERIODIC 0x100000 #define EXPIRED_CLEANING_MEDIA 0x200000 #define INVALID_CLEANING_MEDIA 0x400000 #define STK_CLEAN_REQUESTED 0x800000 int rtn = 1; uchar_t *page; uchar_t *log_param; #define PAGE_LEN 256 uchar_t tmp_page [PAGE_LEN]; int resid; int i; int j; int page_len; int param_len; int param_code; int add_page_len; sam_extended_sense_t *sense; sam_extended_sense_t saved_sense; uchar_t saved_cdb [16]; #define FLAGS_LEN 64 int flags_len; uint64_t flags; uchar_t val; int save_errno = errno; uint64_t seq_no = 0; int supported; int enabled; int init_query; int required; int requested; int expired; int invalid; supported = un->tapealert & TAPEALERT_SUPPORTED; enabled = un->tapealert & TAPEALERT_ENABLED; init_query = un->tapealert & TAPEALERT_INIT_QUERY; if (!(supported && (enabled || init_query))) { return (0); } /* * get device sense pointer. */ sense = (sam_extended_sense_t *)SHM_REF_ADDR(un->sense); /* * Second, process tapealert log sense page. */ if (logpage == NULL || logpage_len < 4) { /* save callers previous cdb and sense */ memcpy(saved_cdb, un->cdb, SAM_CDB_LENGTH); memcpy(&saved_sense, sense, sizeof (sam_extended_sense_t)); if (scsi_cmd(fd, un, SCMD_LOG_SENSE, 0, tmp_page, 0, 0x2e, 0, PAGE_LEN, &resid) < 0) { DevLog(DL_DEBUG(12002), sense->es_key, sense->es_add_code, sense->es_qual_code); memcpy(un->cdb, saved_cdb, SAM_CDB_LENGTH); memcpy(sense, &saved_sense, sizeof (sam_extended_sense_t)); goto cleanup; } /* restore callers previous cdb and sense */ memcpy(un->cdb, saved_cdb, SAM_CDB_LENGTH); memcpy(sense, &saved_sense, sizeof (sam_extended_sense_t)); page = tmp_page; page_len = PAGE_LEN - resid; } else { page = logpage; page_len = logpage_len; } if (page_len < 4) { DevLog(DL_DEBUG(12003), page_len); goto cleanup; } if (page [0] != 0x2e) { DevLog(DL_DEBUG(12004), page [0]); goto cleanup; } add_page_len = (page [2] << 8) | page [3]; add_page_len &= 0xffff; log_param = page + 4; flags = 0; flags_len = 0; for (i = 0, j = 0; i < FLAGS_LEN && j < add_page_len; i++, j += 5) { param_code = (log_param [j] << 8) | log_param [j + 1]; if (param_code != (i + 1)) { if (flags != 0) break; goto cleanup; } param_len = log_param [j + 3]; param_len &= 0xff; if (param_len == 1) { val = log_param [j + 4]; if (i < 64 && val != 0) { flags |= ((uint64_t)1 << i); } } else { /* * vendor unique flag length value, quit * processing flags */ break; } /* * increment number of valid TapeAlert flags * contained in the 64 bit wide flags variable */ flags_len++; } /* check for in-active or already seen */ if (flags == 0 || (flags == un->tapealert_flags && strcmp(un->tapealert_vsn, un->vsn) == 0)) { rtn = 0; goto cleanup; } /* build active flags filter by vsn */ if (strcmp(un->tapealert_vsn, un->vsn) == 0) { /* check for already seen */ if ((flags & ~un->tapealert_flags) == 0) { rtn = 0; goto cleanup; } /* current vsn, add active flag(s) to filter */ un->tapealert_flags |= flags; } else { /* new vsn, initialize flags filter */ un->tapealert_flags = flags; } strcpy(un->tapealert_vsn, un->vsn); /* * send tapealert sysevent */ rtn = tapealert_sysevent(src_fn, src_ln, un, flags_len, flags, &seq_no); /* * log active flags * * seq_no is zero when sysevent not sent. */ if (strlen(un->vsn) > 0) { DevLog(DL_ALL(12007), un->version, un->eq, un->scsi_type, seq_no, flags_len, flags, un->vsn); } else { DevLog(DL_ALL(12006), un->version, un->eq, un->scsi_type, seq_no, flags_len, flags); } if ((un->tapeclean & TAPECLEAN_AUTOCLEAN) && (un->tapeclean & TAPECLEAN_LOGSENSE)) { required = (flags & CLEAN_NOW) ? 1 : 0; requested = (flags & CLEAN_PERIODIC) ? 1 : 0; expired = (flags & EXPIRED_CLEANING_MEDIA) ? 1 : 0; invalid = (flags & INVALID_CLEANING_MEDIA) ? 1 : 0; if (un->equ_type == DT_9840 || un->equ_type == DT_9940 || un->equ_type == DT_TITAN) { requested = (flags & STK_CLEAN_REQUESTED) ? 1 : 0; } /* Map active TapeAlert flags onto SAM-FS status. */ tapeclean_active(un, required, requested, expired, invalid); } cleanup: /* * restore callers errno state */ errno = save_errno; return (rtn); }
/* * --- get_supports_tapealert - determine if the robot or tape drive supports * TapeAlert. */ void get_supports_tapealert(dev_ent_t *un, int fd) { int local_open = 0; int open_fd; sam_extended_sense_t *sense; #define PAGE_LEN 256 char page[PAGE_LEN], *page_ptr; int i, page_len, resid; boolean_t unlock_needed = B_FALSE; /* Feature check. */ if ((un->tapealert & TAPEALERT_ENABLED) == 0) { return; } /* Clear previous success flag. */ un->tapealert &= ~TAPEALERT_SUPPORTED; /* Only tape drives and robots. */ if (un->scsi_type != 1 && un->scsi_type != 8) { return; } /* Local file descriptor open used by fifo command message. */ if (fd < 0) { if ((open_fd = open(un->name, O_RDONLY | O_NONBLOCK)) < 0) { if (IS_TAPE(un)) { char *open_name; if ((open_fd = open((open_name = samst_devname(un)), O_RDONLY | O_NONBLOCK)) < 0) { if (open_name != (char *) un->dt.tp.samst_name) free(open_name); return; } else { INC_OPEN(un); if (open_name != (char *) un->dt.tp.samst_name) free(open_name); local_open = TRUE; } } else { DevLog(DL_DEBUG(12014)); return; } } else { INC_OPEN(un); local_open = TRUE; } } else { open_fd = fd; } /* Look for log sense tapealert page 0x2e */ sense = (sam_extended_sense_t *)SHM_REF_ADDR(un->sense); (void) memset(sense, 0, sizeof (sam_extended_sense_t)); if (mutex_trylock(&un->io_mutex) == 0) { unlock_needed = B_TRUE; } memset(page, 0, PAGE_LEN); if (scsi_cmd(open_fd, un, SCMD_LOG_SENSE, 0, page, 0, 0, 0, PAGE_LEN, &resid) >= 0) { page_len = ((PAGE_LEN - resid) >= 4 ? (PAGE_LEN - resid) : 0); if (page_len >= 4) { page_len = (page[2] << 8) | page[3]; page_ptr = page + 4; } for (i = 0; i < page_len; i++) { if (page_ptr[i] == 0x2e) { /* initialize tapealert data */ un->tapealert |= TAPEALERT_SUPPORTED; un->tapealert_flags = 0; un->tapealert_vsn[0] = '\0'; DevLog(DL_ALL(12001)); setup_tapealert(un, open_fd); break; } } } /* query, clear, and report active flags at setup */ un->tapealert |= TAPEALERT_INIT_QUERY; TAPEALERT(open_fd, un); un->tapealert &= ~TAPEALERT_INIT_QUERY; if (unlock_needed == B_TRUE) { mutex_unlock(&un->io_mutex); } if (local_open) { (void) close(open_fd); DEC_OPEN(un); } }
/* * -- setup_tapealert - Setup TapeAlert in polling mode. Disable * recovered error check condition mode. Disable test mode. Set * all other flags to the default values listed in the TapeAlert * Specification v3. */ static void setup_tapealert(dev_ent_t *un, int fd) { int resid; /* bytes not xfered */ #define LEN 255 /* max page len */ uchar_t page[LEN]; /* current page */ int i, len, offset; /* page variables */ #define PERF 0x80 /* performance */ #define EBF 0x20 /* enable background funcs */ #define EWASC 0x10 /* excpt warn chk cond */ #define DEXCPT 0x08 /* polling mode */ #define TEST 0x04 /* test mode */ #define LOGERR 0x01 /* logging of errors */ #define MIRE 0x03 /* tapealert mode */ #define MIRE_MASK 0x0f /* mire field */ sam_extended_sense_t *sense; /* device sense data ptr */ uchar_t pagechg[LEN]; /* changable page */ int offsetchg; /* chg page variables */ uchar_t cdb[SAM_CDB_LENGTH]; /* custom cdb */ /* * Setup TapeAlert mode page in polling mode. */ memset(page, 0, LEN); memset(pagechg, 0, LEN); sense = (sam_extended_sense_t *)SHM_REF_ADDR(un->sense); /* get current page */ if (scsi_cmd(fd, un, SCMD_MODE_SENSE, 30, page, LEN, 0x1c, &resid) < 0) { DevLog(DL_DEBUG(12009), sense->es_key, sense->es_add_code, sense->es_qual_code); goto done; } len = page[0]+1; page[0] = 0; offset = page[3]; page[4+offset] &= 0x7f; /* get changeable page */ memset(cdb, 0, SAM_CDB_LENGTH); cdb[0] = SCMD_MODE_SENSE; if (IS_ROBOT(un)) { cdb[1] = 0x08; } cdb[2] = 0x40 | 0x1c; cdb[4] = LEN; if (scsi_cmd(fd, un, SCMD_ISSUE_CDB, 30, cdb, 6, pagechg, LEN, USCSI_READ, &resid) < 0) { DevLog(DL_DEBUG(12010), sense->es_key, sense->es_add_code, sense->es_qual_code); goto done; } offsetchg = pagechg[3]; /* * Change current TapeAlert page settings to polling mode. */ /* performance */ if ((pagechg[6+offsetchg] & PERF) == PERF) { page[6+offset] &= ~PERF; } /* enable background functions */ if ((pagechg[6+offsetchg] & EBF) == EBF) { page[6+offset] &= ~EBF; } /* exception warning reporting */ if ((pagechg[6+offsetchg] & EWASC) == EWASC) { page[6+offset] &= ~EWASC; } /* disable exception control */ if ((pagechg[6+offsetchg] & DEXCPT) == DEXCPT) { page[6+offset] |= DEXCPT; } /* test mode */ if ((pagechg[6+offsetchg] & TEST) == TEST) { page[6+offset] &= ~TEST; } /* log err */ if ((pagechg[6+offsetchg] & LOGERR) == LOGERR) { page[6+offset] &= ~LOGERR; } /* MIRE - field ignored if DEXCPT is set */ if ((pagechg[7+offsetchg] & MIRE_MASK) != 0) { page[7+offset] &= ~(pagechg[7+offsetchg] & MIRE_MASK); page[7+offset] |= (MIRE & pagechg[7+offsetchg]); if ((page[7+offset] & MIRE_MASK) != MIRE) { page[7+offset] &= ~MIRE_MASK; } } /* interval timer */ for (i = 0; i < 4; i++) { if (pagechg[i+8+offset] != 0) { page[i+8+offset] &= ~(pagechg[i+8+offset]); } } /* report count / test flag number */ for (i = 0; i < 4; i++) { if (pagechg[i+12+offset] != 0) { page[i+12+offset] &= ~(pagechg[i+12+offset]); } } /* set polling mode and defaults */ memset(cdb, 0, SAM_CDB_LENGTH); cdb[0] = SCMD_MODE_SELECT; cdb[1] = 0x10; /* pf bit */ cdb[4] = len; if (scsi_cmd(fd, un, SCMD_ISSUE_CDB, 30, cdb, 6, page, len, USCSI_WRITE, &resid) < 0) { DevLog(DL_DEBUG(12011), sense->es_key, sense->es_add_code, sense->es_qual_code); goto done; } done: /* log run-time settings from current mode page query */ memset(page, 0, LEN); if (scsi_cmd(fd, un, SCMD_MODE_SENSE, 30, page, LEN, 0x1c, &resid) < 0) { DevLog(DL_DEBUG(12012), sense->es_key, sense->es_add_code, sense->es_qual_code); return; } offset = page[3]; if (page[6+offset] != 8 || page[7+offset] != 3) { DevLog(DL_DEBUG(12013), page[6+offset], page[7+offset]); } }
/* * init_elements - get status for all elements in the library. * * exit - */ int /* 0 = all ok !0 = failure */ init_elements( library_t *library) { uint16_t count, start_element; uint16_t avail_drives; int i, err, conlevel = 5; size_t retry; dev_ent_t *un; char *drv_tbl; mode_sense_t *mode_sense; drive_state_t *drive; xport_state_t *xport; iport_state_t *import; robot_ms_page1d_t *pg1d = NULL; robot_ms_page1e_t *pg1e = NULL; robot_ms_page1f_t *pg1f = NULL; sam_extended_sense_t *sense; SANITY_CHECK(library != (library_t *)0); un = library->un; SANITY_CHECK(un != (dev_ent_t *)0); /* Put mode sense data into shared memory. */ /* LINTED pointer cast may result in improper alignment */ mode_sense = (mode_sense_t *)SHM_REF_ADDR(un->mode_sense); sense = (sam_extended_sense_t *)SHM_REF_ADDR(un->sense); SANITY_CHECK(mode_sense != (mode_sense_t *)0); SANITY_CHECK(sense != (sam_extended_sense_t *)0); (void) memset(mode_sense, 0, sizeof (mode_sense_t)); mutex_lock(&un->io_mutex); pg1d = (robot_ms_page1d_t *)lib_mode_sense(library, 0x1d, (uchar_t *)& mode_sense->u.robot_ms.pg1d, sizeof (robot_ms_page1d_t)); pg1f = (robot_ms_page1f_t *)lib_mode_sense(library, 0x1f, (uchar_t *)& mode_sense->u.robot_ms.pg1f, sizeof (robot_ms_page1f_t)); pg1e = (robot_ms_page1e_t *)lib_mode_sense(library, 0x1e, (uchar_t *)& mode_sense->u.robot_ms.pg1e, sizeof (robot_ms_page1e_t)); mutex_unlock(&un->io_mutex); if (pg1d == NULL || pg1f == NULL || pg1e == NULL) { DevLog(DL_ERR(5115)); return (1); } library->status.b.two_sided = pg1e->transport_sets[0].rotate; if (un->type == DT_CYGNET) library->status.b.two_sided = 0; /* Allocate the drive tables. */ BE16toH(&pg1d->first_drive, &start_element); BE16toH(&pg1d->num_drive, &count); library->range.drives_lower = start_element; library->range.drives_count = count; library->range.drives_upper = start_element + count - 1; /* * This code is currently applied to IBM3584 only since the IBM3584 * returns a valid status if drive unit is not installed in a * library. ASC/ASCQ:0x82/0x00. May need to add other library types * to this check, check scsi docs. * * If drive is not fully populated and there is an empty slot for the * drive, we don't need to create a redundant drive_thread. */ avail_drives = count; drv_tbl = malloc_wait(count, 2, 0); (void) memset(drv_tbl, TRUE, count); if (DT_IBM3584 == un->type) if ((avail_drives = (uint16_t)populate_drives(library, drv_tbl)) == 0) { /* * No drives installed, assum fully populated. */ DevLog(DL_ERR(5361)); avail_drives = count; (void) memset(drv_tbl, TRUE, count); } else if (avail_drives > count) { avail_drives = count; } DevLog(DL_DETAIL(5362), avail_drives); /* one for the drive, one for stage and one for the stage helper */ conlevel += (avail_drives * 3); library->drive = (drive_state_t *)malloc_wait( sizeof (drive_state_t), 5, 0); library->index = library->drive; (void) memset(library->drive, 0, sizeof (drive_state_t)); /* * For each drive, build the drive state structure, put the init * request on the list and start a thread with a new lwp. */ for (drive = library->drive, i = 0; i < (int)count && avail_drives > 0; i++) { if (drv_tbl[i] == FALSE) { continue; } /* assign element number */ drive->element = start_element + i; drive->library = library; /* hold the lock until ready */ mutex_lock(&drive->mutex); drive->new_slot = ROBOT_NO_SLOT; drive->open_fd = -1; drive->active_count = 1; drive->first = (robo_event_t *)malloc_wait( sizeof (robo_event_t), 5, 0); (void) memset(drive->first, 0, sizeof (robo_event_t)); drive->first->type = EVENT_TYPE_INTERNAL; drive->first->status.bits = REST_FREEMEM; drive->first->request.internal.command = ROBOT_INTRL_INIT; if (thr_create(NULL, MD_THR_STK, &drive_thread, (void *) drive, (THR_NEW_LWP | THR_BOUND | THR_DETACHED), &drive->thread)) { DevLog(DL_SYSERR(5116)); drive->status.b.offline = TRUE; drive->thread = (thread_t)- 1; } if (--avail_drives <= 0) { break; } else { /* Allocate next entry */ drive->next = (drive_state_t *)malloc_wait( sizeof (drive_state_t), 5, 0); (void) memset(drive->next, 0, sizeof (drive_state_t)); drive->next->previous = drive; /* set back link */ drive = drive->next; } } drive->next = NULL; /* no next drive */ library->drive->previous = NULL; /* no previous drive */ free(drv_tbl); /* Allocate transport tables */ BE16toH(&pg1d->first_tport, &start_element); BE16toH(&pg1d->num_tport, &count); library->range.transport_lower = start_element; library->range.transport_count = count; library->range.transport_upper = start_element + count - 1; library->range.default_transport = 0; library->page1f = pg1f; conlevel += count; library->transports = (xport_state_t *)malloc_wait(sizeof (xport_state_t), 5, 0); (void) memset(library->transports, 0, sizeof (xport_state_t)); for (xport = library->transports, i = 0; i < (int)count; i++) { /* assign element number */ xport->element = start_element + i; xport->library = library; mutex_lock(&xport->mutex); /* start only one transport thread */ if (i == 0) { xport->first = (robo_event_t *)malloc_wait( sizeof (robo_event_t), 5, 0); (void) memset(xport->first, 0, sizeof (robo_event_t)); xport->first->type = EVENT_TYPE_INTERNAL; xport->first->status.bits = REST_FREEMEM; xport->first->request.internal.command = ROBOT_INTRL_INIT; xport->active_count = 1; if (thr_create(NULL, SM_THR_STK, &transport_thread, (void *) xport, (THR_NEW_LWP | THR_BOUND | THR_DETACHED), &xport->thread)) { DevLog(DL_SYSERR(5117)); xport->thread = (thread_t)- 1; } } /* Allocate next entry */ if (i != (count - 1)) { xport->next = (xport_state_t *)malloc_wait( sizeof (xport_state_t), 5, 0); (void) memset(xport->next, 0, sizeof (xport_state_t)); xport->next->previous = xport; /* set back link */ xport = xport->next; } } /* for the metrum d-360 the last transport is used with import export */ xport->next = NULL; /* no next transport */ library->transports->previous = NULL; /* Allocate mailbox (import/export) tables */ BE16toH(&pg1d->first_mail, &start_element); BE16toH(&pg1d->num_mail, &count); library->range.ie_lower = start_element; library->range.ie_count = count; if (count != 0) library->range.ie_upper = start_element + count - 1; else library->range.ie_upper = 0; conlevel += 1; /* only one import/export thread */ library->import = (iport_state_t *)malloc_wait( sizeof (iport_state_t), 5, 0); (void) memset(library->import, 0, sizeof (iport_state_t)); /* store the transport used in import/export for the metrum D-360 */ if (un->type == DT_METD28) library->import->xport = xport; for (import = library->import, i = 0; i < (int)count; i++) { SANITY_CHECK(import != (iport_state_t *)0); /* assign element number */ import->element = start_element + i; import->library = library; mutex_lock(&import->mutex); /* Create only one mailbox thread */ if (i == 0) { import->active_count = 1; import->first = (robo_event_t *)malloc_wait( sizeof (robo_event_t), 5, 0); (void) memset(import->first, 0, sizeof (robo_event_t)); import->first->type = EVENT_TYPE_INTERNAL; import->first->status.bits = REST_FREEMEM; import->first->request.internal.command = ROBOT_INTRL_INIT; if (thr_create(NULL, SM_THR_STK, &import_thread, (void *) import, (THR_DETACHED | THR_BOUND | THR_NEW_LWP), &import->thread)) { DevLog(DL_SYSERR(5118)); import->thread = (thread_t)- 1; } } if (i != (count - 1)) { /* Allocate next entry */ import->next = (iport_state_t *)malloc_wait( sizeof (iport_state_t), 5, 0); (void) memset(import->next, 0, sizeof (iport_state_t)); /* set back link */ import->next->previous = import; import = import->next; } } import->next = NULL; /* no next mailbox */ SANITY_CHECK(library->import != (iport_state_t *)0); library->import->previous = NULL; /* allocate the audit table if needed */ BE16toH(&pg1d->first_stor, &start_element); BE16toH(&pg1d->num_stor, &count); library->range.storage_lower = start_element; library->range.storage_count = count; library->range.storage_upper = start_element + count - 1; /* add for the import/export door slots */ if (un->type == DT_ACL452) count += library->range.ie_count; DevLog(DL_DETAIL(5220), library->range.drives_count, library->range.transport_count, library->range.storage_count, library->range.ie_count); if (thr_setconcurrency(conlevel)) { DevLog(DL_SYSERR(5058)); } /* * If the audit table is the wrong length (based on the number of * storage elements returned by mode-sense) or the audit bit is set, * the set up for an audit. */ if ((library->audit_tab_len == 0) || un->status.b.audit) { int added_more_time = FALSE; char *l_mess = un->dis_mes[DIS_MES_NORM]; /* * Audit table does not exist or is the wrong length. This * is generally a bad thing and will force an initialize * element scsi command and an audit. Both of these take a * long time. */ /* tell the outside world */ un->status.b.audit = TRUE; memccpy(l_mess, catgets(catfd, SET, 9022, "initializing elements"), '\0', DIS_MES_LEN); mutex_lock(&un->io_mutex); retry = 2; do { /* * Allow 16 seconds for each storage element and 30 * seconds of slop. */ (void) memset(sense, 0, sizeof (sam_extended_sense_t)); if ((err = scsi_cmd(library->open_fd, un, SCMD_INIT_ELEMENT_STATUS, (count << 4) + 30)) < 0) { TAPEALERT_SKEY(library->open_fd, un); GENERIC_SCSI_ERROR_PROCESSING(un, library->scsi_err_tab, 0, err, added_more_time, retry, /* code for DOWN_EQU */ down_library(library, SAM_STATE_CHANGE); mutex_unlock(&un->io_mutex); return (-1); /* MACRO for cstyle */, /* code for ILLREQ */ mutex_unlock(&un->io_mutex); return (-1); /* MACRO for cstyle */,
cdrom_ioctl(int fd, u_long cmd, void *arg) { int ret; cgc_t cgc; switch (cmd) { case CDROMREADRAW: case CDROMREADMODE1: case CDROMREADMODE2: { struct cdrom_msf *msf; int blocksize = 0, format = 0, lba; switch (cmd) { case CDROMREADRAW: blocksize = CD_FRAMESIZE_RAW; break; case CDROMREADMODE1: blocksize = CD_FRAMESIZE; format = 2; break; case CDROMREADMODE2: blocksize = CD_FRAMESIZE_RAW0; break; } msf = (struct cdrom_msf *)arg; lba = msf_to_lba(msf->cdmsf_min0,msf->cdmsf_sec0, msf->cdmsf_frame0); ret = EINVAL; if (lba < 0) break; cgc_init(&cgc, arg, blocksize, SUC_READ); ret = cdrom_read_block(fd, &cgc, lba, 1, format, blocksize); if (ret) { /* * SCSI-II devices are not required to support CMD_READ_CD (which specifies * the blocksize to read) so try switching the block size with a mode select, * doing the normal read sector command and then changing the sector size back * to 2048. * * If the program dies before changing the blocksize back sdopen() * in the kernel will fail opens with a message that looks something like: * * "sr1: blksize 2336 not multiple of 512: cannot use" * * At that point the drive has to be power cycled (or reset in some other way). */ if (ret = cdrom_blocksize(fd, blocksize)) break; ret = cdrom_read_cd(fd, &cgc, lba, blocksize, 1); ret |= cdrom_blocksize(fd, 2048); } break; } case CDROMREADTOCHDR: { struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; u_char buffer[12]; cgc_init(&cgc, buffer, sizeof (buffer), SUC_READ); cgc.cdb[0] = CMD_READ_TOC_PMA_ATIP; cgc.cdb[1] = 0x2; /* MSF */ cgc.cdb[8] = 12; /* LSB of length */ ret = scsi_cmd(fd, &cgc); if (!ret) { tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk1 = buffer[3]; } break; } case CDROMREADTOCENTRY: { struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg; u_char buffer[12]; cgc_init(&cgc, buffer, sizeof (buffer), SUC_READ); cgc.cdb[0] = CMD_READ_TOC_PMA_ATIP; cgc.cdb[1] = (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; cgc.cdb[6] = tocentry->cdte_track; cgc.cdb[8] = 12; /* LSB of length */ ret = scsi_cmd(fd, &cgc); if (ret) break; tocentry->cdte_ctrl = buffer[5] & 0xf; tocentry->cdte_adr = buffer[5] >> 4; tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0; if (tocentry->cdte_format == CDROM_MSF) { tocentry->cdte_addr.msf.minute = buffer[9]; tocentry->cdte_addr.msf.second = buffer[10]; tocentry->cdte_addr.msf.frame = buffer[11]; } else tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8) + buffer[10]) << 8) + buffer[11]; break; } case CDROMEJECT: /* NO-OP for now */ ret = cdrom_tray_move(fd, 1); break; case CDROMCLOSETRAY: ret = cdrom_tray_move(fd, 0); break; /* * This sucks but emulates the expected behaviour. Instead of the return * value being the actual status a success/fail indicator should have been * returned and the 3rd arg to the ioctl should have been an 'int *' to update * with the actual status. Both the drive and disc status ioctl calls are * similarily braindamaged. */ case CDROM_DRIVE_STATUS: return(CDS_NO_INFO); /* XXX */ case CDROM_DISC_STATUS: { tracktype tracks; int cnt; cdrom_count_tracks(fd, &tracks); if (tracks.error) return(tracks.error); if (tracks.audio > 0) { cnt = tracks.data + tracks.cdi + tracks.xa; if (cnt == 0) return(CDS_AUDIO); else return(CDS_MIXED); } if (tracks.cdi) return(CDS_XA_2_2); if (tracks.xa) return(CDS_XA_2_1); if (tracks.data) return(CDS_DATA_1); return(CDS_NO_INFO); } } errno = ret; return(ret ? -1 : 0); }
static int dvd_do_auth(int fd, dvd_authinfo *ai) { int ret; u_char buf[20]; cgc_t cgc; rpc_state_t rpc_state; memset(buf, 0, sizeof(buf)); cgc_init(&cgc, buf, 0, SUC_READ); switch (ai->type) { case DVD_LU_SEND_AGID: /* LU data send */ setup_report_key(&cgc, ai->lsa.agid, 0); if (ret = scsi_cmd(fd, &cgc)) return ret; ai->lsa.agid = buf[7] >> 6; break; case DVD_LU_SEND_KEY1: setup_report_key(&cgc, ai->lsk.agid, 2); if (ret = scsi_cmd(fd, &cgc)) return ret; copy_key(ai->lsk.key, &buf[4]); break; case DVD_LU_SEND_CHALLENGE: setup_report_key(&cgc, ai->lsc.agid, 1); if (ret = scsi_cmd(fd, &cgc)) return ret; copy_chal(ai->lsc.chal, &buf[4]); break; case DVD_LU_SEND_TITLE_KEY: /* Post-auth key */ setup_report_key(&cgc, ai->lstk.agid, 4); cgc.cdb[5] = ai->lstk.lba; cgc.cdb[4] = ai->lstk.lba >> 8; cgc.cdb[3] = ai->lstk.lba >> 16; cgc.cdb[2] = ai->lstk.lba >> 24; if (ret = scsi_cmd(fd, &cgc)) return ret; ai->lstk.cpm = (buf[4] >> 7) & 1; ai->lstk.cp_sec = (buf[4] >> 6) & 1; ai->lstk.cgms = (buf[4] >> 4) & 3; copy_key(ai->lstk.title_key, &buf[5]); break; case DVD_LU_SEND_ASF: setup_report_key(&cgc, ai->lsasf.agid, 5); if (ret = scsi_cmd(fd, &cgc)) return ret; ai->lsasf.asf = buf[7] & 1; break; case DVD_HOST_SEND_CHALLENGE: /* LU data receive (LU changes state) */ setup_send_key(&cgc, ai->hsc.agid, 1); buf[1] = 0xe; copy_chal(&buf[4], ai->hsc.chal); if (ret = scsi_cmd(fd, &cgc)) return ret; ai->type = DVD_LU_SEND_KEY1; break; case DVD_HOST_SEND_KEY2: setup_send_key(&cgc, ai->hsk.agid, 3); buf[1] = 0xa; copy_key(&buf[4], ai->hsk.key); if (ret = scsi_cmd(fd, &cgc)) { ai->type = DVD_AUTH_FAILURE; return ret; } ai->type = DVD_AUTH_ESTABLISHED; break; case DVD_INVALIDATE_AGID: setup_report_key(&cgc, ai->lsa.agid, 0x3f); if (ret = scsi_cmd(fd, &cgc)) return ret; break; case DVD_LU_SEND_RPC_STATE: /* Get region settings */ setup_report_key(&cgc, 0, 8); memset(&rpc_state, 0, sizeof(rpc_state_t)); cgc.buf = (char *) &rpc_state; if (ret = scsi_cmd(fd, &cgc)) { ai->lrpcs.type = 0; ai->lrpcs.rpc_scheme = 0; } else { ai->lrpcs.type = rpc_state.type_code; ai->lrpcs.vra = rpc_state.vra; ai->lrpcs.ucca = rpc_state.ucca; ai->lrpcs.region_mask = rpc_state.region_mask; ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; } break; case DVD_HOST_SEND_RPC_STATE: /* Set region settings */ setup_send_key(&cgc, 0, 6); buf[1] = 6; buf[4] = ai->hrpcs.pdrc; if (ret = scsi_cmd(fd, &cgc)) return ret; break; default: return EINVAL; } return 0; }
/* * clean_3570 - attempt to load cleaning tape into 3570. */ void clean_3570( drive_state_t *drive, robo_event_t *event, struct CatalogEntry *ce) { int retry; char *dev_name; char *d_mess = drive->un->dis_mes[DIS_MES_NORM]; dev_ent_t *un = drive->un; library_t *library = drive->library; move_flags_t move_flags; mutex_lock(&drive->mutex); move_flags.bits = 0; /* * The 3570 does not return from the move until the cleaning cycle * has completed. */ memccpy(d_mess, catgets(catfd, SET, 9030, "wait for cleaning cycle"), '\0', DIS_MES_LEN); if (generic_get_media(library, drive, event, ce)) { memccpy(drive->un->dis_mes[DIS_MES_CRIT], catgets(catfd, SET, 9029, "unable to load cleaning cartridge, move failed"), '\0', DIS_MES_LEN); DevLog(DL_ERR(5145), ce->CeSlot); down_drive(drive, SAM_STATE_CHANGE); drive->status.b.cln_inprog = FALSE; mutex_unlock(&drive->mutex); disp_of_event(library, event, EIO); return; } mutex_unlock(&drive->mutex); sleep(4); dev_name = samst_devname(un); mutex_lock(&un->mutex); drive->open_fd = open_unit(un, dev_name, 10); mutex_unlock(&un->mutex); free(dev_name); un->i.ViEq = un->fseq; un->i.ViSlot = un->slot; un->i.ViPart = 0; un->i.ViFlags = VI_cart; UpdateCatalog(drive->un, 0, CatalogVolumeLoaded); /* Wait for cleaning to finish */ retry = 60; while (retry--) { sam_extended_sense_t *sense = (sam_extended_sense_t *) SHM_REF_ADDR(un->sense); mutex_lock(&un->io_mutex); memset(sense, 0, sizeof (sam_extended_sense_t)); if (scsi_cmd(drive->open_fd, un, SCMD_TEST_UNIT_READY, 20) || sense->es_key != 0) { /* If cleaning in progress */ if (sense->es_key == 0x02 && sense->es_add_code == 0x30 && sense->es_qual_code == 0x03) { mutex_unlock(&un->io_mutex); sleep(30); continue; } if (sense->es_key == 0x06 && sense->es_add_code == 0x82 && sense->es_qual_code == 0x83) break; mutex_unlock(&un->io_mutex); sprintf(d_mess, "sense %x, %x, %x", sense->es_key, sense->es_add_code, sense->es_qual_code); sleep(10); } } if (retry <= 0) DevLog(DL_ERR(5216)); memccpy(d_mess, catgets(catfd, SET, 9034, "drive has been cleaned"), '\0', DIS_MES_LEN); mutex_unlock(&un->io_mutex); mutex_lock(&un->mutex); close_unit(un, &drive->open_fd); mutex_unlock(&un->mutex); mutex_lock(&drive->mutex); move_flags.bits = 0; memccpy(d_mess, catgets(catfd, SET, 9009, "waiting for media changer"), '\0', DIS_MES_LEN); if (move_media(library, 0, drive->element, 0xff, 1, move_flags)) { memccpy(drive->un->dis_mes[DIS_MES_CRIT], catgets(catfd, SET, 9032, "unable to unload cleaning cartridge"), '\0', DIS_MES_LEN); DevLog(DL_ERR(5147)); drive->status.b.cln_inprog = FALSE; down_drive(drive, SAM_STATE_CHANGE); mutex_unlock(&drive->mutex); disp_of_event(library, event, EIO); return; } if (CatalogVolumeUnloaded(&un->i, "") == -1) { DevLog(DL_SYSERR(5336), ce->CeSlot); } drive->status.b.cln_inprog = FALSE; mutex_lock(&drive->un->mutex); drive->un->status.bits &= ~(DVST_CLEANING | DVST_REQUESTED); un->label_time = 0; mutex_unlock(&drive->un->mutex); mutex_unlock(&drive->mutex); disp_of_event(library, event, 0); }