sdaoe.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*
  2. * aoe sd driver, copyright © 2007 coraid
  3. */
  4. #include "u.h"
  5. #include "../port/lib.h"
  6. #include "mem.h"
  7. #include "dat.h"
  8. #include "fns.h"
  9. #include "../port/error.h"
  10. #include "../port/netif.h"
  11. #include "../port/sd.h"
  12. #include "etherif.h"
  13. #include "aoe.h"
  14. extern char Echange[];
  15. extern char Enotup[];
  16. #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
  17. enum {
  18. Nctlr = 32,
  19. Maxpath = 128,
  20. };
  21. enum {
  22. /* sync with ahci.h */
  23. Dllba = 1<<0,
  24. Dsmart = 1<<1,
  25. Dpower = 1<<2,
  26. Dnop = 1<<3,
  27. Datapi = 1<<4,
  28. Datapi16= 1<<5,
  29. };
  30. static char *flagname[] = {
  31. "llba",
  32. "smart",
  33. "power",
  34. "nop",
  35. "atapi",
  36. "atapi16",
  37. };
  38. typedef struct Ctlr Ctlr;
  39. struct Ctlr{
  40. QLock;
  41. Ctlr *next;
  42. SDunit *unit;
  43. char path[Maxpath];
  44. Chan *c;
  45. ulong vers;
  46. uchar mediachange;
  47. uchar flag;
  48. uchar smart;
  49. uchar smartrs;
  50. uchar feat;
  51. uvlong sectors;
  52. char serial[20+1];
  53. char firmware[8+1];
  54. char model[40+1];
  55. char ident[0x100];
  56. };
  57. void aoeidmove(char *p, uint16_t *a, unsigned n);
  58. static Lock ctlrlock;
  59. static Ctlr *head;
  60. static Ctlr *tail;
  61. SDifc sdaoeifc;
  62. static uint16_t
  63. gbit16(void *a)
  64. {
  65. uint8_t *i;
  66. i = a;
  67. return i[1] << 8 | i[0];
  68. }
  69. static uint32_t
  70. gbit32(void *a)
  71. {
  72. uint32_t j;
  73. uint8_t *i;
  74. i = a;
  75. j = i[3] << 24;
  76. j |= i[2] << 16;
  77. j |= i[1] << 8;
  78. j |= i[0];
  79. return j;
  80. }
  81. static uint64_t
  82. gbit64(void *a)
  83. {
  84. uint8_t *i;
  85. i = a;
  86. return (uint64_t)gbit32(i+4)<<32 | gbit32(i);
  87. }
  88. static int
  89. identify(Ctlr *c, uint16_t *id)
  90. {
  91. int i;
  92. uint8_t oserial[21];
  93. uint64_t osectors, s;
  94. osectors = c->sectors;
  95. memmove(oserial, c->serial, sizeof c->serial);
  96. c->feat &= ~(Dllba|Dpower|Dsmart|Dnop);
  97. i = gbit16(id+83) | gbit16(id+86);
  98. if(i & (1<<10)){
  99. c->feat |= Dllba;
  100. s = gbit64(id+100);
  101. }else
  102. s = gbit32(id+60);
  103. i = gbit16(id+83);
  104. if((i>>14) == 1) {
  105. if(i & (1<<3))
  106. c->feat |= Dpower;
  107. i = gbit16(id+82);
  108. if(i & 1)
  109. c->feat |= Dsmart;
  110. if(i & (1<<14))
  111. c->feat |= Dnop;
  112. }
  113. aoeidmove(c->serial, id+10, 20);
  114. aoeidmove(c->firmware, id+23, 8);
  115. aoeidmove(c->model, id+27, 40);
  116. if((osectors == 0 || osectors != s) &&
  117. memcmp(oserial, c->serial, sizeof oserial) != 0){
  118. c->sectors = s;
  119. c->mediachange = 1;
  120. c->vers++;
  121. }
  122. return 0;
  123. }
  124. /* must call with d qlocked */
  125. static int
  126. aoeidentify(Ctlr *d, SDunit *u)
  127. {
  128. Chan *c;
  129. c = nil;
  130. if(waserror()){
  131. if(c)
  132. cclose(c);
  133. iprint("aoeidentify: %s\n", up->errstr);
  134. nexterror();
  135. }
  136. uprint("%s/ident", d->path);
  137. c = namec(up->genbuf, Aopen, OREAD, 0);
  138. c->dev->read(c, d->ident, sizeof d->ident, 0);
  139. poperror();
  140. cclose(c);
  141. d->feat = 0;
  142. d->smart = 0;
  143. identify(d, (uint16_t*)d->ident);
  144. memset(u->inquiry, 0, sizeof u->inquiry);
  145. u->inquiry[2] = 2;
  146. u->inquiry[3] = 2;
  147. u->inquiry[4] = sizeof u->inquiry - 4;
  148. memmove(u->inquiry+8, d->model, 40);
  149. return 0;
  150. }
  151. static Ctlr*
  152. ctlrlookup(char *path)
  153. {
  154. Ctlr *c;
  155. lock(&ctlrlock);
  156. for(c = head; c; c = c->next)
  157. if(strcmp(c->path, path) == 0)
  158. break;
  159. unlock(&ctlrlock);
  160. return c;
  161. }
  162. static Ctlr*
  163. newctlr(char *path)
  164. {
  165. Ctlr *c;
  166. /* race? */
  167. if(ctlrlookup(path))
  168. error(Eexist);
  169. if((c = malloc(sizeof *c)) == nil)
  170. return 0;
  171. kstrcpy(c->path, path, sizeof c->path);
  172. lock(&ctlrlock);
  173. if(head != nil)
  174. tail->next = c;
  175. else
  176. head = c;
  177. tail = c;
  178. unlock(&ctlrlock);
  179. return c;
  180. }
  181. static void
  182. delctlr(Ctlr *c)
  183. {
  184. Ctlr *x, *prev;
  185. lock(&ctlrlock);
  186. for(prev = 0, x = head; x; prev = x, x = c->next)
  187. if(strcmp(c->path, x->path) == 0)
  188. break;
  189. if(x == 0){
  190. unlock(&ctlrlock);
  191. error(Enonexist);
  192. }
  193. if(prev)
  194. prev->next = x->next;
  195. else
  196. head = x->next;
  197. if(x->next == nil)
  198. tail = prev;
  199. unlock(&ctlrlock);
  200. if(x->c)
  201. cclose(x->c);
  202. free(x);
  203. }
  204. static SDev*
  205. aoeprobe(char *path, SDev *s)
  206. {
  207. int n, i;
  208. char *p;
  209. Chan *c;
  210. Ctlr *ctlr;
  211. if((p = strrchr(path, '/')) == 0)
  212. error(Ebadarg);
  213. *p = 0;
  214. uprint("%s/ctl", path);
  215. *p = '/';
  216. c = namec(up->genbuf, Aopen, OWRITE, 0);
  217. if(waserror()) {
  218. cclose(c);
  219. nexterror();
  220. }
  221. n = uprint("discover %s", p+1);
  222. c->dev->write(c, up->genbuf, n, 0);
  223. poperror();
  224. cclose(c);
  225. for(i = 0;; i += 200){
  226. if(i > 8000 || waserror())
  227. error(Etimedout);
  228. tsleep(&up->sleep, return0, 0, 200);
  229. poperror();
  230. uprint("%s/ident", path);
  231. if(waserror())
  232. continue;
  233. c = namec(up->genbuf, Aopen, OREAD, 0);
  234. poperror();
  235. cclose(c);
  236. ctlr = newctlr(path);
  237. break;
  238. }
  239. if(s == nil && (s = malloc(sizeof *s)) == nil)
  240. return nil;
  241. s->ctlr = ctlr;
  242. s->ifc = &sdaoeifc;
  243. s->nunit = 1;
  244. return s;
  245. }
  246. static char *probef[32];
  247. static int nprobe;
  248. static int
  249. pnpprobeid(char *s)
  250. {
  251. int id;
  252. if(strlen(s) < 2)
  253. return 0;
  254. id = 'e';
  255. if(s[1] == '!')
  256. id = s[0];
  257. return id;
  258. }
  259. static SDev*
  260. aoepnp(void)
  261. {
  262. int i, id;
  263. char *p;
  264. SDev *h, *t, *s;
  265. if((p = getconf("aoedev")) == 0)
  266. return 0;
  267. nprobe = tokenize(p, probef, nelem(probef));
  268. h = t = 0;
  269. for(i = 0; i < nprobe; i++){
  270. id = pnpprobeid(probef[i]);
  271. if(id == 0)
  272. continue;
  273. s = malloc(sizeof *s);
  274. if(s == nil)
  275. break;
  276. s->ctlr = 0;
  277. s->idno = id;
  278. s->ifc = &sdaoeifc;
  279. s->nunit = 1;
  280. if(h)
  281. t->next = s;
  282. else
  283. h = s;
  284. t = s;
  285. }
  286. return h;
  287. }
  288. static Ctlr*
  289. pnpprobe(SDev *sd)
  290. {
  291. int j;
  292. char *p;
  293. static int i;
  294. if(i > nprobe)
  295. return 0;
  296. p = probef[i++];
  297. if(strlen(p) < 2)
  298. return 0;
  299. if(p[1] == '!')
  300. p += 2;
  301. for(j = 0;; j += 200){
  302. if(j > 8000){
  303. print("#æ: pnpprobe: %s: %s\n", probef[i-1], up->errstr);
  304. return 0;
  305. }
  306. if(waserror()){
  307. tsleep(&up->sleep, return0, 0, 200);
  308. continue;
  309. }
  310. sd = aoeprobe(p, sd);
  311. poperror();
  312. break;
  313. }
  314. print("#æ: pnpprobe establishes %sin %dms\n", probef[i-1], j);
  315. return sd->ctlr;
  316. }
  317. static int
  318. aoeverify(SDunit *u)
  319. {
  320. SDev *s;
  321. Ctlr *c;
  322. s = u->dev;
  323. c = s->ctlr;
  324. if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
  325. return 0;
  326. c->mediachange = 1;
  327. return 1;
  328. }
  329. static int
  330. aoeconnect(SDunit *u, Ctlr *c)
  331. {
  332. qlock(c);
  333. if(waserror()){
  334. qunlock(c);
  335. return -1;
  336. }
  337. aoeidentify(u->dev->ctlr, u);
  338. if(c->c)
  339. cclose(c->c);
  340. c->c = 0;
  341. uprint("%s/data", c->path);
  342. c->c = namec(up->genbuf, Aopen, ORDWR, 0);
  343. qunlock(c);
  344. poperror();
  345. return 0;
  346. }
  347. static int
  348. aoeonline(SDunit *u)
  349. {
  350. Ctlr *c;
  351. int r;
  352. c = u->dev->ctlr;
  353. r = 0;
  354. if((c->feat&Datapi) && c->mediachange){
  355. if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
  356. c->mediachange = 0;
  357. return r;
  358. }
  359. if(c->mediachange){
  360. if(aoeconnect(u, c) == -1)
  361. return 0;
  362. r = 2;
  363. c->mediachange = 0;
  364. u->sectors = c->sectors;
  365. u->secsize = Aoesectsz;
  366. } else
  367. r = 1;
  368. return r;
  369. }
  370. static int
  371. aoerio(SDreq *r)
  372. {
  373. int i, count;
  374. uint64_t lba;
  375. char *name;
  376. uint8_t *cmd;
  377. int32_t (*rio)(Chan*, void*, int32_t, int64_t);
  378. Ctlr *c;
  379. SDunit *unit;
  380. unit = r->unit;
  381. c = unit->dev->ctlr;
  382. // if(c->feat & Datapi)
  383. // return aoeriopkt(r, d);
  384. cmd = r->cmd;
  385. name = unit->name;
  386. if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
  387. // qlock(c);
  388. // i = flushcache();
  389. // qunlock(c);
  390. // if(i == 0)
  391. // return sdsetsense(r, SDok, 0, 0, 0);
  392. return sdsetsense(r, SDcheck, 3, 0xc, 2);
  393. }
  394. if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){
  395. r->status = i;
  396. return i;
  397. }
  398. switch(*cmd){
  399. case 0x88:
  400. case 0x28:
  401. rio = c->c->dev->read;
  402. break;
  403. case 0x8a:
  404. case 0x2a:
  405. rio = c->c->dev->write;
  406. break;
  407. default:
  408. print("%s: bad cmd 0x%.2ux\n", name, cmd[0]);
  409. r->status = SDcheck;
  410. return SDcheck;
  411. }
  412. if(r->data == nil)
  413. return SDok;
  414. if(r->clen == 16){
  415. if(cmd[2] || cmd[3])
  416. return sdsetsense(r, SDcheck, 3, 0xc, 2);
  417. lba = (uint64_t)cmd[4]<<40 | (uint64_t)cmd[5]<<32;
  418. lba |= cmd[6]<<24 | cmd[7]<<16 | cmd[8]<<8 | cmd[9];
  419. count = cmd[10]<<24 | cmd[11]<<16 | cmd[12]<<8 | cmd[13];
  420. }else{
  421. lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
  422. count = cmd[7]<<8 | cmd[8];
  423. }
  424. count *= Aoesectsz;
  425. if(r->dlen < count)
  426. count = r->dlen & ~0x1ff;
  427. if(waserror()){
  428. if(strcmp(up->errstr, Echange) == 0 ||
  429. strcmp(up->errstr, Enotup) == 0)
  430. unit->sectors = 0;
  431. nexterror();
  432. }
  433. r->rlen = rio(c->c, r->data, count, Aoesectsz * lba);
  434. poperror();
  435. r->status = SDok;
  436. return SDok;
  437. }
  438. static char *smarttab[] = {
  439. "unset",
  440. "error",
  441. "threshold exceeded",
  442. "normal"
  443. };
  444. static char *
  445. pflag(char *s, char *e, uint8_t f)
  446. {
  447. uint8_t i, m;
  448. for(i = 0; i < 8; i++){
  449. m = 1 << i;
  450. if(f & m)
  451. s = seprint(s, e, "%s ", flagname[i]);
  452. }
  453. return seprint(s, e, "\n");
  454. }
  455. static int
  456. aoerctl(SDunit *u, char *p, int l)
  457. {
  458. Ctlr *c;
  459. char *e, *op;
  460. if((c = u->dev->ctlr) == nil)
  461. return 0;
  462. e = p+l;
  463. op = p;
  464. p = seprint(p, e, "model\t%s\n", c->model);
  465. p = seprint(p, e, "serial\t%s\n", c->serial);
  466. p = seprint(p, e, "firm %s\n", c->firmware);
  467. if(c->smartrs == 0xff)
  468. p = seprint(p, e, "smart\tenable error\n");
  469. else if(c->smartrs == 0)
  470. p = seprint(p, e, "smart\tdisabled\n");
  471. else
  472. p = seprint(p, e, "smart\t%s\n", smarttab[c->smart]);
  473. p = seprint(p, e, "flag ");
  474. p = pflag(p, e, c->feat);
  475. p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
  476. return p-op;
  477. }
  478. static int
  479. aoewctl(SDunit *, Cmdbuf *cmd)
  480. {
  481. cmderror(cmd, Ebadarg);
  482. return 0;
  483. }
  484. static SDev*
  485. aoeprobew(DevConf *c)
  486. {
  487. char *p;
  488. p = strchr(c->type, '/');
  489. if(p == nil || strlen(p) > Maxpath - 11)
  490. error(Ebadarg);
  491. if(p[1] == '#')
  492. p++; /* hack */
  493. if(ctlrlookup(p))
  494. error(Einuse);
  495. return aoeprobe(p, 0);
  496. }
  497. static void
  498. aoeclear(SDev *s)
  499. {
  500. delctlr((Ctlr *)s->ctlr);
  501. }
  502. static char*
  503. aoertopctl(SDev *s, char *p, char *e)
  504. {
  505. Ctlr *c;
  506. c = s->ctlr;
  507. return seprint(p, e, "%s aoe %s\n", s->name, c->path);
  508. }
  509. static int
  510. aoewtopctl(SDev *, Cmdbuf *cmd)
  511. {
  512. switch(cmd->nf){
  513. default:
  514. cmderror(cmd, Ebadarg);
  515. }
  516. return 0;
  517. }
  518. SDifc sdaoeifc = {
  519. "aoe",
  520. aoepnp,
  521. nil, /* legacy */
  522. nil, /* enable */
  523. nil, /* disable */
  524. aoeverify,
  525. aoeonline,
  526. aoerio,
  527. aoerctl,
  528. aoewctl,
  529. scsibio,
  530. aoeprobew, /* probe */
  531. aoeclear, /* clear */
  532. aoertopctl,
  533. aoewtopctl,
  534. };