1 " ***********************************************************
  2 " *                                                         *
  3 " * Copyright, (C) Honeywell Bull Inc., 1987                *
  4 " *                                                         *
  5 " * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  6 " *                                                         *
  7 " ***********************************************************
  8 
  9 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 10 "
 11 "         stock
 12 "
 13 "         Record Stock Management Routines
 14 "
 15 "         Entries:
 16 "
 17 "           withdraw - withdraws a single record address from a stock
 18 "
 19 "           withdraw_range - withdraws a single record address from
 20 "                     a stock within a range of addresses
 21 "
 22 "           withdraw_range_ext - same as withdraw_range, available
 23 "                     outside ALM Page Control
 24 "
 25 "           deposit - deposits a single record address into a stock
 26 "
 27 "           reset_os - resets all out-of-service bits in a stock
 28 "
 29 "           flush_os - removes all out-of-service entries from a stock.
 30 "                     Called when there is an unrecoverable I/O error
 31 "                     on a Volume Map page.
 32 "
 33 "           check_low_threshold - checks for stock below threshold and
 34 "                     selects a volume map page to replenish it
 35 "
 36 "           recover - adjust stock counts (called during ESD)
 37 "
 38 "         Written January 1982 by J. Bongiovanni
 39 "         Modified July 1982, J. Bongiovanni, for withdraw_range_ext
 40 "
 41 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 42 
 43           name      stock
 44           segdef    deposit
 45           segdef    withdraw
 46           segdef    withdraw_range
 47           segdef    withdraw_range_ext
 48           segdef    reset_os
 49           segdef    flush_os
 50           segdef    check_low_threshold
 51           segdef    recover
 52 
 53           bool      live_address,377777
 54           bool      os_address,400000
 55 
 56 reset_os_upper_bits:
 57           oct       377777777777                  " reset_os
 58           oct       000000777777                  " flush_os
 59 reset_os_lower_bits:
 60           oct       777777377777                  " reset_os
 61           oct       777777000000                  " flush_os
 62 
 63 high_record_address:
 64           oct       377777000000
 65 
 66 "^L
 67           include   aste
 68 "^L
 69           include   page_info
 70 "^L
 71           include   ptw
 72 "^L
 73           include   pvte
 74 "^L
 75           include   pxss_page_stack
 76 "^L
 77 
 78           include   stack_frame
 79 ^L
 80           include   stock_seg
 81 "^L
 82 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
 83 "
 84 "         withdraw - routine to withdraw a single record address
 85 "
 86 "         tsx7      stock$withdraw
 87 "         <return if no addresses in stock>
 88 "         <return if succeed with withdrawal>
 89 "
 90 "         On entry
 91 "             ab -> stock_seg$meters
 92 "             bb -> stock of interest
 93 "
 94 "         On exit
 95 "             Areg contains address
 96 "
 97 "
 98 "         withdraw_range - routine to withdraw a single record address
 99 "              within a range specified
