sdaoe.c 9.7 KB

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