akaros/kern/drivers/dev/sdscsi.c
<<
>>
Prefs
   1/*
   2 * This file is part of the UCB release of Plan 9. It is subject to the license
   3 * terms in the LICENSE file found in the top-level directory of this
   4 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
   5 * part of the UCB release of Plan 9, including this file, may be copied,
   6 * modified, propagated, or distributed except according to the terms contained
   7 * in the LICENSE file.
   8 */
   9
  10#include <assert.h>
  11#include <cpio.h>
  12#include <error.h>
  13#include <kmalloc.h>
  14#include <kref.h>
  15#include <net/ip.h>
  16#include <pmap.h>
  17#include <sd.h>
  18#include <slab.h>
  19#include <smp.h>
  20#include <stdio.h>
  21#include <string.h>
  22
  23static int scsitest(struct sdreq *r)
  24{
  25        r->write = 0;
  26        memset(r->cmd, 0, sizeof(r->cmd));
  27        r->cmd[1] = r->lun << 5;
  28        r->clen = 6;
  29        r->data = NULL;
  30        r->dlen = 0;
  31        r->flags = 0;
  32
  33        r->status = ~0;
  34
  35        return r->unit->dev->ifc->rio(r);
  36}
  37
  38int scsiverify(struct sdunit *unit)
  39{
  40        struct sdreq *r;
  41        int i, status;
  42        uint8_t *inquiry;
  43
  44        r = kzmalloc(sizeof(struct sdreq), 0);
  45        if (r == NULL)
  46                return 0;
  47        inquiry = kzmalloc(sizeof(unit->inquiry), MEM_WAIT);
  48        if (inquiry == NULL) {
  49                kfree(r);
  50                return 0;
  51        }
  52        r->unit = unit;
  53        r->lun = 0; /* ??? */
  54
  55        memset(unit->inquiry, 0, sizeof(unit->inquiry));
  56        r->write = 0;
  57        r->cmd[0] = 0x12;
  58        r->cmd[1] = r->lun << 5;
  59        r->cmd[4] = sizeof(unit->inquiry) - 1;
  60        r->clen = 6;
  61        r->data = inquiry;
  62        r->dlen = sizeof(unit->inquiry) - 1;
  63        r->flags = 0;
  64
  65        r->status = ~0;
  66        if (unit->dev->ifc->rio(r) != SDok) {
  67                kfree(r);
  68                return 0;
  69        }
  70        memmove(unit->inquiry, inquiry, r->dlen);
  71        kfree(inquiry);
  72
  73        for (i = 0; i < 3; i++) {
  74                while ((status = scsitest(r)) == SDbusy)
  75                        ;
  76                if (status == SDok || status != SDcheck)
  77                        break;
  78                if (!(r->flags & SDvalidsense))
  79                        break;
  80                if ((r->sense[2] & 0x0F) != 0x02)
  81                        continue;
  82
  83                /*
  84                 * Unit is 'not ready'.
  85                 * If it is in the process of becoming ready or needs
  86                 * an initialising command, set status so it will be spun-up
  87                 * below.
  88                 * If there's no medium, that's OK too, but don't
  89                 * try to spin it up.
  90                 */
  91                if (r->sense[12] == 0x04) {
  92                        if (r->sense[13] == 0x02 || r->sense[13] == 0x01) {
  93                                status = SDok;
  94                                break;
  95                        }
  96                }
  97                if (r->sense[12] == 0x3A)
  98                        break;
  99        }
 100
 101        if (status == SDok) {
 102                /*
 103                 * Try to ensure a direct-access device is spinning.
 104                 * Don't wait for completion, ignore the result.
 105                 */
 106                if ((unit->inquiry[0] & SDinq0periphtype) == SDperdisk) {
 107                        memset(r->cmd, 0, sizeof(r->cmd));
 108                        r->write = 0;
 109                        r->cmd[0] = 0x1B;
 110                        r->cmd[1] = (r->lun << 5) | 0x01;
 111                        r->cmd[4] = 1;
 112                        r->clen = 6;
 113                        r->data = NULL;
 114                        r->dlen = 0;
 115                        r->flags = 0;
 116
 117                        r->status = ~0;
 118                        unit->dev->ifc->rio(r);
 119                }
 120        }
 121        kfree(r);
 122
 123        if (status == SDok || status == SDcheck)
 124                return 1;
 125        return 0;
 126}
 127
 128static int scsirio(struct sdreq *r)
 129{
 130        ERRSTACK(1);
 131        /*
 132         * Perform an I/O request, returning
 133         *      -1      failure
 134         *       0      ok
 135         *       1      no medium present
 136         *       2      retry
 137         * The contents of r may be altered so the
 138         * caller should re-initialise if necesary.
 139         */
 140        r->status = ~0;
 141        switch (r->unit->dev->ifc->rio(r)) {
 142        default:
 143                break;
 144        case SDcheck:
 145                if (!(r->flags & SDvalidsense))
 146                        break;
 147                switch (r->sense[2] & 0x0F) {
 148                case 0x00: /* no sense */
 149                case 0x01: /* recovered error */
 150                        return 2;
 151                case 0x06: /* check condition */
 152                        /*
 153                         * 0x28 - not ready to ready transition,
 154                         *        medium may have changed.
 155                         * 0x29 - power on or some type of reset.
 156                         */
 157                        if (r->sense[12] == 0x28 && r->sense[13] == 0)
 158                                return 2;
 159                        if (r->sense[12] == 0x29)
 160                                return 2;
 161                        break;
 162                case 0x02: /* not ready */
 163                        /*
 164                         * If no medium present, bail out.
 165                         * If unit is becoming ready, rather than not
 166                         * not ready, wait a little then poke it again.
 167                         */
 168                        if (r->sense[12] == 0x3A)
 169                                break;
 170                        if (r->sense[12] != 0x04 || r->sense[13] != 0x01)
 171                                break;
 172
 173                        while (waserror())
 174                                ;
 175                        kthread_usleep(500 * 1000);
 176                        poperror();
 177                        scsitest(r);
 178                        return 2;
 179                default:
 180                        break;
 181                }
 182                break;
 183        case SDok:
 184                return 0;
 185        }
 186        return -1;
 187}
 188
 189int scsionline(struct sdunit *unit)
 190{
 191        struct sdreq *r;
 192        uint8_t *p;
 193        int ok, retries;
 194
 195        r = kzmalloc(sizeof(struct sdreq), 0);
 196        if (r == NULL)
 197                return 0;
 198        p = kzmalloc(8, 0);
 199        if (p == NULL) {
 200                kfree(r);
 201                return 0;
 202        }
 203
 204        ok = 0;
 205
 206        r->unit = unit;
 207        r->lun = 0; /* ??? */
 208        for (retries = 0; retries < 10; retries++) {
 209                /*
 210                 * Read-capacity is mandatory for DA, WORM, CD-ROM and
 211                 * MO. It may return 'not ready' if type DA is not
 212                 * spun up, type MO or type CD-ROM are not loaded or just
 213                 * plain slow getting their act together after a reset.
 214                 */
 215                r->write = 0;
 216                memset(r->cmd, 0, sizeof(r->cmd));
 217                r->cmd[0] = 0x25;
 218                r->cmd[1] = r->lun << 5;
 219                r->clen = 10;
 220                r->data = p;
 221                r->dlen = 8;
 222                r->flags = 0;
 223
 224                r->status = ~0;
 225                switch (scsirio(r)) {
 226                default:
 227                        break;
 228                case 0:
 229                        unit->sectors =
 230                            (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
 231                        unit->secsize =
 232                            (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
 233
 234                        /*
 235                         * Some ATAPI CD readers lie about the block size.
 236                         * Since we don't read audio via this interface
 237                         * it's okay to always fudge this.
 238                         */
 239                        if (unit->secsize == 2352)
 240                                unit->secsize = 2048;
 241                        /*
 242                         * Devices with removable media may return 0 sectors
 243                         * when they have empty media (e.g. sata dvd writers);
 244                         * if so, keep the count zero.
 245                         *
 246                         * Read-capacity returns the LBA of the last sector,
 247                         * therefore the number of sectors must be incremented.
 248                         */
 249                        if (unit->sectors != 0)
 250                                unit->sectors++;
 251                        ok = 1;
 252                        break;
 253                case 1:
 254                        ok = 1;
 255                        break;
 256                case 2:
 257                        continue;
 258                }
 259                break;
 260        }
 261        kfree(p);
 262        kfree(r);
 263
 264        if (ok)
 265                return ok + retries;
 266        else
 267                return 0;
 268}
 269
 270int scsiexec(struct sdunit *unit, int write, uint8_t *cmd, int clen, void *data,
 271             int *dlen)
 272{
 273        struct sdreq *r;
 274        int status;
 275
 276        r = kzmalloc(sizeof(struct sdreq), 0);
 277        if (r == NULL)
 278                return SDmalloc;
 279        r->unit = unit;
 280        r->lun = cmd[1] >> 5; /* ??? */
 281        r->write = write;
 282        memmove(r->cmd, cmd, clen);
 283        r->clen = clen;
 284        r->data = data;
 285        if (dlen)
 286                r->dlen = *dlen;
 287        r->flags = 0;
 288
 289        r->status = ~0;
 290
 291        /*
 292         * Call the device-specific I/O routine.
 293         * There should be no calls to 'error()' below this
 294         * which percolate back up.
 295         */
 296        switch (status = unit->dev->ifc->rio(r)) {
 297        case SDok:
 298                if (dlen)
 299                        *dlen = r->rlen;
 300        /*FALLTHROUGH*/
 301        case SDcheck:
 302        /*FALLTHROUGH*/
 303        default:
 304                /*
 305                 * It's more complicated than this. There are conditions
 306                 * which are 'ok' but for which the returned status code
 307                 * is not 'SDok'.
 308                 * Also, not all conditions require a reqsense, might
 309                 * need to do a reqsense here and make it available to the
 310                 * caller somehow.
 311                 *
 312                 * Ma\xC3\xB1ana.
 313                 */
 314                break;
 315        }
 316        kfree(r);
 317
 318        return status;
 319}
 320
 321static void scsifmt10(struct sdreq *r, int write, int lun, uint32_t nb,
 322                      uint64_t bno)
 323{
 324        uint8_t *c;
 325
 326        c = r->cmd;
 327        if (write == 0)
 328                c[0] = 0x28;
 329        else
 330                c[0] = 0x2A;
 331        c[1] = lun << 5;
 332        c[2] = bno >> 24;
 333        c[3] = bno >> 16;
 334        c[4] = bno >> 8;
 335        c[5] = bno;
 336        c[6] = 0;
 337        c[7] = nb >> 8;
 338        c[8] = nb;
 339        c[9] = 0;
 340
 341        r->clen = 10;
 342}
 343
 344static void scsifmt16(struct sdreq *r, int write, int lun, uint32_t nb,
 345                      uint64_t bno)
 346{
 347        uint8_t *c;
 348
 349        c = r->cmd;
 350        if (write == 0)
 351                c[0] = 0x88;
 352        else
 353                c[0] = 0x8A;
 354        c[1] = lun << 5; /* so wrong */
 355        c[2] = bno >> 56;
 356        c[3] = bno >> 48;
 357        c[4] = bno >> 40;
 358        c[5] = bno >> 32;
 359        c[6] = bno >> 24;
 360        c[7] = bno >> 16;
 361        c[8] = bno >> 8;
 362        c[9] = bno;
 363        c[10] = nb >> 24;
 364        c[11] = nb >> 16;
 365        c[12] = nb >> 8;
 366        c[13] = nb;
 367        c[14] = 0;
 368        c[15] = 0;
 369
 370        r->clen = 16;
 371}
 372
 373int32_t scsibio(struct sdunit *unit, int lun, int write, void *data, int32_t nb,
 374                uint64_t bno)
 375{
 376        struct sdreq *r;
 377        int32_t rlen;
 378
 379        r = kzmalloc(sizeof(struct sdreq), 0);
 380        if (r == NULL)
 381                error(ENOMEM, "scsibio: can't allocate %d bytes", sizeof(*r));
 382        r->unit = unit;
 383        r->lun = lun;
 384again:
 385        r->write = write;
 386        if (bno >= (1ULL << 32))
 387                scsifmt16(r, write, lun, nb, bno);
 388        else
 389                scsifmt10(r, write, lun, nb, bno);
 390        r->data = data;
 391        r->dlen = nb * unit->secsize;
 392        r->flags = 0;
 393
 394        r->status = ~0;
 395        switch (scsirio(r)) {
 396        default:
 397                rlen = -1;
 398                break;
 399        case 0:
 400                rlen = r->rlen;
 401                break;
 402        case 2:
 403                rlen = -1;
 404                if (!(r->flags & SDvalidsense))
 405                        break;
 406                switch (r->sense[2] & 0x0F) {
 407                default:
 408                        break;
 409                case 0x01: /* recovered error */
 410                        printd("%s: recovered error at sector %llu\n",
 411                               unit->SDperm.name, bno);
 412                        rlen = r->rlen;
 413                        break;
 414                case 0x06: /* check condition */
 415                        /*
 416                         * Check for a removeable media change.
 417                         * If so, mark it by zapping the geometry info
 418                         * to force an online request.
 419                         */
 420                        if (r->sense[12] != 0x28 || r->sense[13] != 0)
 421                                break;
 422                        if (unit->inquiry[1] & SDinq1removable)
 423                                unit->sectors = 0;
 424                        break;
 425                case 0x02: /* not ready */
 426                        /*
 427                         * If unit is becoming ready,
 428                         * rather than not not ready, try again.
 429                         */
 430                        if (r->sense[12] == 0x04 && r->sense[13] == 0x01)
 431                                goto again;
 432                        break;
 433                }
 434                break;
 435        }
 436        kfree(r);
 437
 438        return rlen;
 439}
 440