1 /*
2 * Copyright (c) 1998,1999,2000
3 * Traakan, Inc., Los Altos, CA
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
11 * disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * Project: NDMJOB
31 * Ident: $Id: $
32 *
33 * Description:
34 *
35 */
36
37
38 #include "ndmagents.h"
39
40
41 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
42
43
44 int
ndmca_robot_issue_scsi_req(struct smc_ctrl_block * smc)45 ndmca_robot_issue_scsi_req (struct smc_ctrl_block *smc)
46 {
47 struct ndmconn * conn = (struct ndmconn *) smc->app_data;
48 struct smc_scsi_req * sr = &smc->scsi_req;
49 int rc;
50
51 rc = ndmscsi_execute (conn, (struct ndmscsi_request *) sr, 0);
52 return rc;
53 }
54
55
56 int
ndmca_robot_prep_target(struct ndm_session * sess)57 ndmca_robot_prep_target (struct ndm_session *sess)
58 {
59 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
60 int rc;
61
62 NDMOS_MACRO_ZEROFILL (smc);
63
64 smc->app_data = sess->plumb.robot;
65 smc->issue_scsi_req = ndmca_robot_issue_scsi_req;
66
67 rc = ndmscsi_use (sess->plumb.robot,
68 &sess->control_acb.job.robot_target);
69 if (rc) return rc;
70
71 return 0;
72 }
73
74 int
ndmca_robot_obtain_info(struct ndm_session * sess)75 ndmca_robot_obtain_info (struct ndm_session *sess)
76 {
77 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
78 int rc;
79
80 rc = smc_inquire (smc);
81 if (rc) return rc;
82
83 rc = smc_get_elem_aa (smc);
84 if (rc) return rc;
85
86 rc = smc_read_elem_status (smc);
87 if (rc) return rc;
88
89 return 0;
90 }
91
92 int
ndmca_robot_init_elem_status(struct ndm_session * sess)93 ndmca_robot_init_elem_status (struct ndm_session *sess)
94 {
95 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
96 int rc;
97
98 ndmalogf (sess, 0, 1,
99 "Commanding robot to initialize element status (take inventory)");
100
101 rc = smc_init_elem_status (smc);
102 if (rc) {
103 ndmalogf (sess, 0, 0, "init-elem-status failed");
104 return rc;
105 }
106
107 return 0;
108 }
109
110 int
ndmca_robot_startup(struct ndm_session * sess)111 ndmca_robot_startup (struct ndm_session *sess)
112 {
113 int rc;
114
115 if (!sess->control_acb.job.have_robot)
116 return -1; /* Huh? why were we called */
117
118 rc = ndmca_connect_robot_agent(sess);
119 if (rc) return rc;
120
121 rc = ndmca_robot_prep_target(sess);
122 if (rc) return rc;
123
124 return 0;
125 }
126
127 int
ndmca_robot_move(struct ndm_session * sess,int src_addr,int dst_addr)128 ndmca_robot_move (struct ndm_session *sess, int src_addr, int dst_addr)
129 {
130 struct ndm_control_agent *ca = &sess->control_acb;
131 struct smc_ctrl_block * smc = &ca->smc_cb;
132 int rc;
133 unsigned int t;
134
135 ndmalogf (sess, 0, 2, "robot moving @%d to @%d",
136 src_addr, dst_addr);
137
138 rc = -1;
139 for (t = 0; t <= ca->job.robot_timeout; t += 10) {
140 if (t > 0) {
141 ndmalogf (sess, 0, 2,
142 "Pausing ten seconds before retry (%d/%d)",
143 t, ca->job.robot_timeout);
144 sleep (10);
145 }
146 rc = smc_move (smc, src_addr, dst_addr,
147 0, smc->elem_aa.mte_addr);
148 if (rc == 0) break;
149 }
150
151 if (rc == 0) {
152 ndmalogf (sess, 0, 2, "robot move OK @%d to @%d",
153 src_addr, dst_addr);
154 } else {
155 ndmalogf (sess, 0, 2, "robot move BAD @%d to @%d",
156 src_addr, dst_addr);
157 }
158
159 return rc;
160 }
161
162 int
ndmca_robot_load(struct ndm_session * sess,int slot_addr)163 ndmca_robot_load (struct ndm_session *sess, int slot_addr)
164 {
165 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
166 unsigned dte_addr = smc->elem_aa.dte_addr;
167 int rc;
168
169 if (sess->control_acb.job.drive_addr_given)
170 dte_addr = sess->control_acb.job.drive_addr;
171
172 ndmalogf (sess, 0, 1,
173 "Commanding robot to load slot @%d into drive @%d",
174 slot_addr, dte_addr);
175
176 rc = ndmca_robot_move (sess, slot_addr, dte_addr);
177
178 return rc;
179 }
180
181 int
ndmca_robot_unload(struct ndm_session * sess,int slot_addr)182 ndmca_robot_unload (struct ndm_session *sess, int slot_addr)
183 {
184 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
185 int dte_addr = smc->elem_aa.dte_addr;
186 int rc;
187
188 if (sess->control_acb.job.drive_addr_given)
189 dte_addr = sess->control_acb.job.drive_addr;
190
191 /* tricky part -- some (most?) robots need the drive to eject */
192
193 ndmalogf (sess, 0, 1,
194 "Commanding robot to unload drive @%d to slot @%d",
195 dte_addr, slot_addr);
196
197 rc = ndmca_robot_move (sess, dte_addr, slot_addr);
198
199 return rc;
200 }
201
202
203 struct smc_element_descriptor *
ndmca_robot_find_element(struct ndm_session * sess,int element_address)204 ndmca_robot_find_element (struct ndm_session *sess, int element_address)
205 {
206 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
207 unsigned int i;
208 struct smc_element_descriptor * edp;
209
210 for (i = 0; i < smc->n_elem_desc; i++) {
211 edp = &smc->elem_desc[i];
212 if (edp->element_address == element_address)
213 return edp;
214 }
215
216 return 0;
217 }
218
219 int
ndmca_robot_check_ready(struct ndm_session * sess)220 ndmca_robot_check_ready (struct ndm_session *sess)
221 {
222 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
223 unsigned first_dte_addr;
224 unsigned n_dte_addr;
225 int rc;
226 unsigned int i;
227 int errcnt = 0;
228 struct smc_element_descriptor * edp;
229
230 rc = ndmca_robot_obtain_info (sess);
231 if (rc) return rc;
232
233 if (sess->control_acb.job.remedy_all) {
234 first_dte_addr = smc->elem_aa.dte_addr;
235 n_dte_addr = smc->elem_aa.dte_count;
236 } else {
237 n_dte_addr = 1;
238 if (sess->control_acb.job.drive_addr_given) {
239 first_dte_addr = sess->control_acb.job.drive_addr;
240 } else {
241 first_dte_addr = smc->elem_aa.dte_addr;
242 }
243 }
244
245 for (i = 0; i < n_dte_addr; i++) {
246 edp = ndmca_robot_find_element (sess, first_dte_addr+i);
247
248 if (!edp->Full)
249 continue;
250
251 ndmalogf (sess, 0, 1, "tape drive @%d not empty",
252 edp->element_address);
253 errcnt++;
254 }
255
256 return errcnt;
257 }
258
259 int
ndmca_robot_remedy_ready(struct ndm_session * sess)260 ndmca_robot_remedy_ready (struct ndm_session *sess)
261 {
262 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
263 int rc;
264 unsigned int i;
265 int errcnt;
266 struct smc_element_descriptor * edp;
267 struct smc_element_descriptor * edp2;
268 unsigned first_dte_addr;
269 unsigned n_dte_addr;
270 char prefix[60];
271
272 errcnt = 0;
273
274 rc = ndmca_robot_obtain_info (sess);
275 if (rc) return rc;
276
277 if (sess->control_acb.job.remedy_all) {
278 first_dte_addr = smc->elem_aa.dte_addr;
279 n_dte_addr = smc->elem_aa.dte_count;
280 } else {
281 n_dte_addr = 1;
282 if (sess->control_acb.job.drive_addr_given) {
283 first_dte_addr = sess->control_acb.job.drive_addr;
284 } else {
285 first_dte_addr = smc->elem_aa.dte_addr;
286 }
287 }
288
289 for (i = 0; i < n_dte_addr; i++) {
290 edp = ndmca_robot_find_element (sess, first_dte_addr+i);
291
292 if (!edp->Full)
293 continue;
294
295 sprintf (prefix, "drive @%d not empty", edp->element_address);
296
297 if (!edp->SValid) {
298 ndmalogf (sess, 0, 1, "%s, invalid source", prefix);
299 errcnt++;
300 continue;
301 }
302
303 sprintf (NDMOS_API_STREND(prefix), ", src @%d",
304 edp->src_se_addr);
305
306 edp2 = ndmca_robot_find_element (sess, edp->src_se_addr);
307
308 if (edp2->element_type_code != SMC_ELEM_TYPE_SE) {
309 ndmalogf (sess, 0, 1, "%s, not slot", prefix);
310 errcnt++;
311 continue;
312 }
313
314 if (edp2->Full) {
315 ndmalogf (sess, 0, 1, "%s, but slot Full", prefix);
316 errcnt++;
317 continue;
318 }
319
320 rc = ndmca_robot_move (sess,
321 edp->element_address, edp->src_se_addr);
322 if (rc) {
323 ndmalogf (sess, 0, 1, "%s, move failed", prefix);
324 errcnt++;
325 continue;
326 }
327 }
328
329 return errcnt;
330 }
331
332
333
334 /*
335 * ndmca_robot_query() incrementally obtains info so that we
336 * can print progress.
337 */
338
339 int
ndmca_robot_query(struct ndm_session * sess)340 ndmca_robot_query (struct ndm_session *sess)
341 {
342 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
343 int rc;
344 unsigned int i;
345 char buf[100];
346 char lnbuf[30];
347 int lineno, nline = 1;
348
349 ndmalogqr (sess, " Type");
350
351 rc = smc_inquire (smc);
352 if (rc) {
353 ndmalogqr (sess, " ERROR smc_inquire(): %s", smc->errmsg);
354 } else {
355 ndmalogqr (sess, " '%s'", smc->ident);
356 }
357
358
359 ndmalogqr (sess, " Elements");
360 rc = smc_get_elem_aa (smc);
361 if (rc) {
362 ndmalogqr (sess, " ERROR smc_get_elem_aa(): %s", smc->errmsg);
363 } else {
364 strcpy (lnbuf, " ");
365 for (lineno = 0, nline = 1; lineno < nline; lineno++) {
366 rc = smc_pp_element_address_assignments (&smc->elem_aa,
367 lineno, buf);
368 if (rc < 0) {
369 strcpy (buf, "PP-ERROR");
370 }
371 nline = rc;
372 ndmalogqr (sess, "%s %s", lnbuf, buf);
373 }
374 }
375
376 ndmalogqr (sess, " Status");
377 rc = smc_read_elem_status (smc);
378 if (rc) {
379 ndmalogqr (sess, " ERROR smc_read_elem_status(): %s", smc->errmsg);
380 } else {
381 ndmalogqr (sess, " E# Addr Type Status");
382 ndmalogqr (sess, " -- ---- ---- ---------------------");
383 for (i = 0; i < smc->n_elem_desc; i++) {
384 struct smc_element_descriptor * edp;
385
386 edp = &smc->elem_desc[i];
387
388 for (lineno = 0, nline = 1; lineno < nline; lineno++) {
389 rc = smc_pp_element_descriptor (edp,
390 lineno, buf);
391
392 if (lineno == 0)
393 sprintf (lnbuf, " %2d ", i+1);
394 else
395 sprintf (lnbuf, " ");
396
397 if (rc < 0) {
398 strcpy (buf, "PP-ERROR");
399 }
400 nline = rc;
401 ndmalogqr (sess, "%s %s", lnbuf, buf);
402 }
403 }
404 }
405
406 return 0;
407 }
408
409
410 int
ndmca_robot_verify_media(struct ndm_session * sess)411 ndmca_robot_verify_media (struct ndm_session *sess)
412 {
413 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
414 struct ndm_media_table *mtab = &sess->control_acb.job.media_tab;
415 int rc;
416 struct ndmmedia * me;
417 struct smc_element_descriptor *edp;
418 int i;
419 unsigned int j;
420 int errcnt = 0;
421
422 rc = ndmca_robot_obtain_info (sess);
423 if (rc) return rc;
424
425 for (i = 0; i < mtab->n_media; i++) {
426 me = &mtab->media[i];
427
428 if (! me->valid_slot) {
429 me->slot_missing = 1;
430 errcnt++;
431 continue; /* what now */
432 }
433
434 for (j = 0; j < smc->n_elem_desc; j++) {
435 edp = &smc->elem_desc[j];
436
437 if (edp->element_type_code != SMC_ELEM_TYPE_SE)
438 continue;
439
440 if (edp->element_address != me->slot_addr)
441 continue;
442
443 if (!edp->Full) {
444 me->slot_empty = 1;
445 errcnt++;
446 } else {
447 me->slot_empty = 0;
448 }
449 break;
450 }
451 if (j >= smc->n_elem_desc) {
452 me->slot_bad = 1;
453 errcnt++;
454 }
455 }
456
457 return errcnt;
458 }
459
460 /*
461 * For NDM_JOB_OP_LIST_LABELS, fill in media_tab based on non-empty slots.
462 * Note: this might REALLY nerf on a cleaning cartridge.
463 */
464
465 int
ndmca_robot_synthesize_media(struct ndm_session * sess)466 ndmca_robot_synthesize_media (struct ndm_session *sess)
467 {
468 struct smc_ctrl_block * smc = &sess->control_acb.smc_cb;
469 struct ndm_media_table *mtab = &sess->control_acb.job.media_tab;
470 int rc;
471 struct ndmmedia * me;
472 struct smc_element_descriptor *edp;
473 unsigned int i;
474
475 rc = ndmca_robot_obtain_info (sess);
476 if (rc) return rc;
477
478 for (i = 0; i < smc->n_elem_desc; i++) {
479 edp = &smc->elem_desc[i];
480
481 if (edp->element_type_code != SMC_ELEM_TYPE_SE)
482 continue;
483
484 if (!edp->Full)
485 continue;
486
487 me = &mtab->media[mtab->n_media++];
488 NDMOS_MACRO_ZEROFILL (me);
489
490 me->valid_slot = 1;
491 me->slot_addr = edp->element_address;
492 }
493
494 return 0;
495 }
496 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */
497