static void robot_state_init(struct robot_state *rs) { int i; /* invent some nice data, with some nice voltags and whatnot */ NDMOS_API_BZERO(rs, sizeof(*rs)); /* (nothing to do for MTEs) */ for (i = 0; i < STORAGE_COUNT; i++) { struct element_state *es = &rs->storage[i]; es->full = 1; es->medium_type = 1; /* data */ es->source_element = 0; snprintf(es->pvoltag, sizeof(es->pvoltag), "PTAG%02XXX ", i); snprintf(es->avoltag, sizeof(es->avoltag), "ATAG%02XXX ", i); } /* (i/e are all empty) */ /* (dte's are all empty) */ }
/* * Env list mgmt. * * Return a chunk of memory with all entries from the envlist as * one big enumeration useable for rpc to use as return value. * We allacate the memory and keep the pointer in the table handle * which gets freed on destroy of the table. */ ndmp9_pval * ndma_enumerate_env_list (struct ndm_env_table *envtab) { int i; struct ndm_env_entry * entry; /* * See if we need to allocate memory or can reuse the memory * already allocated in an earlier call. */ if (!envtab->enumerate) { envtab->enumerate = NDMOS_API_MALLOC (sizeof(ndmp9_pval) * envtab->n_env); envtab->enumerate_length = envtab->n_env; } else if (envtab->enumerate_length != envtab->n_env) { NDMOS_API_FREE (envtab->enumerate); envtab->enumerate = NDMOS_API_MALLOC (sizeof(ndmp9_pval) * envtab->n_env); envtab->enumerate_length = envtab->n_env; } if (!envtab->enumerate) { return NULL; } NDMOS_API_BZERO (envtab->enumerate, sizeof(ndmp9_pval) * envtab->n_env); i = 0; for (entry = envtab->head; entry; entry = entry->next) { memcpy (&envtab->enumerate[i], &entry->pval, sizeof(ndmp9_pval)); i++; } return envtab->enumerate; }
/* * Nlist mgmt. * * Return a chunk of memory with all entries from the nlist as * one big enumeration useable for rpc to use as return value. * We allacate the memory and keep the pointer in the table handle * which gets freed on destroy of the table. */ ndmp9_name * ndma_enumerate_nlist (struct ndm_nlist_table *nlist) { int i; struct ndm_nlist_entry * entry; /* * See if we need to allocate memory or can reuse the memory * already allocated in an earlier call. */ if (!nlist->enumerate) { nlist->enumerate = NDMOS_API_MALLOC (sizeof(ndmp9_name) * nlist->n_nlist); nlist->enumerate_length = nlist->n_nlist; } else if (nlist->enumerate_length != nlist->n_nlist) { NDMOS_API_FREE (nlist->enumerate); nlist->enumerate = NDMOS_API_MALLOC (sizeof(ndmp9_name) * nlist->n_nlist); nlist->enumerate_length = nlist->n_nlist; } if (!nlist->enumerate) { return NULL; } NDMOS_API_BZERO (nlist->enumerate, sizeof(ndmp9_name) * nlist->n_nlist); i = 0; for (entry = nlist->head; entry; entry = entry->next) { memcpy (&nlist->enumerate[i], &entry->name, sizeof(ndmp9_name)); i++; } return nlist->enumerate; }
/* Decommission -- Discard agent */ int ndmda_decommission (struct ndm_session *sess) { ndmis_data_close (sess); ndmda_purge_environment (sess); ndmda_purge_nlist (sess); ndmda_fh_decommission (sess); NDMOS_API_BZERO (sess->data_acb->bu_type,sizeof sess->data_acb->bu_type); ndmda_commission (sess); return 0; }
static ndmp9_error execute_cdb_inquiry (struct ndm_session *sess, ndmp9_execute_cdb_request *request, ndmp9_execute_cdb_reply *reply) { unsigned char *cdb = (unsigned char *)request->cdb.cdb_val; char *response; int response_len; char *p; /* N.B.: only page code 0 is supported */ if (request->cdb.cdb_len != 6 || request->data_dir != NDMP9_SCSI_DATA_DIR_IN || cdb[1] & 0x01 || cdb[2] != 0 || request->datain_len < 96 || ((cdb[3] << 8) + cdb[4]) < 96) return scsi_fail_with_sense_code(sess, reply, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_KEY_ILLEGAL_REQUEST, ASQ_INVALID_FIELD_IN_CDB); response_len = 96; p = response = NDMOS_API_MALLOC(response_len); NDMOS_API_BZERO(response, response_len); *(p++) = 0x08; /* media changer */ *(p++) = 0; /* RMB=0 */ *(p++) = 6; /* VERSION=SPC-4 */ *(p++) = 2; /* !NORMACA, !HISUP, RESPONSE DATA FORMAT = 2 */ *(p++) = 92; /* remaining bytes */ *(p++) = 0; /* lots of flags, all 0 */ *(p++) = 0; /* lots of flags, all 0 */ *(p++) = 0; /* lots of flags, all 0 */ NDMOS_API_BCOPY("NDMJOB ", p, 8); p += 8; NDMOS_API_BCOPY("FakeRobot ", p, 16); p += 16; NDMOS_API_BCOPY("1.0 ", p, 4); p += 4; /* remainder is zero */ reply->datain.datain_len = response_len; reply->datain.datain_val = response; return NDMP9_NO_ERR; }
ndmp9_error ndmos_tape_open (struct ndm_session *sess, char *drive_name, int will_write) { struct ndm_tape_agent * ta = &sess->tape_acb; struct simu_gap gap; struct stat st; int read_only, omode; int rc, fd; char pos_symlink_name[PATH_MAX]; char pos_buf[32]; off_t pos = -1; if (ta->tape_fd >= 0) { return NDMP9_DEVICE_OPENED_ERR; } if (stat (drive_name, &st) < 0) { return NDMP9_NO_DEVICE_ERR; } read_only = (st.st_mode & 0222) == 0; if (!will_write) { omode = 0; } else { if (read_only) return NDMP9_WRITE_PROTECT_ERR; omode = 2; /* ndmp_write means read/write */ } if (touch_tape_lockfile(drive_name) < 0) return NDMP9_DEVICE_BUSY_ERR; fd = open (drive_name, omode); if (fd < 0) { return NDMP9_PERMISSION_ERR; } snprintf(pos_symlink_name, sizeof pos_symlink_name, "%s.pos", drive_name); pos_symlink_name[sizeof pos_symlink_name -1] = '\0'; if (st.st_size == 0) { remove (pos_symlink_name); if (will_write) { gap.magic = SIMU_GAP_MAGIC; gap.rectype = SIMU_GAP_RT_BOT; gap.size = 0; gap.prev_size = 0; if (write (fd, &gap, sizeof gap) < (int)sizeof gap) { close(fd); return NDMP9_IO_ERR; } gap.rectype = SIMU_GAP_RT_EOT; if (write (fd, &gap, sizeof gap) < (int)sizeof gap) { close(fd); return NDMP9_IO_ERR; } lseek (fd, (off_t)0, 0); } else { goto skip_header_check; } } rc = read (fd, &gap, sizeof gap); if (rc != sizeof gap) { close (fd); return NDMP9_NO_TAPE_LOADED_ERR; } #if 1 if (gap.magic != SIMU_GAP_MAGIC) { close (fd); return NDMP9_IO_ERR; } #else if (gap.magic != SIMU_GAP_MAGIC || gap.rectype != SIMU_GAP_RT_BOT || gap.size != 0) { close (fd); return NDMP9_IO_ERR; } #endif rc = readlink (pos_symlink_name, pos_buf, sizeof pos_buf); if (rc > 0) { pos_buf[rc] = 0; pos = strtol (pos_buf, 0, 0); lseek (fd, pos, 0); rc = read (fd, &gap, sizeof gap); if (rc == sizeof gap && gap.magic == SIMU_GAP_MAGIC) { } else { pos = sizeof gap; } lseek (fd, pos, 0); } skip_header_check: remove (pos_symlink_name); ta->tape_fd = fd; NDMOS_API_BZERO (ta->drive_name, sizeof ta->drive_name); strncpy (ta->drive_name, drive_name, sizeof ta->drive_name - 1); bzero (&ta->tape_state, sizeof ta->tape_state); ta->tape_state.error = NDMP9_NO_ERR; ta->tape_state.state = NDMP9_TAPE_STATE_OPEN; ta->tape_state.open_mode = will_write ? NDMP9_TAPE_RDWR_MODE : NDMP9_TAPE_READ_MODE; ta->tape_state.file_num.valid = NDMP9_VALIDITY_VALID; ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_VALID; ta->tape_state.block_size.valid = NDMP9_VALIDITY_VALID; ta->tape_state.blockno.valid = NDMP9_VALIDITY_VALID; ta->tape_state.total_space.valid = NDMP9_VALIDITY_INVALID; ta->tape_state.space_remain.valid = NDMP9_VALIDITY_INVALID; ta->sent_leom = 0; if (o_tape_limit) { ta->tape_state.total_space.valid = NDMP9_VALIDITY_VALID; ta->tape_state.total_space.value = o_tape_limit; ta->tape_state.space_remain.valid = NDMP9_VALIDITY_VALID; ta->tape_state.space_remain.value = o_tape_limit - st.st_size; } return NDMP9_NO_ERR; }
static ndmp9_error execute_cdb_read_element_status (struct ndm_session *sess, ndmp9_execute_cdb_request *request, ndmp9_execute_cdb_reply *reply) { unsigned char *cdb = (unsigned char *)request->cdb.cdb_val; struct robot_state rs; int min_addr, max_elts; char *response; int response_len; int required_len; int num_elts = IE_COUNT + MTE_COUNT + DTE_COUNT + STORAGE_COUNT; char *p; if (request->cdb.cdb_len != 12 || request->data_dir != NDMP9_SCSI_DATA_DIR_IN) return scsi_fail_with_sense_code(sess, reply, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_KEY_ILLEGAL_REQUEST, ASQ_INVALID_FIELD_IN_CDB); min_addr = (cdb[2] << 8) + cdb[3]; max_elts = (cdb[4] << 8) + cdb[5]; response_len = (cdb[7] << 16) + (cdb[8] << 8) + cdb[9]; if (response_len < 8) { return scsi_fail_with_sense_code(sess, reply, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_KEY_ILLEGAL_REQUEST, ASQ_INVALID_FIELD_IN_CDB); } /* this is bogus, but we don't allow "partial" status requests */ if (min_addr > IE_FIRST || max_elts < num_elts) { return scsi_fail_with_sense_code(sess, reply, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_KEY_ILLEGAL_REQUEST, ASQ_INVALID_FIELD_IN_CDB); } robot_state_load(sess, &rs); robot_state_save(sess, &rs); /* calculate the total space required */ required_len = 8; /* element status data header */ if (MTE_COUNT) { required_len += 8; /* element status page header */ required_len += 12 * MTE_COUNT; /* element status descriptor w/o tags */ } if (STORAGE_COUNT) { required_len += 8; /* element status page header */ required_len += 84 * STORAGE_COUNT; /* element status descriptor w/ tags */ } if (IE_COUNT) { required_len += 8; /* element status page header */ required_len += 84 * IE_COUNT; /* element status descriptor w/ tags */ } if (DTE_COUNT) { required_len += 8; /* element status page header */ required_len += 84 * DTE_COUNT; /* element status descriptor w/ tags */ } p = response = NDMOS_API_MALLOC(response_len); NDMOS_API_BZERO(response, response_len); /* write the element status data header */ *(p++) = IE_FIRST >> 8; /* first element address */ *(p++) = IE_FIRST & 0xff; *(p++) = num_elts >> 8; /* number of elements */ *(p++) = num_elts & 0xff; *(p++) = 0; /* reserved */ *(p++) = (required_len-8) >> 16; /* remaining byte count of report */ *(p++) = ((required_len-8) >> 8) & 0xff; *(p++) = (required_len-8) & 0xff; /* only fill in the rest if we have space */ if (required_len <= response_len) { int i; struct { int first, count, have_voltags, eltype; int empty_flags, full_flags; struct element_state *es; } page[4] = { { IE_FIRST, IE_COUNT, 1, 3, 0x38, 0x39, &rs.ie[0] }, { MTE_FIRST, MTE_COUNT, 0, 1, 0x00, 0x01, &rs.mte[0] }, { DTE_FIRST, DTE_COUNT, 1, 4, 0x08, 0x81, &rs.dte[0] }, { STORAGE_FIRST, STORAGE_COUNT, 1, 2, 0x08, 0x09, &rs.storage[0] }, }; for (i = 0; i < 4; i++) { int descr_size = page[i].have_voltags? 84 : 12; int totalsize = descr_size * page[i].count; int j; if (page[i].count == 0) continue; /* write the page header */ *(p++) = page[i].eltype; *(p++) = page[i].have_voltags? 0xc0 : 0; *(p++) = 0; *(p++) = descr_size; *(p++) = 0; /* reserved */ *(p++) = totalsize >> 16; *(p++) = (totalsize >> 8) & 0xff; *(p++) = totalsize & 0xff; /* and write each descriptor */ for (j = 0; j < page[i].count; j++) { int elt_addr = page[i].first + j; int src_elt = page[i].es[j].source_element; unsigned char byte9 = page[i].es[j].medium_type; if (src_elt!= 0) byte9 |= 0x80; /* SVALID */ *(p++) = elt_addr >> 8; *(p++) = elt_addr & 0xff; *(p++) = page[i].es[j].full? page[i].full_flags : page[i].empty_flags; *(p++) = 0; *(p++) = 0; *(p++) = 0; *(p++) = 0; *(p++) = 0; *(p++) = 0; *(p++) = byte9; *(p++) = src_elt >> 8; *(p++) = src_elt & 0xff; if (page[i].have_voltags) { int k; if (page[i].es[j].full) { for (k = 0; k < 32; k++) { if (!page[i].es[j].pvoltag[k]) break; p[k] = page[i].es[j].pvoltag[k]; } for (k = 0; k < 32; k++) { if (!page[i].es[j].avoltag[k]) break; p[k+36] = page[i].es[j].avoltag[k]; } } else { for (k = 0; k < 32; k++) { p[k] = p[k+36] = ' '; } } p += 72; } } } }
static ndmp9_error execute_cdb_mode_sense_6 (struct ndm_session *sess, ndmp9_execute_cdb_request *request, ndmp9_execute_cdb_reply *reply) { unsigned char *cdb = (unsigned char *)request->cdb.cdb_val; int page, subpage; char *response; int response_len; char *p; if (request->cdb.cdb_len != 6 || request->data_dir != NDMP9_SCSI_DATA_DIR_IN) return scsi_fail_with_sense_code(sess, reply, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_KEY_ILLEGAL_REQUEST, ASQ_INVALID_FIELD_IN_CDB); page = cdb[2] & 0x3f; subpage = cdb[3]; switch ((page << 8) + subpage) { case 0x1D00: /* Element Address Assignment */ if (request->datain_len < 20 || cdb[4] < 20) return scsi_fail_with_sense_code(sess, reply, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_KEY_ILLEGAL_REQUEST, ASQ_INVALID_FIELD_IN_CDB); response_len = 24; p = response = NDMOS_API_MALLOC(response_len); NDMOS_API_BZERO(response, response_len); *(p++) = response_len; *(p++) = 0; /* reserved medium type */ *(p++) = 0; /* reserved device-specific parameter */ *(p++) = 0; /* block descriptor length (DBD = 0 above)*/ *(p++) = 0x1D; /* page code */ *(p++) = 18; /* remaining bytes */ *(p++) = (MTE_FIRST >> 8) & 0xff; *(p++) = MTE_FIRST & 0xff; *(p++) = (MTE_COUNT >> 8) & 0xff; *(p++) = MTE_COUNT & 0xff; *(p++) = (STORAGE_FIRST >> 8) & 0xff; *(p++) = STORAGE_FIRST & 0xff; *(p++) = (STORAGE_COUNT >> 8) & 0xff; *(p++) = STORAGE_COUNT & 0xff; *(p++) = (IE_FIRST >> 8) & 0xff; *(p++) = IE_FIRST & 0xff; *(p++) = (IE_COUNT >> 8) & 0xff; *(p++) = IE_COUNT & 0xff; *(p++) = (DTE_FIRST >> 8) & 0xff; *(p++) = DTE_FIRST & 0xff; *(p++) = (DTE_COUNT >> 8) & 0xff; *(p++) = DTE_COUNT & 0xff; /* remainder is zero */ break; default: return scsi_fail_with_sense_code(sess, reply, SCSI_STATUS_CHECK_CONDITION, SCSI_SENSE_KEY_ILLEGAL_REQUEST, ASQ_INVALID_FIELD_IN_CDB); } reply->datain.datain_len = response_len; reply->datain.datain_val = response; return NDMP9_NO_ERR; }