100 "
101 "         Same as above, except on entry
102 "             AU = high address (rec < high address)
103 "             AL = low address  (rec >= low address)
104 "
105 "         withdraw_range_ext - withdraw range accessible outside
106 "             ALM Page control
107 "
108 "             call page$withdraw_range (pvtep, low_address, high_address, record_address)
109 "
110 "         No locks are required by this routine.
111 "
112 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
113 
114 withdraw_range_ext:
115           push
116 
117           stz       ap|8,*                        " Clear returned address
118           tsx6      page_fault$init_savex
119 
120           eppbp     ap|2,*                        " bp -> ptr -> PVTE
121           eppbp     bp|0,*                        " bp -> PVTE
122           lprpbb    bp|pvte.volmap_stock_ptr      " bb -> stock
123           epbpab    bb|0                          " ab -> base of stock_seg
124           eppab     ab|stock_seg.meters           " ab -> meters
125 
126           lda       ap|6,*                        " AL = high address
127           als       18                            " AU = high address
128           ora       ap|4,*                        " AU = high address, AL = low address
129           tsx7      withdraw_range                " Try for an address
130           tra       withdraw_range_ext_ret        " None
131 
132           eppap     sp|stack_frame.arg_ptr,*      " Restore argument list ptr
133           sta       ap|8,*                        " Record address
134 
135 withdraw_range_ext_ret:
136           return
137 
138 
139 
140 withdraw:
141           eax6      0                             " withdraw
142           stz       stock_temp_1                  " low address
143           lda       high_record_address
144           sta       stock_temp_2                  " high address
145           increment ab|rsmeters.n_withdraw_attempt
146           tra       withdraw_join
147 
148 withdraw_range:
149           eax6      1                             " withdraw_range
150           increment ab|rsmeters.n_withdraw_range
151           sta       stock_temp_2                  " high address
152           ana       -1,dl
153           als       18                            " low address
154           sta       stock_temp_1
155 
156 withdraw_join:
157           lxl0      bb|record_stock.stock_offset
158           eppap     bb|0,x0                       " ap -> stock
159 
160           eax6      0,x6                          " withdraw_range?
161           tnz       withdraw_set_begin            " Yes
162 
163           lxl0      bb|record_stock.search_index  " Roving pointer
164           eax0      -1,x0
165           tra       withdraw_common
166 
167 withdraw_retry:
168           eax6      0,x6                          " withdraw_range?
169           tze       withdraw_set_begin            " No
170           eax6      1,x6                          " Bump bail-out counter
171           cmpx6     2,du                          " Gone through once
172           tpl       0,x7                          " Yes -- once is enough
173 
174 withdraw_set_begin:
175           ldx0      -1,du                         " Start at the beginning
176 
177 withdraw_common:
178           ldx1      bb|record_stock.n_free_in_stock " Any free?
179           tze       0,x7                          " No -- give up
180 
181 withdraw_loop:
182           increment ab|rsmeters.withdraw_stock_steps " Meter
183           eax0      1,x0                          " Next 2 entires
184           cmpx0     bb|record_stock.n_words_in_stock " Any left
185           tpl       withdraw_retry                " No - retry from the top
186 
187 withdraw_loop_retry:
188           ldq       ap|0,x0                       " Next 2 entries
189           tze       withdraw_loop                 " Both empty
190           lda       ap|0,x0                       " Protected by Q, stacq
191           eax1      0,au                          " Check upper address
192           tmoz      withdraw_check_lower          " Empty or out-of-service
193           cmpx1     stock_temp_1                  " >= low address
194           tmi       withdraw_check_lower          " No
195           cmpx1     stock_temp_2                  " < high address
196           tpl       withdraw_check_lower          " No
197           ana       -1,dl                         " Mark upper as empty
198           tra       withdraw_try                  " And attempt lockless withdraw
199 withdraw_check_lower:
200           eax1      0,ql                          " Look at lower entry
201           tmoz      withdraw_loop                 " Empty or out-of-service
202           cmpx1     stock_temp_1                  " >= low address
203           tmi       withdraw_loop                 " No
204           cmpx1     stock_temp_2                  " < high address
205           tpl       withdraw_loop                 " No
206           ana       -1,du                         " Mark lower as empty
207 
208 withdraw_try:
209           stacq     ap|0,x0                       " Attempt lockless withdraw
210           tze       withdraw_succeed              " Made it
211           increment ab|rsmeters.withdraw_stock_losses
212           tra       withdraw_loop_retry           " Meter and retry
213 
214 withdraw_succeed:
215           eax6      0,x6                          " withdraw_range ?
216           tnz       withdraw_leave_pointer        " Yes -- don't adjust pointer
217           sxl0      bb|record_stock.search_index  " Roving pointer
218 withdraw_leave_pointer:
219           ldq       bb|record_stock.n_free_in_stock " Adjust count lockless
220           lda       bb|record_stock.n_free_in_stock
221           sba       1,du                          " One fewer free record
222           stacq     bb|record_stock.n_free_in_stock
223           tnz       withdraw_leave_pointer        " Lost race, retry
224 
225           eaa       0,x1                          " Record address
226           arl       18                            " Areg = record address
227           increment ab|rsmeters.n_pages_withdraw_stock
228           tra       1,x7
229 
230 "^L
231 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
232 "
233 "         deposit - routine to deposit a single address
234 "
235 "         tsx7      stock$deposit
236 "         <return if fail>
237 "         <return if succeed>
238 "
239 "         On entry,
240 "             Areg = address to deposit
241 "             ab -> stock_seg$meters
242 "             bb -> stock of interest
243 "
244 "         No locks are required by this routine.
245 "
246 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
247 
248 deposit:
249           cana      live_address,dl               " Valid record address
250           tze       page_error$deposit_zero_address " No - bad lossage
251 
252           sta       stock_temp_1                  " Record address
253           als       18                            " Into upper
254           sta       stock_temp_2
255 
256           increment ab|rsmeters.n_deposit_attempt
257 
258           lxl0      bb|record_stock.stock_offset
259           eppap     bb|0,x0                         " ap -> stock
260           lxl0      bb|record_stock.search_index  " Roving pointer
261           eax0      1,x0                          " Adjust for initial decrement
262           tra       deposit_common
263 
264 deposit_retry:
265           ldx0      bb|record_stock.n_words_in_stock " Start at the top
266 
267 deposit_common:
268           lxl1      bb|record_stock.n_os_in_stock " Check whether any free slots
269           adlx1     bb|record_stock.n_free_in_stock "   exist
270           cmpx1     bb|record_stock.n_in_stock
271           tpl       0,x7                          " None free
272 
273 deposit_loop:
274           increment ab|rsmeters.deposit_stock_steps
275           eax0      -1,x0                         " 2 entries/word
276           tmi       deposit_retry                 " None left
277 
278 deposit_loop_retry:
279           ldq       ap|0,x0                       " Next 2 entries
280           lda       ap|0,x0                       " Protected by Qreg, stacq
281           tze       deposit_try_upper             " Both entries free
282 
283           eax1      0,au                          " Check upper entry
284           tnz       deposit_check_lower           " Not free
285 deposit_try_upper:
286           ora       stock_temp_2                  " Dep address into upper
287           tra       deposit_try
288 
289 deposit_check_lower:
290           eax1      0,al                          " Check lower entry
291           tnz       deposit_loop                  " Not empty
292           ora       stock_temp_1                  " Dep address into lower
293 
294 deposit_try:
295           stacq     ap|0,x0                       " Lockless deposit
296           tze       deposit_succeed               " We win
297           increment ab|rsmeters.deposit_stock_losses
298           tra       deposit_loop_retry            " Lose - meter and retry
299 
300 deposit_succeed:
301           lda       1,dl                          " Set up to increment number OS
302           ldx1      stock_temp_2                  " Address just deposited
303           tmi       deposit_os                    " An out-of-service address
304           lda       1,du                          " Set up to increment number free
305           sxl0      bb|record_stock.search_index  " Roving pointer
306 
307 deposit_os:
308           sta       stock_temp_2                  " Save for lost race
309 deposit_os_retry:
310           ldq       bb|record_stock.n_free_in_stock
311           lda       stock_temp_2                  " Restore
312           adla      bb|record_stock.n_free_in_stock
313           stacq     bb|record_stock.n_free_in_stock  " Lockless update
314           tnz       deposit_os_retry              " Lost - retry
315 
316           increment ab|rsmeters.n_pages_deposit_stock
317           tra       1,x7
318 
319 "^L
320 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
321 "
322 "         reset_os - routine to reset all out-of-service bits
323 "
324 "         tsx7      stock$reset_os
325 "
326 "         On entry,
327 "             ab -> stock_seg$meters
328 "             bb -> stock of interest
329 "
330 "         No locks are required by this routine
331 "
332 "         flush_os - routine to remove all out-of-service entries
333 "            from a stock.
334 "
335 "         On entry, same as above
336 "
337 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
338 
339 reset_os:
340           eax6      0                             " reset_os
341           tra       reset_os_common
342 
343 flush_os:
344           eax6      1                             " flush_os
345 
346 reset_os_common:
347           increment ab|rsmeters.reset_os_calls
348 
349           lxl0      bb|record_stock.stock_offset
350           eppap     bb|0,x0                        " ap -> stock
351           ldx0      bb|record_stock.n_words_in_stock
352 
353 reset_os_loop:
354           eax0      -1,x0                         " One less
355           tmi       0,x7                          " Done - exit
356 
357 reset_os_loop_retry:
358           ldq       ap|0,x0                       " Next 2 addresses
359           ldx1      0,du                          " Count of OS reset
360           lda       ap|0,x0                       " Protected by Qreg, stacq
361           tze       reset_os_loop                 " None in use
362           tpl       reset_os_check_lower          " High address not OS
363           ldx1      1,du                          " Count of OS reset
364           ana       reset_os_upper_bits,x6        " Reset/Flush
365 reset_os_check_lower:
366           cana      =o400000,dl                   " Low address OS
367           tze       reset_os_try                  " No
368           adlx1     1,du                          " Bump counter
369           ana       reset_os_lower_bits,x6        " Reset/Flush
370 
371 reset_os_try:
372           eax1      0,x1                          " Any to reset
373           tze       reset_os_loop                 " No
374           stacq     ap|0,x0                       " Lockless
375           tze       reset_os_update_count         " Won
376           increment ab|rsmeters.reset_os_losses   " Lost - meter and retry
377           tra       reset_os_loop_retry
378 
379 reset_os_update_count:
380           stz       stock_temp_1
381           stz       stock_temp_2
382           sxl1      stock_temp_2                  " To decrement count of OS
383           eax6      0,x6                          " Flush call
384           tnz       reset_os_update_retry         " Yes - don't increment free count
385           stx1      stock_temp_1                  " To increment count of free
386 reset_os_update_retry:
387           ldq       bb|record_stock.n_free_in_stock " Change count of OS, free
388           lda       bb|record_stock.n_free_in_stock " Lockless
389           adla      stock_temp_1
390           sbla      stock_temp_2
391           stacq     bb|record_stock.n_free_in_stock
392           tnz       reset_os_update_retry         " lost race
393           tra       reset_os_loop
394 
395 
396 "^L
397 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
398 "
399 "         check_low_threshold - routine to check whether a stock is below
400 "                   threshold, and (if so) to select a volmap page to
401 "                   replenish it
402 "
403 "         tsx7      stock$check_low_threshold
404 "         <return if within threshold or no page selected>
405 "         <return if below threshold and page selected>
406 "
407 "         On entry,
408 "             ab -> stock_seg$meters
409 "             bb -> stock of interest
410 "             bp -> pvte
411 "
412 "         On exit,
413 "             if page selected, page number is in Areg
414 "
415 "         This routine requires the Global Page Table Lock, the per-volume
416 "         volume map lock (with async state idle)
417 "
418 "         A volmap page is selected as follows:
419 "
420 "         1. If a page is in memory, it is selected
421 "         2. If no page is in memory, the lowest page which can replenish
422 "            the stock to target is selected
423 "         3. Otherwise, the page with the largest number of free records
424 "            is selected
425 "
426 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
427 
428 check_low_threshold:
429           lxl0      bb|record_stock.n_os_in_stock
430           adlx0     bb|record_stock.n_free_in_stock
431           cmpx0     bb|record_stock.low_threshold " Below threshold
432           tpl       0,x7                          " No
433 
434           aos       ab|rsmeters.low_thresh_detected " Meter
435           stx0      stock_temp_1                  " Free + OS
436           ldx0      bb|record_stock.target        " Target for Free + OS
437           sbx0      stock_temp_1                  " Shortfall
438           stx0      stock_temp_1
439 
440           lprpap    bp|pvte.volmap_astep          " ap -> ASTE for volmap_seg
441           eppap     ap|aste_size                  " ap -> Page Table for volmap_seg
442           lxl0      bb|record_stock.n_volmap_pages
443           stz       stock_temp_2
444           sxl0      stock_temp_2
445           lda       0,dl                          " Page number
446           ldx1      -1,du                         " First page which can replenish
447           ldx2      -1,du                         " Page with largest number free
448 
449 check_low_mem:
450           ldx0      bb|record_stock.n_free,al     " Number free records this page
451           tze       check_low_next                " None - skip
452           ldq       ap|0,al                       " Qreg = PTW
453           canq      ptw.valid,dl                  " In memory
454           tnz       1,x7                          " Yes - exit with page number in Areg
455           cmpx0     stock_temp_1                  " Enough to replenish to target
456           tmi       check_low_not_enough          " No
457           eax1      0,x1                          " Found such yet
458           tpl       check_low_next                " Yes - use first such
459           eax1      0,al                          " No - this is such
460           tra       check_low_next
461 
462 check_low_not_enough:
463           eax2      0,x2                          " Largest number records so far
464           tpl       check_low_highest             " One such found
465           eax2      0,al                          " This is it
466           tra       check_low_next
467 check_low_highest:
468           cmpx0     bb|record_stock.n_free,x2     " Is this one higher
469           tmoz      check_low_next                " No
470           eax2      0,al                          " Yes
471 
472 check_low_next:
473           ada       1,dl                          " Bump page number
474           cmpa      stock_temp_2                  " Done all pages
475           tmi       check_low_mem                 " No
476           eaa       0,x1                          " First which can replenish
477           tpl       check_low_got                 " One was found
478           eaa       0,x2                          " Largest number records
479           tpl       check_low_got                 " Somebody found
480           aos       ab|rsmeters.low_thresh_fails  " Nobody found - meter
481           tra       0,x7                          " And exit
482 
483 check_low_got:
484           arl       18                            " Page number in AL
485           tra       1,x7
486 "^L
487 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
488 "
489 "         recover - routine to recompute counts in the record stock for ESD.
490 "                   The system may have crashed due to a stock inconsistency,
491 "                   and this may allow ESD to succeed. Of course, major
492 "                   trashage to the stock cannot be bypassed.
493 "
494 "         On entry,
495 "             ab -> stock_seg$meters
496 "             bb -> stock of interest
497 "             bp -> pvte
498 "
499 "         This routine should be called only during ESD
500 "
501 "
502 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
503 
504 recover:
505           stz       stock_temp_1                  " Number free
506           stz       stock_temp_2                  " Number out-of-service
507 
508           sprpbp    bb|record_stock.pvtep         " Restore pointer to PVTE
509           lxl0      bb|record_stock.stock_offset
510           eppap     bb|0,x0                       " ap -> stock array
511 
512           ldx0      bb|record_stock.n_words_in_stock
513 
514 recover_loop:
515           eax0      -1,x0                         " Index into stock array
516           tmi       recover_done                  " None left
517           lda       ap|0,x0                       " Next 2 entries
518           tze       recover_loop                  " Both empty
519           tpl       recover_check_upper           " Upper not out-of-service
520           aos       stock_temp_2                  " Upper out-of-service
521           tra       recover_check_lower
522 recover_check_upper:
523           cana      live_address,du               " Upper empty
524           tze       recover_check_lower           " Yes
525           aos       stock_temp_1                  " No
526 recover_check_lower:
527           cana      os_address,dl                 " Lower out-of-service
528           tze       recover_check_lower_inuse     " No
529           aos       stock_temp_2                  " Yes
530           tra       recover_loop
531 
532 recover_check_lower_inuse:
533           cana      live_address,dl               " Lower empty
534           tze       recover_loop                  " Yes
535           aos       stock_temp_1                  " No
536           tra       recover_loop
537 
538 recover_done:
539           lda       stock_temp_1                  " Number free
540           als       18                            " Align
541           ora       stock_temp_2                  " Merge in number out-of-service
542           sta       bb|record_stock.n_free_in_stock " And set count into stock
543 
544           tra       0,x7
545 
546           end