home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1828 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  39.9 KB

  1. From: tin@szebra.szebra.uucp (Tin Le)
  2. Newsgroups: alt.sources
  3. Subject: ST-0X 386/ix driver pt 2/6
  4. Message-ID: <1990Sep17.062917.25505@szebra.uucp>
  5. Date: 17 Sep 90 06:29:17 GMT
  6.  
  7. Seagate ST-0x 386/ix driver v1.0
  8.  
  9. #!/bin/sh
  10. # this is st02.02 (part 2 of a multipart archive)
  11. # do not concatenate these parts, unpack them in order with /bin/sh
  12. # file README continued
  13. #
  14. if test ! -r _shar_seq_.tmp; then
  15.     echo 'Please unpack part 1 first!'
  16.     exit 1
  17. fi
  18. (read Scheck
  19.  if test "$Scheck" != 2; then
  20.     echo Please unpack part "$Scheck" next!
  21.     exit 1
  22.  else
  23.     exit 0
  24.  fi
  25. ) < _shar_seq_.tmp || exit 1
  26. if test ! -f _shar_wnt_.tmp; then
  27.     echo 'x - still skipping README'
  28. else
  29. echo 'x - continuing file README'
  30. sed 's/^X//' << 'SHAR_EOF' >> 'README' &&
  31. pins A-B shorted           CE000H
  32. pins A-B & C-D shorted     DE000H
  33. X
  34. The memory address set on the card must match the value defined in the driver.
  35. Check the driver source for the correct address.  If you want to use a
  36. different address, change the define in the source.
  37. X
  38. X
  39. Interrupt selection
  40. X
  41. No jumper installed       interrupts disabled (default configuration)
  42. E-F shorted               IRQ3
  43. F-G shorted               IRQ5
  44. X
  45. Interrupts must be enabled to use my driver under unix.  The interrupt
  46. selected must match the value in file "config" in the modules/scsi
  47. directory.  Check the config file for the correct value; change the value
  48. in config file if you wish to use some other value.
  49. X
  50. NOTE: at least in the card I received, there were no jumper connectors
  51. in E, F and G.  There were just holes in the card.  You have to solder the
  52. connection yourself.  It is not a difficult task if you have ever done
  53. any soldering, and luckily the card does not cost very much if something
  54. goes wrong...  It is better to ground the soldering iron before doing 
  55. anything.
  56. X
  57. If I recall correctly, I am using IRQ5, and soldered F&G together with a
  58. short wire.  A friend of mine had both of those interrupts in use,
  59. and soldered F to some other interrupt number on the bus and everything
  60. works fine.  However, I can't help with that.  For more info, see
  61. IBM AT technical manual.  (You might get some help by sending mail to
  62. jnopanen@hupu.hut.fi).
  63. X
  64. It seems like Seagate has been thinking that the controller would never
  65. be used with unix...
  66. X
  67. X
  68. I think the 0ws jumper should be connected on most (almost every?)
  69. machines.  On my machine it raised the transfer rate from about 500kB/sec
  70. to about 700kB/sec under msdos.  The transfer rate is really cpu-bound
  71. as the data transfers are done in software (the card does not support
  72. dma), so faster machines might get faster transfer rates (mine is a slow
  73. 16 MHz 386).
  74. X
  75. X  Tatu Yl|nen    ylo@hupu.hut.fi
  76. X
  77. SHAR_EOF
  78. echo 'File README is complete' &&
  79. chmod 0644 README ||
  80. echo 'restore of README failed'
  81. Wc_c="`wc -c < 'README'`"
  82. test 10877 -eq "$Wc_c" ||
  83.     echo 'README: original size 10877, current size' "$Wc_c"
  84. rm -f _shar_wnt_.tmp
  85. fi
  86. # ============= README.2 ==============
  87. if test -f 'README.2' -a X"$1" != X"-c"; then
  88.     echo 'x - skipping README.2 (File already exists)'
  89.     rm -f _shar_wnt_.tmp
  90. else
  91. > _shar_wnt_.tmp
  92. echo 'x - extracting README.2 (Text)'
  93. sed 's/^X//' << 'SHAR_EOF' > 'README.2' &&
  94. Copyright (c) 1990 Tin Le
  95. X
  96. ST0x SCSI driver version 1.0
  97. X
  98. Sunday 9/16/90
  99. X
  100. First, to cover my behind (don't you love lawyers? :) )
  101. X
  102. DISCLAIMER
  103. ----------
  104. X
  105. X    This software has been tested to the best of my abilities.
  106. X    It works for me.  However, you use this at your own risks.
  107. X
  108. README
  109. ------
  110. X
  111. X    SCSI driver for Seagate ST-02 Host Adapter for Interactive
  112. X    386/ix v2.0.2.  Usage rights are release into the public
  113. X    domain.  You may use and distribute this package, but you
  114. X    may not charge for it.
  115. X
  116. X    This is a modified version of the ST-01 driver by Tatu Ylonen.
  117. X    His driver was for Microport UNIX v3.00e, I adapted it for
  118. X    386/ix, fixed some problems (changed char to unsigned char),
  119. X    optimized things a little bit more.
  120. X
  121. X    The difference between the ST-01 and ST-02 is that the ST-02
  122. X    also include floppy ctlr (both 5 1/4" and 3 1/2").  Since Tatu
  123. X    wrote his driver, Seagate apparently changed the revision of
  124. X    the ST-0X boards.  They now uses 16K BIOS instead of 8K.
  125. X    Luckily, the hardware addresses seemed to have been kept the
  126. X    same (anyone who knows how I can get more technical information
  127. X    on these boards, please let me know - email to tin@szebra.uucp
  128. X    or uunet!claris!szebra!tin).
  129. X
  130. X    Here is a recap of the featurres and drawbacks of the boards:
  131. X
  132. X    Advantages:
  133. X
  134. X    - will work with most SCSI disks
  135. X    - no limit on disk or partition size
  136. X    - each physical driver can have up to 15 partitions
  137. X    - support multiple drives (up to 7) on a single ctrlr
  138. X    - transfer rate faster than MFM disk
  139. X    - the ST-02 (ST-01) will work in the system along with
  140. X    other controller you have (ST506 or RLL).
  141. X    - driver is free and complete SCSI subsystem can be put
  142. X    together at low cost
  143. X    - you have source code!
  144. X
  145. X    Disadvantages:
  146. X
  147. X    - does not use DMA
  148. X    - character devices not supported (no raw I/O)
  149. X    - you can not boot from SCSI disk
  150. X    - lots of data movement at each interrupt, which can
  151. X    lead to contention with the serial ports
  152. X
  153. X    Besides the drives Tatu used, some of the other ones that works
  154. X    are: a CDC Imprimis 94161-156 (150MB formatted), Seagate ST296N
  155. X    (80MB formatted).  I used it on my Usenet news node, and also
  156. X    XBBS.  As I mentioned, under heavy disk usage, the serial port
  157. X    will start dropping characters.  However, I run my Telebit+ at
  158. X    19200 bps so my guess is that 2400 or less should be OK.  I
  159. X    might eventually rewrite the driver interrupt in assembler to
  160. X    help speed up things, but I doubt it'd make much difference.
  161. X    There's only so much that can be done in moving large amounts
  162. X    of data using interrupts driven approach.  My suggestion is to
  163. X    use the FAS driver with a 16550AN (that's what I did, and yes
  164. X    it works!).
  165. X
  166. X    I also have a WD1003 ST506 16 bit controller (since I can't
  167. X    boot on SCSI - yet!) in the system controlling a Micropolis 72MB
  168. X    and 2 floppies.
  169. X    
  170. X
  171. INSTALLATION
  172. ------------
  173. X
  174. NOTE:    You must be root during this entire installation process!
  175. X
  176. X    I am assuming that you are using Interactive 386/ix v2.0.2,
  177. X    as that is the only *NIX I have available to me for my 386.
  178. X    If (when) I decide to move to newer versions, I will definitely
  179. X    port the driver.
  180. X
  181. X    BEFORE YOU DO ANYTHING, BACK UP YOUR DATA FILES!
  182. X
  183. X    Backup this file:
  184. X
  185. X    /etc/conf/cf.d/mdevice ---------> /etc/conf/cf.d/mdevice.org
  186. X
  187. NOTE:
  188. The ST-01 and ST-02 comes with BIOS (either 8K or 16K), you
  189. WILL HAVE TO REMOVE it or the driver won't work.  At least it
  190. didn't for me until I removed the BIOS.  Save it somewhere for
  191. a time you decided to sell the board or <ugh, shudder!> go
  192. back to MSDOS!
  193. X
  194. X    There are 2 methods you can use to install the driver.  You can
  195. X    use my automated install script, or you can do it by hand.  I'll
  196. X    describe how to do it manually in case something went wrong with
  197. X    the script.
  198. X
  199. Using install script
  200. X
  201. X    To use the install script, go to some directory where you have
  202. X    enough room to unpack the driver package.  I recommend /tmp or
  203. X    /usr/tmp.  Make a directory there call scsi.  Unpack the package
  204. X    in there.  Then execute install by: sh install.  That should
  205. X    do most of the work for you.  Go to the next section, running
  206. X    kconfig when it tells you to.
  207. X
  208. Manual installation
  209. X
  210. X    Go to the /etc/conf/pack.d directory, create a scsi directory
  211. X    there and unpack the files in it.
  212. X
  213. X    Change dir (cd) into /etc/conf/pack.d/scsi
  214. X
  215. X    You will now need to copy some of the files into the correct
  216. X    directories.  The files and their directories are:
  217. X
  218. X    node.d        ---------------->       /etc/conf/node.d/scsi
  219. X    sdevice.d     ---------------->       /etc/conf/sdevice.d/scsi
  220. X
  221. X    Example:  cp node.d /etc/conf/node.d/scsi
  222. X        cp sdevice.d /etc/conf/sdevice.d/scsi
  223. X
  224. X    You will need to either edit /etc/conf/cf.d/mdevice to add the
  225. X    lines in mdevice or you can do the following:
  226. X
  227. X    cat mdevice >> /etc/conf/cf.d/mdevice
  228. X
  229. X    If you have the SDS, then you can recompile the source files.
  230. X    Everything is setup in the makefile for that, so you just need
  231. X    to type make.
  232. X
  233. X    If you don't have the SDS, then you can use the included
  234. X    pre-compiled object (Driver.o).  I am currently using this in
  235. X    my own system, so I know it works.
  236. X
  237. X    A WARNING:  DO NOT USE gcc as it uses a few routines in gcc-lib
  238. X    that the regular kernel libraries do not have.  The resulting
  239. X    kernel will be unusable!
  240. X
  241. Running kconfig
  242. X
  243. X    After all the config files have been setup and the driver
  244. X    compiled, you will need to run kconfig to relink the kernel.
  245. X
  246. X    /etc/kconfig
  247. X
  248. X    After asking you about Root Directory (just press Enter here), it
  249. X    will give you a menu of 3 choices:
  250. X
  251. X    MAIN MENU
  252. X
  253. X    1) CONFIGURE KERNEL
  254. X    2) BUILD A KERNEL
  255. X    3) INSTALL A KERNEL
  256. X
  257. X    Enter Choice [1-3,q]:
  258. X
  259. X    Chose choice 2 to build a kernel.  That's it.  kconfig will build
  260. X    the kernel, then after about 10-15 minutes (depending on how fast
  261. X    your system is), it will ask if you want to install the kernel.
  262. X    At this time, if you are ready to install, then type yes.
  263. X
  264. WARNING: installing a new kernel mean that you will have to reboot so
  265. make sure no one else is on the system and that you don't have anything
  266. important running!
  267. X
  268. X    When the system rebooted, the new kernel will be install and you
  269. X    should see the driver copyright message at boot up.  If you have
  270. X    a SCSI disk connected to the controller, then the driver will
  271. X    also print its geometry information (manufacturer id, size).
  272. X
  273. X    Unless you had already somehow formatted and partitioned the
  274. X    disk before hand, you will now need to do just that.  Run the
  275. X    program scsipart to low level format the disk and partition
  276. X    it.
  277. X
  278. X    Interleave:  I am currently using 3:1 interleave and block size
  279. X    of 512 bytes, that seems to be the best for my configuration
  280. X    (386/20 Mhz interleaved memory).  For those of you lucky enough
  281. X    to have faster systems, you can problably use 1:1 interleave.
  282. X    Just remember that you will need to experiment a little bit
  283. X    to find the best combination for your applications requirements.
  284. X
  285. SUMMARY
  286. -------
  287. X
  288. X    I will enhance and fix bugs for the package as time permits.
  289. X    Please send me any fixes and enhancements you've made so that
  290. X    I can incorporate it in for the next release.  I'd like to
  291. X    keep the changes coordinated so that it is easier on everyone
  292. X    in tracking software versions (and system problems).
  293. X
  294. X    Comments, fixes/bug reports, fan mails to:
  295. X
  296. X    tin@szebra.uucp or uunet!claris!szebra!tin
  297. X
  298. -- Tin Le
  299. X
  300. SHAR_EOF
  301. chmod 0644 README.2 ||
  302. echo 'restore of README.2 failed'
  303. Wc_c="`wc -c < 'README.2'`"
  304. test 7169 -eq "$Wc_c" ||
  305.     echo 'README.2: original size 7169, current size' "$Wc_c"
  306. rm -f _shar_wnt_.tmp
  307. fi
  308. # ============= config ==============
  309. if test -f 'config' -a X"$1" != X"-c"; then
  310.     echo 'x - skipping config (File already exists)'
  311.     rm -f _shar_wnt_.tmp
  312. else
  313. > _shar_wnt_.tmp
  314. echo 'x - extracting config (Text)'
  315. sed 's/^X//' << 'SHAR_EOF' > 'config' &&
  316. *
  317. * config file for scsi driver on Microport System V/386
  318. * Copyright (c) 9.6.1988 Tatu Yl|nen
  319. *               All rights reserved.
  320. *
  321. X
  322. character(9)
  323. block(9)
  324. X
  325. prefix = scsi
  326. X
  327. intvec = 5
  328. X
  329. intpri = SPL5
  330. X
  331. functions = init, open, close, read, write, ioctl, strategy
  332. SHAR_EOF
  333. chmod 0644 config ||
  334. echo 'restore of config failed'
  335. Wc_c="`wc -c < 'config'`"
  336. test 260 -eq "$Wc_c" ||
  337.     echo 'config: original size 260, current size' "$Wc_c"
  338. rm -f _shar_wnt_.tmp
  339. fi
  340. # ============= install ==============
  341. if test -f 'install' -a X"$1" != X"-c"; then
  342.     echo 'x - skipping install (File already exists)'
  343.     rm -f _shar_wnt_.tmp
  344. else
  345. > _shar_wnt_.tmp
  346. echo 'x - extracting install (Text)'
  347. sed 's/^X//' << 'SHAR_EOF' > 'install' &&
  348. #!/bin/sh
  349. # Install script for ST-0X SCSI driver
  350. #
  351. # 9/16/90 Tin Le
  352. X
  353. if test ! `who am i | cut -f1 -d' '` = "root" ; then
  354. X    echo "You must be root to do this!"
  355. X    exit 1
  356. fi
  357. X
  358. PATH=/bin:/usr/bin:/usr/local/bin
  359. export PATH
  360. X
  361. CONFROOT=/etc/conf
  362. ST02DIR=/etc/conf/pack.d/scsi
  363. X
  364. echo;echo
  365. echo "Checking for /etc/conf directory ..."
  366. if test ! -d /etc/conf ; then
  367. X    echo "You don't have the kernel config package loaded!"
  368. X    echo "Please load it first before installing this driver."
  369. X    exit 1
  370. fi
  371. X
  372. echo "/etc/conf found, checking for /etc/conf/pack.d directory ..."
  373. if test ! -d /etc/conf/pack.d ; then
  374. X    echo "/etc/conf/pack.d directory not found!"
  375. X    echo "Did you loaded the kernel config package correctly?"
  376. X    exit 1
  377. fi
  378. X
  379. echo "/etc/conf/pack.d found, checking for scsi directory ..."
  380. if test ! -d ${ST02DIR} ; then
  381. X    echo "${ST02DIR} does not exist"
  382. X    echo "creating it ..."
  383. X    mkdir /etc/conf/pack.d/scsi
  384. X    echo "moving driver files into it ..."
  385. X    mv * ${ST02DIR}
  386. else
  387. X    echo "${ST02DIR} exist!"
  388. X    echo "will save files there in ${ST02DIR}/OLD directory"
  389. X    mkdir ${ST02DIR}/OLD
  390. X    mv ${ST02DIR}/* ${ST02DIR}/OLD
  391. X    mv * ${ST02DIR}
  392. fi
  393. cd ${ST02DIR}
  394. X
  395. echo "Copying sdevice.d to ${CONFROOT}/sdevice.d"
  396. cp sdevice.d ${CONFROOT}/sdevice.d/scsi
  397. echo "Copying node.d to ${CONFROOT}/node.d"
  398. cp node.d ${CONFROOT}/node.d/scsi
  399. X
  400. echo "Adding mdevice to ${CONFROOT}/cf.d/mdevice"
  401. # Back it up first!
  402. cp ${CONFROOT}/cf.d/mdevice ${CONFROOT}/cf.d/mdevice.org
  403. cat mdevice >> ${CONFROOT}/cf.d/mdevice
  404. X
  405. echo "The package comes with a precompiled Driver.o file."
  406. echo "You will have to use it if your system do not have the Software"
  407. echo "Development Package.  Or you could recompile it."
  408. echo -n "Do you wish to use the included Driver.o file? [yes] "
  409. read ans
  410. case $ans in
  411. y*|Y*)  echo "Using the included Driver.o file" ;;
  412. *) echo "Recompiling the source files" ;
  413. X   touch *.c
  414. X   make ;;
  415. esac
  416. X
  417. echo; echo
  418. echo "All the data and config files have been set up."
  419. echo "You need to run kconfig now to relink the kernel."
  420. X
  421. SHAR_EOF
  422. chmod 0755 install ||
  423. echo 'restore of install failed'
  424. Wc_c="`wc -c < 'install'`"
  425. test 1975 -eq "$Wc_c" ||
  426.     echo 'install: original size 1975, current size' "$Wc_c"
  427. rm -f _shar_wnt_.tmp
  428. fi
  429. # ============= makefile ==============
  430. if test -f 'makefile' -a X"$1" != X"-c"; then
  431.     echo 'x - skipping makefile (File already exists)'
  432.     rm -f _shar_wnt_.tmp
  433. else
  434. > _shar_wnt_.tmp
  435. echo 'x - extracting makefile (Text)'
  436. sed 's/^X//' << 'SHAR_EOF' > 'makefile' &&
  437. #
  438. # makefile for scsi driver
  439. #
  440. # Copyright (c) 8.6.1988 Tatu Yl|nen
  441. # Copyright (c) 16.9.1990 Tin Le
  442. #               All rights reserved.
  443. #
  444. # 8/90 Tin
  445. #    Added scsiasm.o to makefile (using ld -r)
  446. #    Added Driver.o, td, scsipart targets
  447. #
  448. X
  449. CC = cc
  450. #CFLAGS = -O -DASM -fstrength-reduce -fpcc-struct-return -DDEBUG # -DDEBUG0
  451. #CFLAGS = -O -fstrength-reduce -fpcc-struct-return -DDEBUG # -DDEBUG0
  452. CFLAGS = -O -DDEBUG -DASM # -DDEBUG0
  453. X
  454. all: scsi.o scsiasm.o scsipart Driver.o td
  455. X
  456. td: td.c
  457. X    cc td.c -o td -O
  458. X
  459. Driver.o: scsi.o scsiasm.o
  460. X    ld -r scsi.o scsiasm.o
  461. X    mv a.out Driver.o
  462. X
  463. scsiasm.o: scsiasm.s
  464. X
  465. scsi.o: scsi.c scsi.h
  466. X
  467. scsipart: scsipart.c scsi.h
  468. X    cc -o scsipart scsipart.c
  469. X
  470. SHAR_EOF
  471. chmod 0644 makefile ||
  472. echo 'restore of makefile failed'
  473. Wc_c="`wc -c < 'makefile'`"
  474. test 673 -eq "$Wc_c" ||
  475.     echo 'makefile: original size 673, current size' "$Wc_c"
  476. rm -f _shar_wnt_.tmp
  477. fi
  478. # ============= mdevice ==============
  479. if test -f 'mdevice' -a X"$1" != X"-c"; then
  480.     echo 'x - skipping mdevice (File already exists)'
  481.     rm -f _shar_wnt_.tmp
  482. else
  483. > _shar_wnt_.tmp
  484. echo 'x - extracting mdevice (Text)'
  485. sed 's/^X//' << 'SHAR_EOF' > 'mdevice' &&
  486. scsi    Iocrwi    icbHo        scsi    9    60    1    7    -1
  487. SHAR_EOF
  488. chmod 0644 mdevice ||
  489. echo 'restore of mdevice failed'
  490. Wc_c="`wc -c < 'mdevice'`"
  491. test 36 -eq "$Wc_c" ||
  492.     echo 'mdevice: original size 36, current size' "$Wc_c"
  493. rm -f _shar_wnt_.tmp
  494. fi
  495. # ============= node.d ==============
  496. if test -f 'node.d' -a X"$1" != X"-c"; then
  497.     echo 'x - skipping node.d (File already exists)'
  498.     rm -f _shar_wnt_.tmp
  499. else
  500. > _shar_wnt_.tmp
  501. echo 'x - extracting node.d (Text)'
  502. sed 's/^X//' << 'SHAR_EOF' > 'node.d' &&
  503. scsi    rscsi0s    c    15
  504. scsi    rscsi1s    c    15
  505. SHAR_EOF
  506. chmod 0644 node.d ||
  507. echo 'restore of node.d failed'
  508. Wc_c="`wc -c < 'node.d'`"
  509. test 36 -eq "$Wc_c" ||
  510.     echo 'node.d: original size 36, current size' "$Wc_c"
  511. rm -f _shar_wnt_.tmp
  512. fi
  513. # ============= scsi.c ==============
  514. if test -f 'scsi.c' -a X"$1" != X"-c"; then
  515.     echo 'x - skipping scsi.c (File already exists)'
  516.     rm -f _shar_wnt_.tmp
  517. else
  518. > _shar_wnt_.tmp
  519. echo 'x - extracting scsi.c (Text)'
  520. sed 's/^X//' << 'SHAR_EOF' > 'scsi.c' &&
  521. /*
  522. X
  523. 9/16/90 Tin Le
  524. X    - Released to the world version 1.0
  525. X
  526. X    Modified for Interactive 386/ix v2.0.2 with some bug fixes
  527. X    and minor enhancements.
  528. X    Will work with ST-02.
  529. X
  530. SCSI disk driver for unix system V (Microport system V/386)
  531. This driver uses the ST-01 controller.  This supports multiple initiators
  532. and multiple targets.
  533. X
  534. Copyright (c) 9.6.1988 Tatu Yl|nen
  535. Copyright (c) 16.9.1988 Tin Le
  536. X              All rights reserved.
  537. X
  538. */
  539. X
  540. #include <fcntl.h>
  541. X
  542. #include <sys/sysmacros.h>
  543. #include <sys/types.h>
  544. #include <sys/param.h>
  545. #include <sys/signal.h>
  546. #include <sys/errno.h>
  547. #include <sys/dir.h>
  548. #include <sys/file.h>
  549. #include <sys/user.h>
  550. #include <sys/buf.h>
  551. #include <sys/iobuf.h>
  552. #include <sys/immu.h>
  553. #include <sys/region.h>
  554. #include <sys/proc.h>
  555. #include "scsi.h"
  556. X
  557. #define COPYRIGHT "SCSI disk driver V1.1  Copyright (c) 9.6.1988 Tatu Yl|nen\n\tCopyright (c) 8.8.1990 Tin Le"
  558. X
  559. /* #define ASM */    /* use certain routines coded in assembly */
  560. X
  561. #define TICKSPERSECOND HZ /* system timer ticks per second */
  562. #define RWTIMEOUT       5 /* timeout for read/write waiting for reconnect */
  563. #define MYSLEEPPRI      (PZERO+1) /* sleeping priority (allow signals) */
  564. #define PAGESIZE     4096 /* page size in sptalloc */
  565. X
  566. #define UNITNO(minornum) ((minornum)>>4) /* minor device to unit */
  567. #define PARTNO(minornum) ((minornum)&15) /* minor device to partition */
  568. #define BLTOSEC(unit,bl) ((long)(bl)*NBPSCTR/d[unit].blocksize)
  569. X                                 /* converts block number to sector number */
  570. #define BLPTOSEC(unit,part,bl) (BLTOSEC(unit,bl)+d[unit].parts[part].start)
  571. X                        /* calculates sector number from block and partition */
  572. X
  573. #define splnointrs() spl6() /* disable any interrupts to this driver (clock!)*/
  574. X
  575. #define NULL 0
  576. X
  577. #define SCSIBASE        0x000cb000l /* address of the scsi controller(no rom)*/
  578. #define SCSICONTROLOFS  0x00000a00l /* control/status port offset */
  579. #define SCSIDATAOFS     0x00000c00l /* data port offset */
  580. #define SCSIDATAPORTSZ  1024        /* size of data port */
  581. #define SCSISIZE        4096        /* size of controller memory area */
  582. X
  583. #define MYADDR          0x80        /* my address as bit mask */
  584. X
  585. #define CMDENABLE       0x80        /* scsi enable */
  586. #define CMDENINTR       0x40        /* enable scsi interrupts */
  587. #define CMDPARENB       0x20        /* enable scsi parity generation */
  588. #define CMDSTARB        0x10        /* start arbitration bit */
  589. #define CMDATTN         0x08        /* scsi attention */
  590. #define CMDBSY          0x04        /* scsi busy */
  591. #define CMDSEL          0x02        /* scsi select */
  592. #define CMDRST          0x01        /* scsi reset */
  593. X
  594. #define STARBCOMPL      0x80        /* arbitration complete bit */
  595. #define STPARERR        0x40        /* parity error bit */
  596. #define STSEL           0x20        /* scsi select */
  597. #define STREQ           0x10        /* scsi req */
  598. #define STCD            0x08        /* scsi c/d */
  599. #define STIO            0x04        /* scsi i/o */
  600. #define STMSG           0x02        /* scsi msg */
  601. #define STBSY           0x01        /* scsi busy */
  602. X
  603. #define CMDBASE         (CMDPARENB|CMDENINTR) /* cmd when doing nothing */
  604. X
  605. #define SCSIREAD        0x28        /* read command code (10-byte) */
  606. #define SCSIWRITE       0x2a        /* write command code (10-byte) */
  607. #define SCSIINQUIRY     0x12        /* inquiry command (6-byte) */
  608. #define SCSIREADCAPACITY 0x25       /* read drive capacity and block size */
  609. #define SCSIMODESELECT  0x15        /* select format parameters */
  610. #define SCSIFORMATUNIT  0x04        /* hard format the scsi drive */
  611. #define SCSIREQSENSE    0x03        /* request sense command */
  612. #define SCSITESTREADY   0x00        /* test unit ready command */
  613. X
  614. #define MSGMYIDENTIFY   0xc0        /* our identify message to send to target */
  615. X
  616. #define MSGCOMPLETE     0x00        /* command complete */
  617. #define MSGSAVEDATAPTR  0x02        /* save data pointer */
  618. #define MSGRESTOREPTR   0x03        /* restore pointer */
  619. #define MSGDISCONNECT   0x04        /* disconnect message */
  620. #define MSGIDETECTERR   0x05        /* initiator detected error */
  621. #define MSGABORT        0x06        /* scsi abort message */
  622. #define MSGMSGREJECT    0x07        /* message reject */
  623. #define MSGNOP          0x08        /* no operation message */
  624. #define MSGIDENTIFY     0x80        /* identify message from target */
  625. X
  626. #define COK             0 /* command completed successfully */
  627. #define CNOCONNECT      1 /* no connection could be made to the drive */
  628. #define CBUSBUSY        2 /* the bus is busy and cannot be cleared */
  629. #define CTIMEOUT        3 /* timeout waiting for the drive */
  630. #define CERROR          4 /* an error was returned by the target */
  631. #define CBUSY           5 /* the drive is busy - wait and retry later */
  632. #define CDISCONNECT     6 /* target disconnected; this is not an error */
  633. X
  634. #ifdef DEBUG0
  635. static char *Cresults[] = {
  636. X    "COK", "CNOCONNECT", "CBUSBUSY", "CTIMEOUT",
  637. X    "CERROR", "CBUSY", "CDISCONNECT", "BAD_RESULT_CODE"
  638. };
  639. #endif
  640. X
  641. static unchar *baseaddr=NULL;    /* controller base address */
  642. static unchar *cmdport;        /* controller command port */
  643. unchar *scsidataport;        /* controller data port */
  644. X
  645. static SCSIDRIVE d[SCSIMAXDRIVES]; /* drive information */
  646. X
  647. static struct buf scsibuf; /* used for raw io */
  648. static unchar rawiobuf[SCSIDATAPORTSZ]; /* data copied temporarily here */
  649. X
  650. static char timeouting=0;
  651. static char intrserviced=0;
  652. X
  653. /* marks the unit as not busy and starts any pending io */
  654. static void marknotbusy();
  655. X
  656. /* This generates a hard reset on the scsi bus by asserting the reset line */
  657. X
  658. static void resetscsibus()
  659. {
  660. X  long l;
  661. X  int a;
  662. X
  663. X  printf("scsi: sending hard reset to scsi bus\n");
  664. X  *cmdport=CMDBASE|CMDENABLE|CMDRST;
  665. X  for (l=0;l<10000l;l++); /* keep rst asserted for a while */
  666. X  *cmdport=CMDBASE;
  667. X  for (l=0;l<500000l;l++); /* give some time to recover before returning */
  668. X  for (a=0;a<SCSIMAXDRIVES;a++)
  669. X    d[a].connected=0; /* do this just in case */
  670. }
  671. X
  672. /* This arbitrates for the scsi bus and selects the desired target.  This
  673. X   returns a C* result code.  This will also set the connected flag
  674. X   if appropriate.  If there are possibly recoverable errors, this will
  675. X   retry.  The calling procedure should not retry if this returns
  676. X   failure. */
  677. X
  678. static int arbitrate(unit)
  679. int unit;
  680. {
  681. X  long l;
  682. X  int arbcnt,bsycnt; /* retry counts */
  683. X
  684. X  arbcnt=0;
  685. X  bsycnt=0;
  686. X retryarb:
  687. X  *cmdport=CMDBASE;
  688. X  *scsidataport=MYADDR;
  689. X  *cmdport=(CMDBASE&~CMDENINTR)|CMDSTARB;
  690. X  /* wait for arbitration complete */
  691. X  for (l=0;l<300000l;l++)
  692. X    if (*cmdport & STARBCOMPL)
  693. X      goto gotarb;
  694. X  /* arbitration timeout - someone is keeping the bus reserved. */
  695. X  *cmdport=CMDBASE;
  696. X  if (arbcnt >= 2) /* retry twice, then give up */
  697. X    {
  698. X      printf("scsi: arbitration timeout - someone is sitting on the bus?\n");
  699. X      return CBUSBUSY;
  700. X    }
  701. X  resetscsibus(); /* reset the bus and hope the condition clears */
  702. X  arbcnt++;
  703. X  goto retryarb;
  704. X gotarb:
  705. X  arbcnt=0;
  706. X  *scsidataport|=1<<unit;
  707. X  *cmdport=CMDBASE|CMDENABLE|CMDSEL|CMDATTN;
  708. X  for (l=0;l<100000l;l++)
  709. X    if (*cmdport & STBSY)
  710. X      goto gotbusy;
  711. X  /* timeout waiting for busy */
  712. X  *cmdport=CMDBASE;
  713. X  if (bsycnt >= 2)
  714. X    {
  715. #ifdef DEBUG0
  716. X      printf("scsi arbitrate: returning CNOCONNECT\n");
  717. #endif
  718. X      return CNOCONNECT; /* probably no drive present */
  719. X    }
  720. X  bsycnt++;
  721. X  for (l=0;l<20000l;l++); /* give some time for the drive */
  722. #ifdef DEBUG0
  723. X  printf("scsi: busy timeout on drive %d\n",unit);
  724. #endif
  725. X  goto retryarb;
  726. X gotbusy:
  727. X  d[unit].connected=1;
  728. X  if (!d[unit].nomsgs)
  729. X    {
  730. X      *cmdport=CMDBASE|CMDENABLE|CMDATTN;
  731. X      for (l=0;l<200000l;l++)
  732. X        if ((*cmdport & (STMSG|STCD|STIO|STREQ)) == (STMSG|STCD|0|STREQ))
  733. X          goto gotmsgreq;
  734. X      /* timeout waiting for msg out */
  735. X      printf("scsi: timeout identify msg out - drive %d does not support messages?\n",
  736. X             unit);
  737. X      d[unit].nomsgs=1; /* don't try messages again */
  738. X      *cmdport=CMDBASE|CMDENABLE;
  739. X      return COK;
  740. X     gotmsgreq:
  741. X      *scsidataport=MSGMYIDENTIFY; /* this enables disconnect */
  742. X      /* fall to successful completion */
  743. X    }
  744. #ifdef DEBUG
  745. X  if (!(*cmdport & STBSY))
  746. X    {
  747. X      printf("scsi: after successful arbitrate !STBSY\n");
  748. X      for (l=0;l<10000000l;l++);
  749. X      arbcnt++;
  750. X      goto retryarb;
  751. X    }
  752. #endif /* DEBUG */
  753. X  *cmdport=CMDBASE|CMDENABLE;
  754. X  return COK;
  755. }
  756. X
  757. #ifndef ASM
  758. X
  759. /* This copies data to the scsi data port as fast as possible.  This could
  760. X   even be coded in assembly language for efficiency. */
  761. X
  762. static void sendtoscsi(buf,len)
  763. register unchar *buf;
  764. register int len;
  765. {
  766. X  while (len--)
  767. X    *scsidataport=(*buf++);
  768. }
  769. X
  770. /* This reads data from the scsi data port as fast as possible. */
  771. X
  772. static void getfromscsi(buf,len)
  773. register unchar *buf;
  774. register int len;
  775. {
  776. X  while (len--)
  777. X    *buf++=(*scsidataport);
  778. }
  779. X
  780. #endif /* ASM */
  781. X
  782. /* This implements the scsi data out phase.  There are several operating
  783. X   modes for this.  1) normal as fast as possible io 2) slow io where we
  784. X   check req individually for each character 3) moving data directly from
  785. X   user space. If an error is encountered (such as a protection fault when
  786. X   moving data from user space), this will return 0.  Moving data from
  787. X   user space is only implemented in "fast" mode. */
  788. X
  789. static int dataout(unit)
  790. int unit;
  791. {
  792. X  register int le;
  793. X  long l;
  794. X  register char slow;
  795. X  int    copyin();
  796. X
  797. X  slow=d[unit].xferslow;
  798. X  for (;d[unit].xferlen > 0;d[unit].xferlen-=le,d[unit].xferbuf+=le)
  799. X    {
  800. X      for (l=0;l<100000l;l++)
  801. X        if (*cmdport & STREQ)
  802. X          goto gotreq;
  803. X      /* timeout */
  804. X      break;
  805. X     gotreq:
  806. X      if ((*cmdport & (STMSG|STCD|STIO)) != (0|0|0))
  807. X        break;
  808. X      if (slow)
  809. X        {
  810. X          le=1;
  811. X          *scsidataport=(*d[unit].xferbuf);
  812. X          continue;
  813. X        }
  814. X      le=d[unit].xferlen;
  815. X      if (le > SCSIDATAPORTSZ)
  816. X        le=SCSIDATAPORTSZ;
  817. X      if (le > d[unit].blocksize)
  818. X        le=d[unit].blocksize;
  819. X      if (d[unit].xferphys)
  820. X        {
  821. X      if (le > sizeof(rawiobuf))
  822. X        le=sizeof(rawiobuf);
  823. X          if (copyin(d[unit].xferbuf,rawiobuf,le) == -1)
  824. X            return 0;
  825. X          sendtoscsi(rawiobuf,le);
  826. X        }
  827. X       else
  828. X        sendtoscsi(d[unit].xferbuf,le);
  829. X    }
  830. X  while ((*cmdport & (STMSG|STCD|STIO|STREQ)) == (0|0|0|STREQ))
  831. X    {
  832. X      *scsidataport=0;
  833. X      for (l=0;l<4000l;l++)
  834. X        if (*cmdport & STREQ)
  835. X          break;
  836. X    }
  837. X  return 1;
  838. }
  839. X
  840. /* this implements the scsi data in phase.  This copies data from
  841. X   scsi bus to system memory.  There are three modes of operation:
  842. X   1) "slow" transfer to kernel memory 2) "fast" transfer to kernel
  843. X   memory 3) "fast" transfer to user memory */
  844. X
  845. static int datain(unit)
  846. int unit;
  847. {
  848. X  register int le;
  849. X  long l;
  850. X  register char slow;
  851. X  int    copyout();
  852. X
  853. /*  slow=d[unit].xferslow; */
  854. X  slow=1;
  855. X  d[unit].xferphys=0;
  856. X  for (;d[unit].xferlen > 0;d[unit].xferlen-=le,d[unit].xferbuf+=le)
  857. X    {
  858. X      for (l=0;l<100000l;l++)
  859. X        if (*cmdport & STREQ)
  860. X          goto gotreq;
  861. X      /* timeout */
  862. X      break;
  863. X     gotreq:
  864. X      if ((*cmdport & (STMSG|STCD|STIO)) != (0|0|STIO))
  865. X        break;
  866. X      if (slow)
  867. X        {
  868. X          le=1;
  869. X          *d[unit].xferbuf=(*scsidataport);
  870. X          continue;
  871. X        }
  872. X      le=d[unit].xferlen;
  873. X      if (le > SCSIDATAPORTSZ)
  874. X        le=SCSIDATAPORTSZ;
  875. X      if (le > d[unit].blocksize)
  876. X        le=d[unit].blocksize;
  877. X      if (d[unit].xferphys)
  878. X        { /* directly to user space */
  879. X      if (le > sizeof(rawiobuf))
  880. X        le=sizeof(rawiobuf);
  881. X          getfromscsi(rawiobuf,le);
  882. X          if (copyout(rawiobuf,d[unit].xferbuf,le) == -1)
  883. X            return 0;
  884. X        }
  885. X       else
  886. X        getfromscsi(d[unit].xferbuf,le);
  887. X    }
  888. X  while ((*cmdport & (STMSG|STCD|STIO|STREQ)) == (0|0|STIO|STREQ))
  889. X    {
  890. X      le=(*scsidataport);
  891. X      for (l=0;l<4000l;l++)
  892. X        if (*cmdport & STREQ)
  893. X          break;
  894. X    }
  895. X  return 1;
  896. }
  897. X
  898. /* This is called when we are connected to the target on the scsi bus.
  899. X   This will do any exchange of data with the target.  The dialog is
  900. X   controlled by the target.  This will remain connected until the
  901. X   target sends a disconnect message, the command is complete, or a timeout
  902. X   is encountered. There should be no interrupts while this is executing,
  903. X   as the unit should be connected all the time.  This returns a C* completion
  904. X   status. Normally, this should return quite fast.  This will never sleep
  905. X   and will also be called at interrupt time.  With dumb drives not supporting
  906. X   disconnect (are there any?) this would block the system for the duration
  907. X   of this call.  This will only mark the drive not busy if the command
  908. X   completed successfully.  If an error is returned, the drive has not
  909. X   been marked not busy. */
  910. X
  911. static int doxfernosleep(unit)
  912. int unit;
  913. {
  914. X  register int a;
  915. X  long l;
  916. X
  917. X  for (l=0; l<1000000l || d[unit].xfertimeout == 0; l++)
  918. X    {
  919. X      if (!(*cmdport & STBSY))
  920. X        {
  921. #ifdef DEBUG
  922. X          printf("scsi doxfernosleep: !STBSY unit %d\n",unit);
  923. #endif
  924. X          d[unit].connected=0;
  925. X          return CERROR; /* we are no longer connected??? */
  926. X        }
  927. X      if (!(*cmdport & STREQ))
  928. X        continue; /* loop until target requesting something */
  929. #ifdef DEBUG1
  930. X      printf("scsi doxfernosleep: new state=%x\n",*cmdport);
  931. #endif
  932. X      switch ((*cmdport & (STMSG|STCD|STIO)) & 0xff)
  933. X        {
  934. X          case 0|0|0: /* data out */
  935. X            if (!dataout(unit))
  936. X              {
  937. #ifdef DEBUG
  938. X                printf("scsi: dataout returned error; unit=%d\n",unit);
  939. #endif
  940. X                return CERROR;
  941. X              }
  942. X            break;
  943. X          case 0|0|STIO: /* data in */
  944. X            if (!datain(unit))
  945. X              {
  946. #ifdef DEBUG
  947. X                printf("scsi: datain returned error; unit=%d\n",unit);
  948. #endif
  949. X                return CERROR;
  950. X              }
  951. X            break;
  952. X          case 0|STCD|0: /* command out */
  953. X            *scsidataport=(*d[unit].xfercmd++);
  954. X            break;
  955. X          case 0|STCD|STIO: /* status in */
  956. X            d[unit].xferstatus=(*scsidataport);
  957. X            break;
  958. X          case STMSG|STCD|0: /* msg out */
  959. X            /* we should never get here.  We don't want to send a message.
  960. X               Lets just drop attention and hope the drive understands. */
  961. #ifdef DEBUG0
  962. X            printf("scsi: unexpected msg out state; status=%x\n",*cmdport);
  963. #endif
  964. X            *scsidataport=MSGNOP; /* send a no-operation message */
  965. X            *cmdport=CMDBASE|CMDENABLE;
  966. X            break;
  967. X          case STMSG|STCD|STIO: /* msg in */
  968. X            a=(*scsidataport) & 0xff;
  969. X            switch (a)
  970. X              {
  971. X                case MSGCOMPLETE:
  972. X                  d[unit].connected=0;
  973. X                  *cmdport=CMDBASE;
  974. #ifdef DEBUG0
  975. X                  printf("scsi: COMMAND complete message received\n");
  976. #endif
  977. X                  if (d[unit].xferstatus == 0) /* completed succesfully */
  978. X                    {
  979. X                      marknotbusy(unit,COK);
  980. X                      return COK;
  981. X                    }
  982. X                  return CERROR;
  983. X                case MSGSAVEDATAPTR:
  984. X                  d[unit].savedbuf=d[unit].xferbuf;
  985. X                  d[unit].savedlen=d[unit].xferlen;
  986. X                  break;
  987. X                case MSGRESTOREPTR:
  988. X                  d[unit].xferbuf=d[unit].savedbuf;
  989. X                  d[unit].xferlen=d[unit].savedlen;
  990. X                  d[unit].xfercmd=d[unit].savedcmd;
  991. X                  break;
  992. X                case MSGDISCONNECT:
  993. X                  d[unit].connected=0;
  994. X                  d[unit].xfertime=1;
  995. X                  *cmdport=CMDBASE;
  996. #ifdef DEBUG0
  997. X                  printf("scsi: disconnected\n");
  998. #endif
  999. X                  return CDISCONNECT;
  1000. X                case MSGMSGREJECT:
  1001. X                  break; /* the target rejected some message... Who cares. */
  1002. X                case MSGNOP:
  1003. X                  break; /* this should not be sent by the target, but... */
  1004. X                case MSGIDENTIFY:
  1005. X                  break; /* we don't care about targets identify messages */
  1006. X                default:
  1007. X                  if (a & 0x80)
  1008. X                    break; /* assume it is an identify message */
  1009. X                  printf("scsi: unknown message received from drive %d: %x\n",
  1010. X                         unit,a);
  1011. X                  break;
  1012. X              }
  1013. X            break;
  1014. X          default:
  1015. X            /* unexpected stack state.  Now I don't know what to do.  Lets
  1016. X               hope the drive changes to another state. */
  1017. #ifdef DEBUG
  1018. X            printf("scsi: unexpected bus state: status=%x\n",*cmdport);
  1019. #endif
  1020. X            break;
  1021. X        }
  1022. X    }
  1023. X  return CTIMEOUT;
  1024. }
  1025. X
  1026. /* This implements polled wait for reconnect.  This is mainly used at
  1027. X   system initialization time when the interrupt system may not be fully
  1028. X   initialized.  This returns true if reconnect was encountered.
  1029. X   If there is no successful reconnect, this will time out after a few
  1030. X   seconds and return false. */
  1031. X
  1032. static int polledwaitreconnect(unit)
  1033. int unit;
  1034. {
  1035. X  long l;
  1036. X  unsigned char ch;
  1037. X
  1038. X  *cmdport=CMDBASE&~CMDENINTR;
  1039. X  for (l=0;l<4000000l;l++)
  1040. X    {
  1041. X      if ((*cmdport & (STSEL|STIO|STBSY)) != (STSEL|STIO|0))
  1042. X        continue;
  1043. X      ch=(*scsidataport);
  1044. X      if (!(ch & MYADDR))
  1045. X        {
  1046. #ifdef DEBUG
  1047. X          printf("scsi: polled reselection was not for me: %x\n",ch);
  1048. #endif
  1049. X          continue;
  1050. X        }
  1051. X      ch&=~MYADDR;
  1052. X      if (!(ch & (1 << unit)))
  1053. X        {
  1054. #ifdef DEBUG
  1055. X          printf("scsi: reselecting (polled) unit other than expected: %x\n",
  1056. X                 ch);
  1057. #endif
  1058. X          continue;
  1059. X        }
  1060. X      *cmdport=(CMDBASE&~CMDENINTR)|CMDBSY|CMDENABLE;
  1061. X      for (l=0;l<200000l;l++)
  1062. X        if (!(*cmdport & STSEL))
  1063. X          break;
  1064. X      for (l=0;l<200000l;l++)
  1065. X    if (!(*cmdport & STBSY))
  1066. X      break;
  1067. X      *cmdport=CMDBASE|CMDENABLE;
  1068. X      d[unit].connected=1;
  1069. X      return 1;
  1070. X    }
  1071. X  *cmdport=CMDBASE;
  1072. #ifdef DEBUG
  1073. X  printf("scsi: timeout polled wait for reselection from %d\n",unit);
  1074. #endif
  1075. X  return 0;
  1076. }
  1077. X
  1078. /* This starts the scsi command.  Interrupts may be enabled when this is
  1079. X   called.  When this retuns, either the drive must have been marked not
  1080. X   busy (error or completion), or the target has disconnected and the drive
  1081. X   will be marked not busy when an interrupt or timeout comes.  A failure
  1082. X   to mark the drive not busy will block the drive from all future
  1083. X   requests.  If retries are made for a command, this will be called to
  1084. X   start the retry. */
  1085. X
  1086. static int startscsi(unit)
  1087. int unit;
  1088. {
  1089. X  int a;
  1090. X
  1091. X  d[unit].xferbuf=d[unit].savedbuf=d[unit].origbuf;
  1092. X  d[unit].xferlen=d[unit].savedlen=d[unit].origlen;
  1093. X  d[unit].xfercmd=d[unit].savedcmd=d[unit].origcmd;
  1094. X
  1095. X startagain:
  1096. X
  1097. #ifdef DEBUG0
  1098. X  printf("scsi: arbitrating for %d\n",unit);
  1099. #endif
  1100. X  a=arbitrate(unit);
  1101. X  if (a != COK) /* arbitrate does the necessary retries */
  1102. X    return a;
  1103. X
  1104. #ifdef DEBUG0
  1105. X  printf("scsi: arbitration complete\n");
  1106. #endif
  1107. X  while (1)
  1108. X    {
  1109. X      a=doxfernosleep(unit);
  1110. #ifdef DEBUG0
  1111. X      printf("scsi: doxfernosleep returned %d=%s\n",
  1112. X    a, Cresults[(a>=0 && a<7 ? a : 7)]);
  1113. #endif
  1114. X      if (a == CDISCONNECT)
  1115. X        { /* The target disconnected */
  1116. X          if (d[unit].xferpolled)
  1117. X            {
  1118. #ifdef DEBUG0
  1119. X              printf("scsi: polled wait\n");
  1120. #endif
  1121. X              if (!polledwaitreconnect(unit))
  1122. X                goto retry;
  1123. #ifdef DEBUG0
  1124. X              printf("scsi: polled wait complete - reconnected\n");
  1125. #endif
  1126. X              continue;
  1127. X            }
  1128. X          if (d[unit].currentbuf)
  1129. X            { /* We are doing io for a buffer */
  1130. X              /* All we have to do is to return; intr will call iodone. */
  1131. X              d[unit].xfertime=1; /* enable timeouts */
  1132. X              return CDISCONNECT;
  1133. X            }
  1134. X
  1135. X          /* disconnect; we do not have a buffer but may use intrs */
  1136. X          /* This is not too efficient, as the delay from wakeup to
  1137. X             continuing execution might be substantial, but this is not
  1138. X             a typical case, as transfers do not normally go to
  1139. X             internal buffers. */
  1140. X          d[unit].xfertime=1; /* enable timeouts */
  1141. X          if (sleep(&d[unit].connected,MYSLEEPPRI|PCATCH) == 1)
  1142. X            { /* caught a signal */
  1143. X              d[unit].busy=0; /* I guess this is an atomic operation */
  1144. X              return CERROR;
  1145. X            }
  1146. X          if (!d[unit].connected)
  1147. X            goto retry; /* it must have been a timeout */
  1148. X          continue;
  1149. X        }
  1150. X      if (a == COK || a == CNOCONNECT || a == CBUSBUSY)
  1151. X        {
  1152. X          if (a != COK)
  1153. X            marknotbusy(unit,a);
  1154. X          return a;
  1155. X        }
  1156. X      goto retry;
  1157. X    }
  1158. X retry:
  1159. X  /* a possibly recoverable error was encountered */
  1160. #ifdef DEBUG
  1161. X  printf("scsi: startscsi: retrying or failing\n");
  1162. #endif
  1163. X  if (d[unit].xferretries > 1)
  1164. X    {
  1165. X      d[unit].xferretries--;
  1166. X      goto startagain;
  1167. X    }
  1168. X  if (a == CTIMEOUT || a == CBUSBUSY)
  1169. X    resetscsibus(); /* in case the drive was hanging on the bus */
  1170. X  d[unit].connected=0;
  1171. X  *cmdport=CMDBASE;
  1172. X  marknotbusy(unit,a);
  1173. X  return a; /* too many retries - return error */
  1174. }
  1175. X
  1176. /* This executes the given command on the unit.  This returns command status
  1177. X   (C* constants).  There is no need to retry the operation after calling
  1178. X   this. */
  1179. X
  1180. static int doscsicmd(unit,cmd,buf,len,timeout,retries,slow,phys,polled,bp)
  1181. int unit,    /* drive number */
  1182. X    len,     /* buffer size */
  1183. X    timeout, /* timeout in 1/10 secs if != 0 */
  1184. X    retries, /* number of tries before returning failure; 1=try only once */
  1185. X    slow,    /* set to true if slow transfer (only true for read & write) */
  1186. X    phys,    /* set to true if xfer directly to/from user space (raw io) */
  1187. X    polled;  /* set to true if polled transfer */
  1188. unchar *cmd,   /* command to execute */
  1189. X     *buf;   /* transfer buffer address */
  1190. struct buf *bp; /* io buffer being executed, or NULL */
  1191. {
  1192. X  int x;
  1193. X
  1194. #ifdef DEBUG0
  1195. X  printf("scsi: cmd unit=%d buf=%x len=%d timeout=%d retries=%d slow=%d phys=%d polled=%d bp=%x\n",
  1196. X         unit,buf,len,timeout,retries,slow,phys,polled,bp);
  1197. #endif
  1198. X
  1199. X  x=splnointrs();
  1200. X  if (d[unit].busy)
  1201. X    {
  1202. X      if (bp)
  1203. X        {
  1204. X          splx(x);
  1205. X          return CBUSY;
  1206. X        }
  1207. X      while (d[unit].busy)
  1208. X        {
  1209. X          splx(x);
  1210. X          if (sleep(&d[unit].busy,MYSLEEPPRI) == 1)
  1211. X            { /* caught a signal */
  1212. X              return CERROR;
  1213. X            }
  1214. X          x=splnointrs();
  1215. X        }
  1216. X    }
  1217. X  d[unit].origbuf=buf;
  1218. X  d[unit].origlen=len;
  1219. X  d[unit].origcmd=cmd;
  1220. X  d[unit].xferslow=slow;
  1221. X  d[unit].xferstatus=0x01; /* indicates error */
  1222. X  d[unit].xfertimeout=timeout?timeout+1:0;
  1223. X  d[unit].xfertime=0;
  1224. X  d[unit].xferretries=retries;
  1225. X  d[unit].xferphys=phys;
  1226. X  d[unit].xferpolled=polled;
  1227. X  d[unit].currentbuf=bp;
  1228. X  d[unit].busy=1;
  1229. X  splx(x);
  1230. X
  1231. X  return startscsi(unit);
  1232. }
  1233. X
  1234. static int dorw(unit,sec,buf,len,flags,polled,bp)
  1235. int unit;
  1236. long sec;
  1237. unchar *buf;
  1238. int len,flags,polled;
  1239. struct buf *bp;
  1240. {
  1241. X  unchar cmd[10];
  1242. X  int nblocks,a;
  1243. X
  1244. X  a=d[unit].blocksize;
  1245. X  if (a == 0)
  1246. X    a=512;
  1247. X  nblocks=(len+a-1)/a;
  1248. X
  1249. #ifdef DEBUG0
  1250. X  printf("scsi: dorw: unit=%d sec=%d buf=%x len=%d flags=%x polled=%d bp=%x\n",
  1251. X         unit,sec,buf,len,flags,polled,bp);
  1252. #endif
  1253. X
  1254. X  cmd[0]=(flags & B_READ)?SCSIREAD:SCSIWRITE;
  1255. X  cmd[1]=0x00; /* LU & RADDR */
  1256. X  cmd[2]=sec >> 24;
  1257. X  cmd[3]=sec >> 16;
  1258. X  cmd[4]=sec >> 8;
  1259. X  cmd[5]=sec;
  1260. X  cmd[6]=0;
  1261. X  cmd[7]=nblocks >> 8;
  1262. X  cmd[8]=nblocks;
  1263. X  cmd[9]=0;
  1264. X
  1265. X  return doscsicmd(unit,cmd,buf,len,RWTIMEOUT,3,0,flags & B_PHYS,polled,bp);
  1266. }
  1267. X
  1268. /* This starts an io operation on the given buffer.  This is called when
  1269. X   a new buffer is added to the io queue, and when a previous operation has
  1270. X   completed, to start io on the next buffer.  If the unit is busy, this will
  1271. X   do nothing.  If it is not busy, this will start the request.  This should
  1272. X   be called with splnointrs.  Any routines called by this will not change
  1273. X   the interrupt level to a lower value. */
  1274. SHAR_EOF
  1275. true || echo 'restore of scsi.c failed'
  1276. fi
  1277. echo 'End of  part 2'
  1278. echo 'File scsi.c is continued in part 3'
  1279. echo 3 > _shar_seq_.tmp
  1280. exit 0
  1281. -- 
  1282. +-----------------------------------------------------------------
  1283.  Station Zebra     ....!{claris,zorch}!szebra!tin
  1284.  Sunnyvale, CA      (408) 739-1520  24hrs Telebit+ 300-19200bps
  1285.                     Pub *NIX, Usenet and mail (no fee)
  1286.